Android系统源码阅读(13)(Input消息的分发过程)

知识的领域是无限的,我们的学习也是无限期的。这篇文章主要讲述Android系统源码阅读(13):Input消息的分发过程相关的知识,希望能为你提供帮助。
android系统源码阅读(13):Input消息的分发过程

请对照AOSP版本:6.0.1_r50。学校电脑好渣,看源码时卡半天
先回顾一下前两篇文章。在设备没有事件输入的时候,InputReader和InputDispatcher都处于睡眠状态。当输入事件发生,InputReader首先被激活,然后发送读取消息,激活Dispatcher。Dispatcher被激活以后,将消息发送给当前激活窗口的主线程,然后睡眠等待主线程处理完这个事件。主线程被激活后,会处理相应的消息,处理完毕后反馈给Dispatcher,从而Dispatcher可以继续发送消息。
1. InputReader获取事件回顾一下第11章4.2中,InputReader线程在获取事件以后,会调用processEventsLocked(mEventBuffer, count); 处理事件。
Android系统源码阅读(13)(Input消息的分发过程)

文章图片

1.1
这里先根据event的种类进行分门别类的处理。
frameworks/native/services/inputflinger/InputReader.cpp :
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count; ) { int32_t type = rawEvent-> type; size_t batchSize = 1; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { //如果这里获得是合成事件 //这里一次要将该输入设备中的一组事件都获取出来 int32_t deviceId = rawEvent-> deviceId; while (batchSize < count) { if (rawEvent[batchSize].type > = EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } //处理这些事件 processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { //这些是一些设备状况的事件,没必要将这些消息发送出去,留给自己处理就可以了 switch (rawEvent-> type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent-> when, rawEvent-> deviceId); break; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent-> when, rawEvent-> deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent-> when); break; default: ALOG_ASSERT(false); // can‘t happen break; } } count -= batchSize; rawEvent += batchSize; } }

1.2
准备将事件交给设备进行处理。
frameworks/native/services/inputflinger/InputReader.cpp :
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { //判断设备是否是已知的 ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Discarding event for unknown deviceId %d.", deviceId); return; } //获得设备 InputDevice* device = mDevices.valueAt(deviceIndex); if (device-> isIgnored()) { //ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; } //交给设备进行处理 device-> process(rawEvents, count); }

1.3
用device中的mapper去映射传入的事件,然后再处理。
frameworks/native/services/inputflinger/InputReader.cpp :
void InputDevice::process(const RawEvent* rawEvents, size_t count) { // Process all of the events in order for each mapper. // We cannot simply ask each mapper to process them in bulk because mappers may // have side-effects that must be interleaved.For example, joystick movement events and // gamepad button presses are handled by different mappers but they should be dispatched // in the order received. //一个设备可能有多种类型的event,所有有多个mapper,但是需要保持event的顺序性 //所以这里采用先循环event,再循环mapper的方式 size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {if (mDropUntilNextSync) { if (rawEvent-> type == EV_SYN & & rawEvent-> code == SYN_REPORT) { mDropUntilNextSync = false; //.. } else { //.. } } else if (rawEvent-> type == EV_SYN & & rawEvent-> code == SYN_DROPPED) { //.. mDropUntilNextSync = true; reset(rawEvent-> when); } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; //用每一种mapper尝试处理event mapper-> process(rawEvent); } } } }

1.4
这里InputMapper种类很多,每个事件处理方法各不相同,所以在这里不再详述。其中有如下的InputMapper:
SwitchInputMapper, VibratorInputMapper, KeyboardInputMapper,CursorInputMapper, TouchInputMapper, SingleTouchInputMapper, MultiTouchInputMapper, JoystickInputMapper
这些方法处理到最后,会调用getListener()-> notifyXXX(& args),让Dispatcher进行分发,XXX根据不同的Mapper有相应的名字。在创建InputReader时,将InputDispatcher作为参数传入,同时建立了QueuedInputListener来存放这个InputDispatcher,估计是准备将来处理多个InputDispatcher。所以这里getListener获取的就是当初建立的InputDispatcher对象。
1.5
这里虽然已经开始调用InputDispatcher的函数,但是还是在InputReader线程中。这里开始向InputDispatcher的队列中插入事件,并且把InputDispatcher唤醒了。因为notifyXXX函数同样是针对不同的输入有着不同的处理,所以不再详述,截取一段MotionEvent的代码片段。
frameworks/native/services/inputflinger/InputDispatcher.cpp :
//针对每种event,都会想将其封装成一个EventEntry // Just enqueue a new motion event. MotionEntry* newEntry = new MotionEntry(args-> eventTime, args-> deviceId, args-> source, policyFlags, args-> action, args-> actionButton, args-> flags, args-> metaState, args-> buttonState, args-> edgeFlags, args-> xPrecision, args-> yPrecision, args-> downTime, args-> displayId, args-> pointerCount, args-> pointerProperties, args-> pointerCoords, 0, 0); //然后加入队列 needWake = enqueueInboundEventLocked(newEntry); //... //唤醒Looper线程 if (needWake) { mLooper-> wake(); }

将一个事件放入队列之后,会根据needWake参数决定是否要唤醒线程。如果要唤醒,则调用Looper的wake函数就可以了,和原来道理一样。在有些时候,有事件添加进去,不一定要唤醒线程,比如线程正在等待应用反馈事件处理完毕的消息。
1.6
实实在在的将这个EventEntry放入队列mInboundQueue中了。
frameworks/native/services/inputflinger/InputDispatcher.cpp :
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { //如果队列空了,需要唤醒 bool needWake = mInboundQueue.isEmpty(); //将事件加入队列 mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked(); switch (entry-> type) { //这里会优化App切换的事件,如果上一个App还有事件没处理完,也没反馈事件处理完毕消息 //则清空之前的事件,切换下一个应用 case EventEntry::TYPE_KEY: { // Optimize app switch latency. // If the application takes too long to catch up then we drop all events preceding // the app switch key. KeyEntry* keyEntry = static_cast< KeyEntry*> (entry); if (isAppSwitchKeyEventLocked(keyEntry)) { if (keyEntry-> action == AKEY_EVENT_ACTION_DOWN) { mAppSwitchSawKeyDown = true; } else if (keyEntry-> action == AKEY_EVENT_ACTION_UP) { if (mAppSwitchSawKeyDown) { #if DEBUG_APP_SWITCH ALOGD("App switch is pending!"); #endif mAppSwitchDueTime = keyEntry-> eventTime + APP_SWITCH_TIMEOUT; mAppSwitchSawKeyDown = false; needWake = true; } } } break; }//当一个非当前激活app的点击事件发生,会清空之前的事件 //从这个新的点击事件开始 case EventEntry::TYPE_MOTION: { // Optimize case where the current application is unresponsive and the user // decides to touch a window in a different application. // If the application takes too long to catch up then we drop all events preceding // the touch into the other window. MotionEntry* motionEntry = static_cast< MotionEntry*> (entry); if (motionEntry-> action == AMOTION_EVENT_ACTION_DOWN & & (motionEntry-> source & AINPUT_SOURCE_CLASS_POINTER) & & mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY & & mInputTargetWaitApplicationHandle != NULL) { int32_t displayId = motionEntry-> displayId; int32_t x = int32_t(motionEntry-> pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(motionEntry-> pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp< InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (touchedWindowHandle != NULL & & touchedWindowHandle-> inputApplicationHandle != mInputTargetWaitApplicationHandle) { // User touched a different application than the one we are waiting on. // Flag the event, and start pruning the input queue. mNextUnblockedEvent = motionEntry; needWake = true; } } break; } } return needWake; }

这里做了两种优化,主要是在当前App窗口处理事件过慢,同时你又触发其他App的事件时,Dispatcher就会丢弃先前的事件,从这个开始唤醒Dispatcher。这样做很合情合理,用户在使用时,会遇到App由于开发者水平有限导致处理事件过慢情况,这时用户等的不耐烦,则应该让用户轻松的切换到其它App,而不是阻塞在那。所以,事件无法响应只会发生在App内部,而不会影响应用的切换,从而提升用户体验。App的质量问题不会影响系统的运转,Android在这点上做的很人性。
2. InputDispatcher分发事件在第11章中3.2中,Dispatcher调用函数dispatchOnceInnerLocked(& nextWakeupTime); 来分配队列中的事件。
Android系统源码阅读(13)(Input消息的分发过程)

文章图片

2.1
从队列中获取event,然后准备处理。
frameworks/native/services/inputflinger/InputDispatcher.cpp :
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); // Reset the key repeat timer whenever normal dispatch is suspended while the // device is in a non-interactive state.This is to ensure that we abort a key // repeat if the device is just coming out of sleep. if (!mDispatchEnabled) { resetKeyRepeatLocked(); }// If dispatching is frozen, do not process timeouts or try to deliver any new events. if (mDispatchFrozen) { return; }//对App切换的情况的优化 // Optimize latency of app switches. // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has // been pressed.When it expires, we preempt dispatch and drop all other pending events. bool isAppSwitchDue = mAppSwitchDueTime < = currentTime; if (mAppSwitchDueTime < *nextWakeupTime) { //如果有切换App的event,且时间小于设定的时间 //则将等待事件设为小者 *nextWakeupTime = mAppSwitchDueTime; }// Ready to start a new event. // If we don‘t already have a pending event, go grab one. if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { //队列是空的情况 if (isAppSwitchDue) { // The inbound queue is empty so the app switch key we were waiting // for will never arrive.Stop waiting for it. resetPendingAppSwitchLocked(false); isAppSwitchDue = false; }// Synthesize a key repeat if appropriate. //如果有连续重复事件发生,则制造重复事件 if (mKeyRepeatState.lastKeyEntry) { if (currentTime > = mKeyRepeatState.nextRepeatTime) { mPendingEvent = synthesizeKeyRepeatLocked(currentTime); } else { if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { *nextWakeupTime = mKeyRepeatState.nextRepeatTime; } } }// Nothing to do if there is no pending event. //如果真无事可做,下次睡眠可能比较久 if (!mPendingEvent) { return; } } else { // Inbound queue has at least one entry. //从队列中获取一个Event mPendingEvent = mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); }// Poke user activity for this event. if (mPendingEvent-> policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } //重置ANRT // Get ready to dispatch the event. resetANRTimeoutsLocked(); }// Now we have an event to dispatch. // All events are eventually dequeued and processed this way, even if we intend to drop them. bool done = false; DropReason dropReason = DROP_REASON_NOT_DROPPED; if (!(mPendingEvent-> policyFlags & POLICY_FLAG_PASS_TO_USER)) { dropReason = DROP_REASON_POLICY; } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; }if (mNextUnblockedEvent == mPendingEvent) { mNextUnblockedEvent = NULL; }//分类处理Event switch (mPendingEvent-> type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = static_cast< ConfigurationChangedEntry*> (mPendingEvent); done = dispatchConfigurationChangedLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped break; }case EventEntry::TYPE_DEVICE_RESET: { DeviceResetEntry* typedEntry = static_cast< DeviceResetEntry*> (mPendingEvent); done = dispatchDeviceResetLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped break; }case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast< KeyEntry*> (mPendingEvent); if (isAppSwitchDue) { if (isAppSwitchKeyEventLocked(typedEntry)) { //这个Event就是SwitchEvent,我已经处理 //重置App切换的状态为false resetPendingAppSwitchLocked(true); isAppSwitchDue = false; } else if (dropReason == DROP_REASON_NOT_DROPPED) { //如果是其他事件,则丢弃,因为正在switch dropReason = DROP_REASON_APP_SWITCH; } } if (dropReason == DROP_REASON_NOT_DROPPED & & isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED & & mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } //分发KeyEvent done = dispatchKeyLocked(currentTime, typedEntry, & dropReason, nextWakeupTime); break; }case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast< MotionEntry*> (mPendingEvent); if (dropReason == DROP_REASON_NOT_DROPPED & & isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } if (dropReason == DROP_REASON_NOT_DROPPED & & isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED & & mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } //分发Motion Event done = dispatchMotionLocked(currentTime, typedEntry, & dropReason, nextWakeupTime); break; }default: ALOG_ASSERT(false); break; }if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } mLastDropReason = dropReason; //将mPendingEvent置为null releasePendingEventLocked(); //我已经处理的event,所以需要将睡眠设置时间小一点 *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } }

2.2
这一步根据Event的种类,略有不同。有dispatchMotionLockeddispatchKeyLocked等。主要过程类似,首先判断是否需要丢弃该event,然后获得目标Window,再向目标window发送event。代码片如下:
frameworks/native/services/inputflinger/InputDispatcher.cpp :
//.. // Identify targets. Vector< InputTarget> inputTargets; //.. injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, & conflictingPointerActions); //.. dispatchEventLocked(currentTime, entry, inputTargets);

这里调用findTouchedWindowTargetsLocked()来获取目标Window。在前面12章3.6中,将mFocusedWindowHandle参数设置为了当前激活的Window,所以目前返回的inputTargets就是将mFocusedWindowHandle封装后的结果。
2.3
向每一个目标发送event。
frameworks/native/services/inputflinger/InputDispatcher.cpp :
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector< InputTarget> & inputTargets) {pokeUserActivityLocked(eventEntry); //向每一个目标发送event for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); //获取目标的connection ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex > = 0) { sp< Connection> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget); } else { //.. } } }

2.4
frameworks/native/services/inputflinger/InputDispatcher.cpp :
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp< Connection> & connection, EventEntry* eventEntry, const InputTarget* inputTarget) {// Skip this event if the connection status is not normal. // We don‘t want to enqueue additional outbound events if the connection is broken. if (connection-> status != Connection::STATUS_NORMAL) { return; }// Split a motion event if needed. if (inputTarget-> flags & InputTarget::FLAG_SPLIT) { //Motion event一般为连续的基本event组合而成 //所以可以分割 MotionEntry* originalMotionEntry = static_cast< MotionEntry*> (eventEntry); if (inputTarget-> pointerIds.count() != originalMotionEntry-> pointerCount) { MotionEntry* splitMotionEntry = splitMotionEvent( originalMotionEntry, inputTarget-> pointerIds); if (!splitMotionEntry) { return; // split event was dropped } enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); splitMotionEntry-> release(); return; } }// Not splitting.Enqueue dispatch entries for the event as is. enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); }

2.5
这一步先判断目标Connection是否空,然后向其队列加入event。如果原来队列为空,说明可以进一步分发event;如果不为空,说明旧event还没有处理完毕,则不进一步分发。
frameworks/native/services/inputflinger/InputDispatcher.cpp :
bool wasEmpty = connection-> outboundQueue.isEmpty(); // Enqueue dispatch entries for the requested modes. //将event放入outboundQueue中,省略..// If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty & & !connection-> outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); }

2.6
循环的取出队列中的event,然后交给connection发送。
frameworks/native/services/inputflinger/InputDispatcher.cpp :
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp< Connection> & connection) {//将outboundQueue中的entry一一进行处理 while (connection-> status == Connection::STATUS_NORMAL & & !connection-> outboundQueue.isEmpty()) { //获取首部的entry DispatchEntry* dispatchEntry = connection-> outboundQueue.head; dispatchEntry-> deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry-> eventEntry; switch (eventEntry-> type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast< KeyEntry*> (eventEntry); //..// Publish the key event. status = connection-> inputPublisher.publishKeyEvent(dispatchEntry-> seq, keyEntry-> deviceId, keyEntry-> source, dispatchEntry-> resolvedAction, dispatchEntry-> resolvedFlags, keyEntry-> keyCode, keyEntry-> scanCode, keyEntry-> metaState, keyEntry-> repeatCount, keyEntry-> downTime, keyEntry-> eventTime); break; }case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast< MotionEntry*> (eventEntry); // Set the X and Y offset depending on the input source. //..// Publish the motion event. status = connection-> inputPublisher.publishMotionEvent(dispatchEntry-> seq, motionEntry-> deviceId, motionEntry-> source, dispatchEntry-> resolvedAction, motionEntry-> actionButton, dispatchEntry-> resolvedFlags, motionEntry-> edgeFlags, motionEntry-> metaState, motionEntry-> buttonState, xOffset, yOffset, motionEntry-> xPrecision, motionEntry-> yPrecision, motionEntry-> downTime, motionEntry-> eventTime, motionEntry-> pointerCount, motionEntry-> pointerProperties, usingCoords); break; }default: return; }// Check the result.// Re-enqueue the event on the wait queue. //从outboundQueue中移除 connection-> outboundQueue.dequeue(dispatchEntry); traceOutboundQueueLengthLocked(connection); //加入waitQueue connection-> waitQueue.enqueueAtTail(dispatchEntry); traceWaitQueueLengthLocked(connection); } }

2.7
这一步同样有多种情况,有publishMotionEvent和publishKeyEvent。基本思路相近。先封装成message,最后都调用了mChannel-> sendMessage(& msg)
frameworks/native/libs/input/InputTransport.cpp :
InputMessage msg; msg.header.type = InputMessage::TYPE_MOTION; msg.body.motion.seq = seq; msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.action = action; msg.body.motion.actionButton = actionButton; msg.body.motion.flags = flags; msg.body.motion.edgeFlags = edgeFlags; msg.body.motion.metaState = metaState; msg.body.motion.buttonState = buttonState; msg.body.motion.xOffset = xOffset; msg.body.motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision; msg.body.motion.yPrecision = yPrecision; msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; for (uint32_t i = 0; i < pointerCount; i++) { msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); } return mChannel-> sendMessage(& msg);

2.8
这一步就要像保存的文件描述符mFd中写入数据了。
frameworks/native/libs/input/InputTransport.cpp :
size_t msgLength = msg-> size(); ssize_t nWrite; do { nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 & & errno == EINTR);

到这里,Dispatcher终于把event通过当初建立的Channel pair发送给了应用window。这里和旧版本很不同,当初需要先将event放入共享内存,然后发送一个信号进行通知。
3. 当前激活Window获得消息这一节比较复杂,需要回忆大量的前面几章的细节和一定的逻辑推理(连蒙带猜)能力。
先来回忆一下第12章4.5节,在InputChannel注册到Client时,最后一步做了什么。
frameworks/base/core/jni/android_view_InputEventReceiver.cpp :
mMessageQueue-> getLooper()-> addFd(fd, 0, events, this, NULL);

这里给主线程的Looper添加的一个需要监听fd,这个fd是Client端的InputChannel的文件描述符。addFd函数的第4个参数是一个回调函数,这里this指NativeInputEventReceiver对象,它是LooperCallback的子类。addFd函数新建了一个Request对象,如下:
system/core/libutils/Looper.cpp :
Request request; request.fd = fd; request.ident = ident; request.events = events; request.seq = mNextRequestSeq++; //回调函数指明是上一步传入的NativeInputEventReceiver对象 request.callback = callback; request.data = https://www.songbingjia.com/android/data; //.. //将request以fd为关键字加入mRequests mRequests.add(fd, request);

再次回忆第10章1.6,也就是主线程被阻塞的地方。代码如下:
system/core/libutils/Looper.cpp :
int Looper::pollInner(int timeoutMillis) {// Adjust the timeout based on when the next message is due. //.. //清空mResponses数组 // Poll. int result = POLL_WAKE; mResponses.clear(); mResponseIndex = 0; // We are about to idle. mPolling = true; //等待epoll监测到IO事件 struct epoll_event eventItems[EPOLL_MAX_EVENTS]; int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); //..// Handle all events. for (int i = 0; i < eventCount; i++) { int fd = eventItems[i].data.fd; uint32_t epollEvents = eventItems[i].events; if (fd == mWakeEventFd) { if (epollEvents & EPOLLIN) { //这里处理的唤醒事件 awoken(); } else { ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents); } } else { //这里处理的是input事件 ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex > = 0) { int events = 0; if (epollEvents & EPOLLIN) events |= EVENT_INPUT; if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT; if (epollEvents & EPOLLERR) events |= EVENT_ERROR; if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP; //将event加入mResponses pushResponse(events, mRequests.valueAt(requestIndex)); } else { //.. } } } Done: ; //遍历每一个存在mResponses的event // Invoke all response callbacks. for (size_t i = 0; i < mResponses.size(); i++) { Response& response = mResponses.editItemAt(i); if (response.request.ident == POLL_CALLBACK) { int fd = response.request.fd; int events = response.events; void* data = https://www.songbingjia.com/android/response.request.data; // Invoke the callback.Note that the file descriptor may be closed by // the callback (and potentially even reused) before the function returns so // we need to be a little careful when removing the file descriptor afterwards. //这一步开始调用回调函数,说明该文件描述符下有人输入的event int callbackResult = response.request.callback-> handleEvent(fd, events, data); if (callbackResult == 0) { removeFd(fd, response.request.seq); }// Clear the callback reference in the response structure promptly because we // will not clear the response vector itself until the next poll. response.request.callback.clear(); result = POLL_CALLBACK; } } return result; }

这一步处理wake事件已经在第10章第1节讲述过了,这里需要处理的另一种事件input event。对input event,先将其放入mResponses数组,然后依次调用他们的回调函数。这里就是NativeInputEventReceiver的handleEvent函数了。
Android系统源码阅读(13)(Input消息的分发过程)

文章图片

3.1
Event分为Input和Output,这里是事件输入,所以先看Input分支。
frameworks/base/core/jni/android_view_InputEventReceiver.cpp :
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL); mMessageQueue-> raiseAndClearException(env, "handleReceiveCallback"); return status == OK || status == NO_MEMORY ? 1 : 0; }if (events & ALOOPER_EVENT_OUTPUT) { //.. } return 1; }

3.2
开始从目标Channel中读出event,然后包装成java层的对象,开始调用java函数进行处理。
frameworks/base/core/jni/android_view_InputEventReceiver.cpp :
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {ScopedLocalRef< jobject> receiverObj(env, NULL); bool skipCallbacks = false; //循环从Channel中读出event for (; ; ) { uint32_t seq; InputEvent* inputEvent; //这一步开始从Channel中读取event,存入inputEvent中 status_t status = mInputConsumer.consume(& mInputEventFactory, consumeBatches, frameTime, & seq, & inputEvent); if (status) { if (status == WOULD_BLOCK) { if (!skipCallbacks & & !mBatchedInputEventPending & & mInputConsumer.hasPendingBatch()) { // There is a pending batch.Come back later. //.. return OK; } } return status; }if (!skipCallbacks) { if (!receiverObj.get()) { //这里的mReceiverWeakGlobal是java层的InputEventReceiver receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); //.. }//根据不同的InputEvent种类,将其转化为java层的inputEventObj jobject inputEventObj; switch (inputEvent-> getType()) { case AINPUT_EVENT_TYPE_KEY: inputEventObj = android_view_KeyEvent_fromNative(env, static_cast< KeyEvent*> (inputEvent)); break; case AINPUT_EVENT_TYPE_MOTION: { MotionEvent* motionEvent = static_cast< MotionEvent*> (inputEvent); if ((motionEvent-> getAction() & AMOTION_EVENT_ACTION_MOVE) & & outConsumedBatch) { *outConsumedBatch = true; } inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent); break; } default: assert(false); // InputConsumer should prevent this from ever happening inputEventObj = NULL; }if (inputEventObj) { //开始调用java层的dispatchInputEvent函数 env-> CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); env-> DeleteLocalRef(inputEventObj); } else { //.. } }if (skipCallbacks) { //不需要调用回调函数,则可以直接反馈完成信号 mInputConsumer.sendFinishedSignal(seq, false); } } }

我们先看如何从Channel中获取event的,3.3。然后讲解java层的分发过程,3.4。
3.3
从Chuannel中读取一个(一组)event。
frameworks/native/libs/input/InputTransport.cpp :
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {*outSeq = 0; *outEvent = NULL; // Fetch the next input message. // Loop until an event can be returned or no additional events are received. while (!*outEvent) { if (mMsgDeferred) { // mMsg contains a valid input message from the previous call to consume // that has not yet been processed. mMsgDeferred = false; } else { // Receive a fresh message. //从Channel中读取一个Message status_t result = mChannel-> receiveMessage(& mMsg); if (result) { // Consume the next batched event unless batches are being held for later. //.. } } //根据message种类构造event switch (mMsg.header.type) { case InputMessage::TYPE_KEY: { KeyEvent* keyEvent = factory-> createKeyEvent(); if (!keyEvent) return NO_MEMORY; initializeKeyEvent(keyEvent, & mMsg); *outSeq = mMsg.body.key.seq; *outEvent = keyEvent; break; } case AINPUT_EVENT_TYPE_MOTION: { //对Motion event,需要处理成批的event事件 //.. MotionEvent* motionEvent = factory-> createMotionEvent(); if (! motionEvent) return NO_MEMORY; updateTouchState(& mMsg); initializeMotionEvent(motionEvent, & mMsg); *outSeq = mMsg.body.motion.seq; *outEvent = motionEvent; break; } default: return UNKNOWN_ERROR; } } return OK; }

mChannel-> receiveMessage(& mMsg)函数在InputChannel中主要如下实现,调用socket函数recv从mFd中读出数据。
frameworks/native/libs/input/InputTransport.cpp :
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);

3.4
回到java层,在获得event后,就需要进行分发了。receiverObj指向的是一个InputEventReceiver对象,这里其实是它的子类WindowInputEventReceiver对象,见第12章第4节。dispatchInputEvent函数还是继承的父类的,没有重写。
3.5
这一步直接调用了下一步。
3.6
将event插入等待事件队列的尾部,然后开始调度这些消息。
frameworks/base/core/java/android/view/ViewRootImpl.java :
void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); //将event和receiver封装在一起 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); // Always enqueue the input event in order, regardless of its time stamp. // We do this because the application or the IME may inject key events // in response to touch events and we want to ensure that the injected keys // are processed in the order they were received and we cannot trust that // the time stamp of injected events are monotonic. //找到尾部插入 QueuedInputEvent last = mPendingInputEventTail; if (last == null) { mPendingInputEventHead = q; mPendingInputEventTail = q; } else { last.mNext = q; mPendingInputEventTail = q; } mPendingInputEventCount += 1; if (processImmediately) { //立即处理所有的InputEvent doProcessInputEvents(); } else { //发送一个提醒消息 scheduleProcessInputEvents(); } }

这里会有两种不同的处理event的方式,一个是立即处理;另一种是向主线程Looper发送MSG_PROCESS_INPUT_EVENTS消息。这里选择立即处理。
3.7
这里会把等待在队列中的event,一口气全处理了。这一步会循环拿出队列中的每一个event,然后调用下一步进行处理。
3.8
准备交给stage处理。
frameworks/base/core/java/android/view/ViewRootImpl.java :
private void deliverInputEvent(QueuedInputEvent q) { //... //下面开始从某个stage开始 //寻找适合的stage进行处理 InputStage stage; if (q.shouldSendToSynthesizer()) { stage = mSyntheticInputStage; } else { stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; } if (stage != null) { stage.deliver(q); } else { finishInputEvent(q); } }

3.9
下面就讲解一下stage是什么东西。stage可以说是处理event的不同阶段,如果上一个stage处理不了,就交给下一个stage处理,总有一个stage可以将event处理掉。这里stage的处理顺序图如下所示:
Android系统源码阅读(13)(Input消息的分发过程)

文章图片

  1. NativePrelmeInputStage: Delivers pre-ime input events to a native activity. Does not support pointer events. 其实我也不清楚到底是干什么的,没有想到具体的应用场景。
  2. ViewPreImeInputStage: Delivers pre-ime input events to the view hierarchy. Does not support pointer events. 这一步只处理KeyEvent,在InputMethod处理这个KeyEvent之前,可以截获这个event。典型的例子是处理BACK key。
  3. ImeInputStage: Delivers input events to the ime. Does not support pointer events. 将event交给IputMethodManager处理。
  4. EarlyPostImeInputStage: Performs early processing of post-ime input events. 在交给下一阶段之前,先处理筛选一些event。
  5. NativePostImeInputStage: Delivers post-ime input events to a native activity. 尝试让InputQueue发送event给native activity。
  6. ViewPostImeInputStage: Delivers post-ime input events to the view hierarchy. 将event发送给view的层次结构中。
  7. SyntheticInputStage: Performs synthesis of new input events from unhandled input events. 最后一个阶段,处理综合事件,比如trackball, joystick等。
这里我们暂且研究第6种stage,这个stage和View有直接关系。
3.10
这里根据event的类型分别进行处理。我们先关注一下PointerEvent如何处理的。
3.11
将event交给mView来处理,这里mView就是一个DecorView对象。
3.12
这一步是DecorView继承自View的方法,将event分为TouchEvent和GenericMotionEvent来处理。先看TouchEvent如何处理。
3.13
DecorView重写了该函数。这里调用getCallback函数来获取一个回调对象。该函数是PhoneWindow继承自Window类的方法,获得是mCallback。那么这个mCallback到底是谁呢?
回顾一下Activity的创建过程,在Activity创建以后会调用attach函数对Activity进行一定的初始化,其中就创建了PhoneWindow,同时设置了callback为Activity它自己。所以这一步获得是一个Activity对象,然后调用它的函数继续分发event。
3.14
Event交到Activity手中进行处理。为什么会先交给Activity处理?目的是让开发者可以重写这个函数,从而可以在分发这个事件之前进行截获。
/** * Called to process touch screen events.You can override this to * intercept all touch screen events before they are dispatched to the * window.Be sure to call this implementation for touch screen events * that should be handled normally. * * @param ev The touch screen event. * * @return boolean Return true if this event was consumed. */ public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } //绕一圈有交给PhoneWindow处理 if (getWindow().superDispatchTouchEvent(ev)) { return true; } //没有view可以处理,那么activity自己处理 //默认就是放弃,也可以重写实现特定功能 return onTouchEvent(ev); }

3.15
什么也没做,将event传回DecorView,让它处理。
3.16
这里DecorView又交给dispatchTouchEvent处理。这里的dispatchTouchEvent是源自父类ViewGroup的函数,而不是自己重写的函数。
3.17
ViewGroup是View的子类。它管理了一组View在mChildren数组中,按照设计模式的说法叫Composite模式。
Android系统源码阅读(13)(Input消息的分发过程)

文章图片

这一步会依次访问每个子view,判断他们是否可以处理该event,如果能就交给它处理;没人能处理就自己处理。无论哪种方式,都会调用下一步dispatchTransformedTouchEvent函数。
frameworks/base/core/java/android/view/ViewGroup.java :
public boolean dispatchTouchEvent(MotionEvent ev) { //.. // If the event targets the accessibility focused view and this is it, start // normal event dispatch. Maybe a descendant is what will handle the click. if (ev.isTargetAccessibilityFocus() & & isAccessibilityFocusedViewOrHost()) { ev.setTargetAccessibilityFocus(false); }boolean handled = false; //如果Window没有被遮住,才进行以下过程 if (onFilterTouchEventForSecurity(ev)) { //.. TouchTarget newTouchTarget = null; boolean alreadyDispatchedToNewTouchTarget = false; if (!canceled & & !intercepted) { //.. final int childrenCount = mChildrenCount; if (newTouchTarget == null & & childrenCount != 0) { final float x = ev.getX(actionIndex); final float y = ev.getY(actionIndex); // Find a child that can receive the event. // Scan children from front to back. //根据z坐标进行排序,从小到大的顺序 final ArrayList< View> preorderedList = buildOrderedChildList(); //也可以自己定制顺序 final boolean customOrder = preorderedList == null & & isChildrenDrawingOrderEnabled(); //所有子View存放在mChildren中 final View[] children = mChildren; //按z的值,从大到小开始遍历 for (int i = childrenCount - 1; i > = 0; i--) { final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex); // If there is a view that has accessibility focus we want it // to get the event first and if not handled we will perform a // normal dispatch. We may do a double iteration but this is // safer given the timeframe. //如果指定了一个view去获得这个event,一直循环到那个view为止 if (childWithAccessibilityFocus != null) { if (childWithAccessibilityFocus != child) { continue; } childWithAccessibilityFocus = null; i = childrenCount - 1; }//判断该view是否可以接受这个event,是否在这个view范围内 if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { ev.setTargetAccessibilityFocus(false); continue; }//如果该child正在处理上一个event newTouchTarget = getTouchTarget(child); if (newTouchTarget != null) { // Child is already receiving touch within its bounds. // Give it the new pointer in addition to the ones it is handling. newTouchTarget.pointerIdBits |= idBitsToAssign; break; } //尝试去向该child发送event if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // Child wants to receive touch within its bounds. //.. //将child加入mFirstTouchTarget为首的队列头部 newTouchTarget = addTouchTarget(child, idBitsToAssign); alreadyDispatchedToNewTouchTarget = true; break; } //.. } } } }// Dispatch to touch targets. if (mFirstTouchTarget == null) { //没有child可以处理,那么就自己处理 // No touch targets so treat this as an ordinary view. handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS); } else { // Dispatch to touch targets, excluding the new touch target if we already // dispatched to it.Cancel touch targets if necessary. TouchTarget predecessor = null; TouchTarget target = mFirstTouchTarget; while (target != null) { final TouchTarget next = target.next; if (alreadyDispatchedToNewTouchTarget & & target == newTouchTarget) { handled = true; } else { //.. if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true; } //.. } predecessor = target; target = next; } } //.. } return handled; }

3.18
ViewGroup会决定自己处理还是交给child处理。在ViewGroup自己处理,或者child为不再是一个ViewGroup时,则开始调用View的dispatchTouchEvent函数。
frameworks/base/core/java/android/view/ViewGroup.java :
//省略了计算坐标便宜的过程 if (child == null) { //ViewGroup决定自己处理 handled = super.dispatchTouchEvent(event); } else { //交给child处理,child可能是个view //也可能还是个ViewGroup,这就重复3.17步骤 handled = child.dispatchTouchEvent(event); }

3.19
这一步就会调用用户自己实现的Listener;如果没有Listener,则会调用view默认的处理函数。
frameworks/base/core/java/android/view/View.java :
public boolean dispatchTouchEvent(MotionEvent event) { // If the event should be handled by accessibility focus first. if (event.isTargetAccessibilityFocus()) { // We don‘t have focus or no virtual descendant has it, do not handle the event. if (!isAccessibilityFocusedViewOrHost()) { //该View不可访问的状态,返回 return false; } }boolean result = false; //.. //先判断该View是否被遮挡,没被遮挡才进行处理 if (onFilterTouchEventForSecurity(event)) { //noinspection SimplifiableIfStatement //获得注册的Listener,看是否有注册OnTouchListener ListenerInfo li = mListenerInfo; if (li != null & & li.mOnTouchListener != null & & (mViewFlags & ENABLED_MASK) == ENABLED & & li.mOnTouchListener.onTouch(this, event)) { //调用Listener的回调函数,处理event result = true; } //View也可以采用默认的处理onTouchEvent if (!result & & onTouchEvent(event)) { result = true; } } //.. return result; }

默认处理函数onTouchEvent会处理一些基本的操作,比如button的按下松开的效果,滚动容器产生滚动的效果等。
最后说两句【Android系统源码阅读(13)(Input消息的分发过程)】到这里,Input event的处理流程已经分析完了,心好累。



    推荐阅读