3. InputManager分发键盘消息给应用程序的过程分析
在分析InputManager分发键盘消息给应用程序的过程之前,我们先假设现在没有键盘事件发生,因此,InputManager中的InputReader正在睡眠等待键盘事件的发生,而InputManager中的InputDispatcher正在等待InputReader从睡眠中醒过来并且唤醒它,而应用程序也正在消息循环中等待InputDispatcher从睡眠中醒过来并且唤醒它。这时候,用户按下键盘中的一个键,于是,一系列唤醒的事件就依次发生了,一直到应用程序中正在显示的Activity得到通知,有键盘事件发生了。我们先来看这个过程的序列图,然后再详细分析每一个步骤:
Step 1. InputReader.pollOnce
Step 2. EventHub.getEvent
这两个函数分别定义在frameworks/base/libs/ui/InputReader.cpp和frameworks/base/libs/ui/EventHub.cpp文件中,前面我们在分析InputManager的启动过程的Step 17和Step 18时,已经看到过这两个函数了。InputReaderThread线程会不民地循环调用InputReader.pollOnce函数来读入键盘事件,而实际的键盘事件读入操作是由EventHub.getEvent函数来进行的。如果当前没有键盘事件发生,InputReaderThread线程就会睡眠在EventHub.getEvent函数上,而当键盘事件发生后,就会把这个事件封装成一个RawEvent对象,然后返回到pollOnce函数中,执行process函数进一步处理:
- void InputReader::loopOnce() {
- RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent);
- ......
- process(& rawEvent);
- }
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- void InputReader::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EventHubInterface::DEVICE_ADDED:
- addDevice(rawEvent->deviceId);
- break;
- case EventHubInterface::DEVICE_REMOVED:
- removeDevice(rawEvent->deviceId);
- break;
- case EventHubInterface::FINISHED_DEVICE_SCAN:
- handleConfigurationChanged(rawEvent->when);
- break;
- default:
- consumeEvent(rawEvent);
- break;
- }
- }
当键盘事件发生时,rawEvent->type的值为EV_KEY,这是一个宏定义,具体可以参考bionic/libc/kernel/common/linux/input.h文件:
- #define EV_KEY 0x01
Step 4. InputReader.consumeEvent
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- void InputReader::consumeEvent(const RawEvent* rawEvent) {
- int32_t deviceId = rawEvent->deviceId;
- { // acquire device registry reader lock
- RWLock::AutoRLock _rl(mDeviceRegistryLock);
- ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
- if (deviceIndex < 0) {
- LOGW("Discarding event for unknown deviceId %d.", deviceId);
- return;
- }
- InputDevice* device = mDevices.valueAt(deviceIndex);
- if (device->isIgnored()) {
- //LOGD("Discarding event for ignored deviceId %d.", deviceId);
- return;
- }
- device->process(rawEvent);
- } // release device registry reader lock
- }
Step 5. InputDevice.process
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- void InputDevice::process(const RawEvent* rawEvent) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
- mapper->process(rawEvent);
- }
- }
Step 6. KeyboardInputMapper.process
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- void KeyboardInputMapper::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EV_KEY: {
- int32_t scanCode = rawEvent->scanCode;
- if (isKeyboardOrGamepadKey(scanCode)) {
- processKey(rawEvent->when, rawEvent->value != 0, rawEvent->keyCode, scanCode,
- rawEvent->flags);
- }
- break;
- }
- }
- }
Step 7. KeyboardInputMapper.processKey
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
- int32_t scanCode, uint32_t policyFlags) {
- int32_t newMetaState;
- nsecs_t downTime;
- bool metaStateChanged = false;
- { // acquire lock
- AutoMutex _l(mLock);
- if (down) {
- // Rotate key codes according to orientation if needed.
- // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
- if (mAssociatedDisplayId >= 0) {
- int32_t orientation;
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
- return;
- }
- keyCode = rotateKeyCode(keyCode, orientation);
- }
- // Add key down.
- ssize_t keyDownIndex = findKeyDownLocked(scanCode);
- if (keyDownIndex >= 0) {
- // key repeat, be sure to use same keycode as before in case of rotation
- keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- } else {
- // key down
- if ((policyFlags & POLICY_FLAG_VIRTUAL)
- && mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) {
- return;
- }
- mLocked.keyDowns.push();
- KeyDown& keyDown = mLocked.keyDowns.editTop();
- keyDown.keyCode = keyCode;
- keyDown.scanCode = scanCode;
- }
- mLocked.downTime = when;
- } else {
- // Remove key down.
- ssize_t keyDownIndex = findKeyDownLocked(scanCode);
- if (keyDownIndex >= 0) {
- // key up, be sure to use same keycode as before in case of rotation
- keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- mLocked.keyDowns.removeAt(size_t(keyDownIndex));
- } else {
- // key was not actually down
- LOGI("Dropping key up from device %s because the key was not down. "
- "keyCode=%d, scanCode=%d",
- getDeviceName().string(), keyCode, scanCode);
- return;
- }
- }
- int32_t oldMetaState = mLocked.metaState;
- newMetaState = updateMetaState(keyCode, down, oldMetaState);
- if (oldMetaState != newMetaState) {
- mLocked.metaState = newMetaState;
- metaStateChanged = true;
- }
- downTime = mLocked.downTime;
- } // release lock
- if (metaStateChanged) {
- getContext()->updateGlobalMetaState();
- }
- getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
- down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
- }
- // Rotate key codes according to orientation if needed.
- // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
- if (mAssociatedDisplayId >= 0) {
- int32_t orientation;
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
- return;
- }
- keyCode = rotateKeyCode(keyCode, orientation);
- }
- // Add key down.
- ssize_t keyDownIndex = findKeyDownLocked(scanCode);
- if (keyDownIndex >= 0) {
- // key repeat, be sure to use same keycode as before in case of rotation
- keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- } else {
- // key down
- if ((policyFlags & POLICY_FLAG_VIRTUAL)
- && mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) {
- return;
- }
- mLocked.keyDowns.push();
- KeyDown& keyDown = mLocked.keyDowns.editTop();
- keyDown.keyCode = keyCode;
- keyDown.scanCode = scanCode;
- }
如果是松开键盘上的某个键,就把它从mLocked.keyDowns里面删除:
- // Remove key down.
- ssize_t keyDownIndex = findKeyDownLocked(scanCode);
- if (keyDownIndex >= 0) {
- // key up, be sure to use same keycode as before in case of rotation
- keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- mLocked.keyDowns.removeAt(size_t(keyDownIndex));
- } else {
- // key was not actually down
- LOGI("Dropping key up from device %s because the key was not down. "
- "keyCode=%d, scanCode=%d",
- getDeviceName().string(), keyCode, scanCode);
- return;
- }
最后,KeyboardInputMappger函数通知InputDispatcher,有键盘事件发生了:
- getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
- down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
- uint32_t policyFlags, int32_t action, int32_t flags,
- int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
- ......
- if (! validateKeyEvent(action)) {
- return;
- }
- /* According to http://source.android.com/porting/keymaps_keyboard_input.html
- * Key definitions: Key definitions follow the syntax key SCANCODE KEYCODE [FLAGS...],
- * where SCANCODE is a number, KEYCODE is defined in your specific keylayout file
- * (android.keylayout.xxx), and potential FLAGS are defined as follows:
- * SHIFT: While pressed, the shift key modifier is set
- * ALT: While pressed, the alt key modifier is set
- * CAPS: While pressed, the caps lock key modifier is set
- * Since KeyEvent.java doesn't check if Cap lock is ON and we don't have a
- * modifer state for cap lock, we will not support it.
- */
- if (policyFlags & POLICY_FLAG_ALT) {
- metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
- }
- if (policyFlags & POLICY_FLAG_ALT_GR) {
- metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
- }
- if (policyFlags & POLICY_FLAG_SHIFT) {
- metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
- }
- policyFlags |= POLICY_FLAG_TRUSTED;
- mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
- keyCode, scanCode, /*byref*/ policyFlags);
- bool needWake;
- { // acquire lock
- AutoMutex _l(mLock);
- int32_t repeatCount = 0;
- KeyEntry* newEntry = mAllocator.obtainKeyEntry(eventTime,
- deviceId, source, policyFlags, action, flags, keyCode, scanCode,
- metaState, repeatCount, downTime);
- needWake = enqueueInboundEventLocked(newEntry);
- } // release lock
- if (needWake) {
- mLooper->wake();
- }
- }
- static bool isValidKeyAction(int32_t action) {
- switch (action) {
- case AKEY_EVENT_ACTION_DOWN:
- case AKEY_EVENT_ACTION_UP:
- return true;
- default:
- return false;
- }
- }
- static bool validateKeyEvent(int32_t action) {
- if (! isValidKeyAction(action)) {
- LOGE("Key event has invalid action code 0x%x", action);
- return false;
- }
- return true;
- }
参数action检查通过后,还通过policyFlags参数来检查一下同时是否有ALT和SHIFT键被按下:
- if (policyFlags & POLICY_FLAG_ALT) {
- metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
- }
- if (policyFlags & POLICY_FLAG_ALT_GR) {
- metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
- }
- if (policyFlags & POLICY_FLAG_SHIFT) {
- metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
- }
- bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
- bool needWake = mInboundQueue.isEmpty();
- mInboundQueue.enqueueAtTail(entry);
- switch (entry->type) {
- case EventEntry::TYPE_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) {
- <span style="white-space:pre"> </span> ......
- mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
- mAppSwitchSawKeyDown = false;
- needWake = true;
- }
- }
- }
- break;
- }
- }
- return needWake;
- }
回到前面的notifyKey函数中,根据enqueueInboundEventLocked函数的返回值来决定是否要唤醒InputDispatccherThread线程:
- if (needWake) {
- mLooper->wake();
- }
Step 9. Looper.wake
这个函数定义在frameworks/base/libs/utils/Looper.cpp文件中,在前面一篇文章Android应用程序消息处理机制(Looper、Handler)分析中,我们已经分析过这个函数了,这里不再详述,简单来说,它的作用就是用来唤醒睡眠在Looper对象内部的管道读端的线程,在我们的这个场景中,睡眠在Looper对象内部的管道读端的线程就是InputDispatccherThread线程了。
从上面InputManager启动过程的Step 15中,我们知道,此时InputDispatccherThread线程正在InputDispatcher类的dispatchOnceb函数中通过调用mLooper->loopOnce函数进入睡眠状态。当它被唤醒以后,它就会从InputDispatcher类的dispatchOnceb函数返回到InputDispatcherThread类的threadLoop函数,而InputDispatcherThread类的threadLoop函数是循环执行的,于是,它又会再次进入到InputDispatcher类的dispatchOnce函数来处理当前发生的键盘事件。
Step 10. InputDispatcher.dispatchOnce
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::dispatchOnce() {
- nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
- nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();
- nsecs_t nextWakeupTime = LONG_LONG_MAX;
- { // acquire lock
- AutoMutex _l(mLock);
- dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
- ......
- } // release lock
- ......
- }
Step 11. InputDispatcher.dispatchOnceInnerLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
- nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) {
- ......
- // Ready to start a new event.
- // If we don't already have a pending event, go grab one.
- if (! mPendingEvent) {
- if (mInboundQueue.isEmpty()) {
- ......
- } else {
- // Inbound queue has at least one entry.
- EventEntry* entry = mInboundQueue.headSentinel.next;
- ......
- mInboundQueue.dequeue(entry);
- mPendingEvent = entry;
- }
- ......
- }
- ......
- switch (mPendingEvent->type) {
- ......
- case EventEntry::TYPE_KEY: {
- KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
- ......
- done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
- &dropReason, nextWakeupTime);
- break;
- }
- ......
- }
- ......
- }
我们忽略了这个函数的次要逻辑,主要关注键盘事件的主要处理流程。首先,如果前面发生的键盘事件都已经处理完毕,那么这里的mPendingEvent就为NULL,又因为前面我们把刚刚发生的键盘事件加入了mInboundQueue队列,因此,这里mInboundQueue不为NULL,于是,这里就把mInboundQueue队列中的键盘事件取出来,放在mPendingEvent变量中:
- mInboundQueue.dequeue(entry);
- mPendingEvent = entry;
Step 12. InputDispatcher.dispatchKeyLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- bool InputDispatcher::dispatchKeyLocked(
- nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
- DropReason* dropReason, nsecs_t* nextWakeupTime) {
- ......
- // Identify targets.
- if (! mCurrentInputTargetsValid) {
- int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
- ......
- }
- // Dispatch the key.
- dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
- return true;
- }
我们先来看一InputDispatcher是如何找到当前激活的Activity窗口的,然后再分析它把键盘事件分发给当前激活Activity窗口的过程。
Step 13. InputDispatcher.findFocusedWindowTargetsLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, nsecs_t* nextWakeupTime) {
- mCurrentInputTargets.clear();
- int32_t injectionResult;
- // If there is no currently focused window and no focused application
- // then drop the event.
- if (! mFocusedWindow) {
- if (mFocusedApplication) {
- ......
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, NULL, nextWakeupTime);
- goto Unresponsive;
- }
- ......
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
- }
- // Check permissions.
- if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
- injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
- goto Failed;
- }
- // If the currently focused window is paused then keep waiting.
- if (mFocusedWindow->paused) {
- ......
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
- goto Unresponsive;
- }
- // If the currently focused window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
- ......
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
- goto Unresponsive;
- }
- // Success! Output targets.
- injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0));
- ......
- return injectionResult;
- }
第二个if语句检查权限问题,原来,这个键盘事件除了是由硬件触发的外,也可以由其它进程注入进来的,如果这个键盘事件是由其它进程注入进来的,那么entry->injectState就不为NULL,它里面包含了事件注册者的进程ID和用户ID,于是,这里就会调用checkInjectionPermission来检查这个事件注入者的进程ID和用户ID,看看它是否具有这个权限。这里我们不考虑这种情况,因此,这里的entry->injectState为NULL,于是,这个if语句的检查也通过了。
第三个if语句检查当前激活的Activity窗口是否是处于paused状态,如果是的话,也不用进一步处理了。一般情况下,当前激活的Activity窗口都是处于resumed状态的,于是,这个if语句的检查也通过了。
第四个if语句检查当前激活的Activity窗口是否还正在处理前一个键盘事件,如果是的话,那就要等待它处理完前一个键盘事件后再来处理新的键盘事件了。这里我们也假设当前激活的Activity窗口不是正在处理前面的键盘事件,因此,这个if语句的检查也通过了。
最后,就调用addWindowTargetLocked函数把当前激活的Activity窗口添加到InputDispatcher类的mCurrentInputTargets成员变量中去。
Step 14. InputDispatcher.addWindowTargetLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
- BitSet32 pointerIds) {
- mCurrentInputTargets.push();
- InputTarget& target = mCurrentInputTargets.editTop();
- target.inputChannel = window->inputChannel;
- target.flags = targetFlags;
- target.xOffset = - window->frameLeft;
- target.yOffset = - window->frameTop;
- target.pointerIds = pointerIds;
- }
回到Step 12中的dispatchKeyLocked函数,它接下来就调用dispatchEventToCurrentInputTargetsLocked来进一步处理了。
Step 15. InputDispatcher.dispatchEventToCurrentInputTargetsLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
- EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
- ......
- for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
- const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
- ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
- if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
- resumeWithAppendedMotionSample);
- } else {
- ......
- }
- }
前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18中(InputDispatcher.registerInputChannel),把Server端的InputChannel封装成了一个Connection,然后以这个InputChannel中的Receive Pipe Fd作为键值把这个Connection对象保存在mConnectionsByReceiveFd中。这里,既然我们已经通过mCurrentInputTargets得到了表示当前需要接收键盘事件的Activity窗口的InputTarget对象,而且这个InputTarget对象的inputChannel就表示当初在InputDispatcher中注册的Server端InputChannel,因此,这里就可以把这个Connection对象取出来,最后调用prepareDispatchCycleLocked函数来进一步处理。
Step 16. InputDispatcher.prepareDispatchCycleLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample) {
- ......
- // Resume the dispatch cycle with a freshly appended motion sample.
- // First we check that the last dispatch entry in the outbound queue is for the same
- // motion event to which we appended the motion sample. If we find such a dispatch
- // entry, and if it is currently in progress then we try to stream the new sample.
- bool wasEmpty = connection->outboundQueue.isEmpty();
- if (! wasEmpty && resumeWithAppendedMotionSample) {
- ......
- return;
- }
- // This is a new event.
- // Enqueue a new dispatch entry onto the outbound queue for this connection.
- DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
- inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset);
- ......
- // Enqueue the dispatch entry.
- connection->outboundQueue.enqueueAtTail(dispatchEntry);
- // If the outbound queue was previously empty, start the dispatch cycle going.
- if (wasEmpty) {
- ......
- startDispatchCycleLocked(currentTime, connection);
- }
- }
在开始处理键盘事件之前,这个函数会检查一下传进来的参数connection中的outboundQueue事件队列是否为空,如果不为空,就要看看当前要处理的事件和outboundQueue队列中的最后一个事件是不是同一个motion事件,如果是的话,并且从上面传进来的resumeWithAppendedMotionSample参数为true,这时候就要以流水线的方式来处理这些motion事件了。在我们这个情景中,要处理的是键盘事件,因此在上面Step 12中传进来的resumeWithAppendedMotionSample参数为false,因此,我们略过这种情况。
接下来,就会把当前的键盘事件封装成一个DispatchEntry对象,然后添加到connection对象的outboundQueue队列中去,表示当前键盘事件是一个待处理的键盘事件。
当connection中的outboundQueue事件队列不为空,即wasEmpty为false时,说明当前这个Activity窗口正在处键盘事件了,因此,就不需要调用startDispatchCycleLocked来启动Activity窗口来处理这个事件了,因为一旦这个Activity窗口正在处键盘事件,它就会一直处理下去,直到它里的connection对象的outboundQueue为空为止。当connection中的outboundQueue事件队列为空时,就需要调用startDispatchCycleLocked来通知这个Activity窗口来执行键盘事件处理的流程了。
Step 17. InputDispatcher.startDispatchCycleLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
- ......
- DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
- // Mark the dispatch entry as in progress.
- dispatchEntry->inProgress = true;
- // Update the connection's input state.
- EventEntry* eventEntry = dispatchEntry->eventEntry;
- ......
- // Publish the event.
- status_t status;
- switch (eventEntry->type) {
- case EventEntry::TYPE_KEY: {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
- // Apply target flags.
- int32_t action = keyEntry->action;
- int32_t flags = keyEntry->flags;
- // Publish the key event.
- status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source,
- action, flags, keyEntry->keyCode, keyEntry->scanCode,
- keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
- keyEntry->eventTime);
- ......
- break;
- }
- ......
- }
- // Send the dispatch signal.
- status = connection->inputPublisher.sendDispatchSignal();
- ......
- }
Step 18. InputPublisher.publishKeyEvent
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputPublisher::publishKeyEvent(
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t keyCode,
- int32_t scanCode,
- int32_t metaState,
- int32_t repeatCount,
- nsecs_t downTime,
- nsecs_t eventTime) {
- ......
- status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
- if (result < 0) {
- return result;
- }
- mSharedMessage->key.action = action;
- mSharedMessage->key.flags = flags;
- mSharedMessage->key.keyCode = keyCode;
- mSharedMessage->key.scanCode = scanCode;
- mSharedMessage->key.metaState = metaState;
- mSharedMessage->key.repeatCount = repeatCount;
- mSharedMessage->key.downTime = downTime;
- mSharedMessage->key.eventTime = eventTime;
- return OK;
- }
这个匿名共享内存是什么时候创建的呢?前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18中(InputDispatcher.registerInputChannel),在把Server端的InputChannel封装成一个 Connection对象时,会调用它的initialize成员函数来执行一些初始化工作,就是在这个时候创建这个匿名共享内存的了:
- sp<Connection> connection = new Connection(inputChannel);
- status_t status = connection->initialize();
- status_t InputPublisher::initialize() {
- ......
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_get_size_region(ashmemFd);
- ......
- mAshmemSize = (size_t) result;
- mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
- ......
- mPinned = true;
- mSharedMessage->consumed = false;
- return reset();
- }
这个匿名共享内存mSharedMessage的作用是什么呢?原来,在InputChannel中,前向管道和反向管道的作用只是用来在Server端和Client端之间相互通知有事件发生了,但是具体是什么样的事件,还需要去读取这个匿名共享内存的内容才知道。前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 14中(InputChannel.openInputChannelPair)创建Server端和Client端的InputChannel对时,创建一个匿名共享内存,这个匿名共享内存有两个文件描述符同时指向它,其中一个放在Server端的InputChannel中,另外一个放在Client端的InputChannel中。这样,当InputDispatcher通过Server端的InputChannel的前向管道来通知Client端有键盘事件发生时,Client端只要通过它的InputChannel中的匿名共享内存文件描述符去读取匿名共享内存中的内容,就可以知道发生了什么事情了。有关匿名共享内存的相关知识,请参考Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划一文。
回到Step 17中,接下来就是调用InputPublisher的成员函数sendDispatchSignal来通知Activity窗口处理键盘事件了。
Step 19. InputPublishe.sendDispatchSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputPublisher::sendDispatchSignal() {
- ......
- mWasDispatched = true;
- return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
- }
Step 20. InputChannel.sendSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputChannel::sendSignal(char signal) {
- ssize_t nWrite;
- do {
- nWrite = ::write(mSendPipeFd, & signal, 1);
- } while (nWrite == -1 && errno == EINTR);
- if (nWrite == 1) {
- ......
- return OK;
- }
- return -errno;
- }
在前面分析应用程序注册键盘消息接收通道过程的Step 21中,我们也说过,当应用程序的主线程因为这个InputChannel中的前向管道的写端唤醒时,NativeInputQueue的成员函数handleReceiveCallback就会被回调,因此,接下来,应用程序的主线程就会被唤醒,然后执行NativeInputQueue的成员函数handleReceiveCallback。
Step 21. NativeInputQueue.handleReceiveCallback
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
- NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- sp<Connection> connection;
- InputEvent* inputEvent;
- jobject inputHandlerObjLocal;
- jlong finishedToken;
- { // acquire lock
- AutoMutex _l(q->mLock);
- ssize_t connectionIndex = q->mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- connection = q->mConnectionsByReceiveFd.valueAt(connectionIndex);
- ......
- status_t status = connection->inputConsumer.receiveDispatchSignal();
- if (status) {
- ......
- return 0; // remove the callback
- }
- ......
- status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent);
- ......
- finishedToken = generateFinishedToken(receiveFd, connection->id, connection->messageSeqNum);
- inputHandlerObjLocal = env->NewLocalRef(connection->inputHandlerObjGlobal);
- } // release lock
- ......
- int32_t inputEventType = inputEvent->getType();
- jobject inputEventObj;
- jmethodID dispatchMethodId;
- switch (inputEventType) {
- case AINPUT_EVENT_TYPE_KEY:
- ......
- inputEventObj = android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- dispatchMethodId = gInputQueueClassInfo.dispatchKeyEvent;
- break;
- }
- ......
- }
- ......
- env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
- dispatchMethodId, inputHandlerObjLocal, inputEventObj,
- jlong(finishedToken));
- ......
- return 1;
- }
这个函数首先是通过参数data获得当初注册InputChannel的NativeInputQueue对象,具体可以参考前面介绍的应用程序注册键盘消息接收通道过程的Step 21。接下来再通过参数receiveFd获得保存在这个NativeInputQueue对象中的mConnectionsByReceiveFd成员变量中的Connection对象。有了这个Connection对象后,就可以获得它内部的InputConsumer对象,这个InputConsumer对象是和上面的Step 18中介绍的InputPublisher对象相应的。
在InputChannel内部中,分别有一个InputPublisher对象和一个InputConsumer对象,对于Server端的InputChannel来说,它使用的是InputPublisher对象,通过它进行键盘消息的分发,而对于Client端的InputChannel来说,它使用的是InputConsumer对象,通过它进行键盘消息的读取。
获得了这个InputConsumer对象后首先是调用它的receiveDispatchSignal来确认是否是接收到了键盘消息的通知,如果是的话,再调用它的consume函数来把键盘事件读取出来,最后,调用Java层的回调对象InputQueue的DispatchKeyEvent来处理这个键盘事件。下面,我们就依次来分析这些过程。
Step 22. InputConsumer.receiveDispatchSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputConsumer::receiveDispatchSignal() {
- ......
- char signal;
- status_t result = mChannel->receiveSignal(& signal);
- if (result) {
- return result;
- }
- if (signal != INPUT_SIGNAL_DISPATCH) {
- ......
- return UNKNOWN_ERROR;
- }
- return OK;
- }
InputChannel类的receiveSignal函数也是定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputChannel::receiveSignal(char* outSignal) {
- ssize_t nRead;
- do {
- nRead = ::read(mReceivePipeFd, outSignal, 1);
- } while (nRead == -1 && errno == EINTR);
- if (nRead == 1) {
- ......
- return OK;
- }
- ......
- return -errno;
- }
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
- ......
- *outEvent = NULL;
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_pin_region(ashmemFd, 0, 0);
- ......
- if (mSharedMessage->consumed) {
- ......
- return INVALID_OPERATION;
- }
- // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
- // to the publisher that the message has been consumed (or is in the process of being
- // consumed). Eventually the publisher will reinitialize the semaphore for the next message.
- result = sem_wait(& mSharedMessage->semaphore);
- ......
- mSharedMessage->consumed = true;
- switch (mSharedMessage->type) {
- case AINPUT_EVENT_TYPE_KEY: {
- KeyEvent* keyEvent = factory->createKeyEvent();
- if (! keyEvent) return NO_MEMORY;
- populateKeyEvent(keyEvent);
- *outEvent = keyEvent;
- break;
- }
- ......
- }
- return OK;
- }
回到Step 21中的handleReceiveCallback函数中,从InputConsumer中获得了键盘事件的内容(保存在本地变量inputEvent中)后,就开始要通知Java层的应用程序了。在前面分析应用程序注册键盘消息接收通道的过程时,在Step 21中(NativeInputQueue.registerInputChannel),会把传进来的对象inputHandlerObj保存在Connection对象中:
- connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);
- inputHandlerObjLocal = env->NewLocalRef(connection->inputHandlerObjGlobal);
- dispatchMethodId = gInputQueueClassInfo.dispatchKeyEvent;
- inputEventObj = android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
- dispatchMethodId, inputHandlerObjLocal, inputEventObj,
- jlong(finishedToken));
这个函数定义在frameworks/base/core/java/android/view/InputQueue.java文件中:
- public final class InputQueue {
- ......
- private static void dispatchKeyEvent(InputHandler inputHandler,
- KeyEvent event, long finishedToken) {
- Runnable finishedCallback = FinishedCallback.obtain(finishedToken);
- inputHandler.handleKey(event, finishedCallback);
- }
- ......
- }
这里的inputHandler对象是在前面分析应用程序注册键盘消息接收通道的过程时,在Step 1(ViewRoot.setView)中传进来的:
- InputQueue.registerInputChannel(mInputChannel, mInputHandler,
- Looper.myQueue());
Step 25. InputHandler.handleKey
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- private final InputHandler mInputHandler = new InputHandler() {
- public void handleKey(KeyEvent event, Runnable finishedCallback) {
- startInputEvent(finishedCallback);
- dispatchKey(event, true);
- }
- ......
- };
- ......
- }
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- private void startInputEvent(Runnable finishedCallback) {
- ......
- mFinishedCallback = finishedCallback;
- }
- ......
- }
Step 26. ViewRoot.dispatchKey
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- private void dispatchKey(KeyEvent event, boolean sendDone) {
- ......
- Message msg = obtainMessage(DISPATCH_KEY);
- msg.obj = event;
- msg.arg1 = sendDone ? 1 : 0;
- ......
- sendMessageAtTime(msg, event.getEventTime());
- }
- ......
- }
Step 27. ViewRoot.deliverKeyEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
- // If mView is null, we just consume the key event because it doesn't
- // make sense to do anything else with it.
- boolean handled = mView != null
- ? mView.dispatchKeyEventPreIme(event) : true;
- ......
- // If it is possible for this window to interact with the input
- // method window, then we want to first dispatch our key events
- // to the input method.
- if (mLastWasImTarget) {
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null && mView != null) {
- ......
- imm.dispatchKeyEvent(mView.getContext(), seq, event,
- mInputMethodCallback);
- return;
- }
- }
- ......
- }
- ......
- }
Step 28. InputMethodManager.dispatchKeyEvent
这个函数定义在frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java文件中。这是一个输入法相关的类,我们这里就不关注了,只要知道当输入法处理完成之后,它就会调用ViewRoot类的mInputMehtodCallback对象的finishedEvent成员函数。
Step 29. InputMethodCallack.finishedEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- static class InputMethodCallback extends IInputMethodCallback.Stub {
- private WeakReference<ViewRoot> mViewRoot;
- public InputMethodCallback(ViewRoot viewRoot) {
- mViewRoot = new WeakReference<ViewRoot>(viewRoot);
- }
- public void finishedEvent(int seq, boolean handled) {
- final ViewRoot viewRoot = mViewRoot.get();
- if (viewRoot != null) {
- viewRoot.dispatchFinishedEvent(seq, handled);
- }
- }
- ......
- }
- ......
- }
Step 30. ViewRoot.dispatchFinishedEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- public void dispatchFinishedEvent(int seq, boolean handled) {
- Message msg = obtainMessage(FINISHED_EVENT);
- msg.arg1 = seq;
- msg.arg2 = handled ? 1 : 0;
- sendMessage(msg);
- }
- ......
- }
Step 31. ViewRoot.handleFinishedEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- void handleFinishedEvent(int seq, boolean handled) {
- final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
- ......
- if (event != null) {
- final boolean sendDone = seq >= 0;
- if (!handled) {
- deliverKeyEventToViewHierarchy(event, sendDone);
- return;
- } else if (sendDone) {
- ......
- } else {
- ......
- }
- }
- }
- ......
- }
Step 32. ViewRoot.deliverKeyEventToViewHierarchy
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- private void deliverKeyEventToViewHierarchy(KeyEvent event, boolean sendDone) {
- try {
- if (mView != null && mAdded) {
- ......
- boolean keyHandled = mView.dispatchKeyEvent(event);
- }
- ......
- } finally {
- if (sendDone) {
- finishInputEvent();
- }
- }
- }
- ......
- }
ViewRoot类的成员变量mView的类型为DecorView,它是由ActivityThread类第一次Resume当前的Activity窗口时创建的,具体可以参考ActivityThread类的handleResumeActivity成员函数,这里就不关注了。
Step 33. DecorView.dispatchKeyEvent
这个函数定义在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java文件中,它是PhoneWindow类的一个内部类:
- public class PhoneWindow extends Window implements MenuBuilder.Callback {
- ......
- private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
- ......
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- ......
- final Callback cb = getCallback();
- final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
- : super.dispatchKeyEvent(event);
- ......
- }
- ......
- }
- ......
- }
Step 34. Activity.dispatchKeyEvent
这个函数定义在frameworks/base/core/java/android/app/Activity.java文件中:
- public class Activity extends ContextThemeWrapper
- implements LayoutInflater.Factory,
- Window.Callback, KeyEvent.Callback,
- OnCreateContextMenuListener, ComponentCallbacks {
- ......
- public boolean dispatchKeyEvent(KeyEvent event) {
- ......
- View decor = mDecor;
- if (decor == null) decor = win.getDecorView();
- return event.dispatch(this, decor != null
- ? decor.getKeyDispatcherState() : null, this);
- }
- ......
- }
Step 35. KeyEvent.dispatch
这个函数定义在frameworks/base/core/java/android/view/KeyEvent.java文件中:
- public class KeyEvent extends InputEvent implements Parcelable {
- ......
- public final boolean dispatch(Callback receiver, DispatcherState state,
- Object target) {
- switch (mAction) {
- case ACTION_DOWN: {
- ......
- boolean res = receiver.onKeyDown(mKeyCode, this);
- ......
- return res;
- }
- case ACTION_UP:
- ......
- return receiver.onKeyUp(mKeyCode, this);
- case ACTION_MULTIPLE:
- final int count = mRepeatCount;
- final int code = mKeyCode;
- if (receiver.onKeyMultiple(code, count, this)) {
- return true;
- }
- ......
- return false;
- }
- return false;
- }
- ......
- }
Activity窗口处理完这个键盘事件后,层层返回,最后回到Step 32中,调用finishInputEvent事件来处理一些手尾工,下面我们将会看到这些手尾工是什么。
Step 36. ViewRoot.finishInputEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.Callbacks {
- ......
- private void finishInputEvent() {
- ......
- if (mFinishedCallback != null) {
- mFinishedCallback.run();
- mFinishedCallback = null;
- } else {
- ......
- }
- }
- ......
- }
ViewRoot类里面的成员变量mFinishedCallback是在前面Step 25中由InputQueue设置的,它是一个Runnable对象,实际类型是定义在InputQueue的内部类FinishedCallback,因此,这里调用它的run方法时,接下来就会调用InputQueue的内部类FinishedCallback的run成员函数:
- public final class InputQueue {
- ......
- private static class FinishedCallback implements Runnable {
- ......
- public void run() {
- synchronized (sLock) {
- ......
- nativeFinished(mFinishedToken);
- ......
- }
- }
- ......
- }
- ......
- }
Step 37. InputQueue.nativeFinished
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- static void android_view_InputQueue_nativeFinished(JNIEnv* env, jclass clazz,
- jlong finishedToken) {
- status_t status = gNativeInputQueue.finished(
- env, finishedToken, false /*ignoreSpuriousFinish*/);
- ......
- }
Step 38. NativeInputQueue.finished
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- status_t NativeInputQueue::finished(JNIEnv* env, jlong finishedToken, bool ignoreSpuriousFinish) {
- int32_t receiveFd;
- uint16_t connectionId;
- uint16_t messageSeqNum;
- parseFinishedToken(finishedToken, &receiveFd, &connectionId, &messageSeqNum);
- { // acquire lock
- AutoMutex _l(mLock);
- ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- ......
- connection->messageInProgress = false;
- status_t status = connection->inputConsumer.sendFinishedSignal();
- ......
- } // release lock
- return OK;
- }
- finishedToken = generateFinishedToken(receiveFd, connection->id, connection->messageSeqNum);
- jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,
- uint16_t messageSeqNum) {
- return (jlong(receiveFd) << 32) | (jlong(connectionId) << 16) | jlong(messageSeqNum);
- }
因此,在上面的finished函数里面,首先就是要对参数值finishedToken进行解码,把receiveFd、connectionId和messageSeqNum三个值分别取回来:
- parseFinishedToken(finishedToken, &receiveFd, &connectionId, &messageSeqNum);
- void NativeInputQueue::parseFinishedToken(jlong finishedToken,
- int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex) {
- *outReceiveFd = int32_t(finishedToken >> 32);
- *outConnectionId = uint16_t(finishedToken >> 16);
- *outMessageIndex = uint16_t(finishedToken);
- }
- ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- status_t status = connection->inputConsumer.sendFinishedSignal();
Step 39. InputConsumer.sendFinishedSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputConsumer::sendFinishedSignal() {
- ......
- return mChannel->sendSignal(INPUT_SIGNAL_FINISHED);
- }
前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18(InputDispatcher.registerInputChannel)中,说到InputDispatcher把一个反向管道的读端文件描述符添加到WindowManagerService所运行的线程中的Looper对象中去,然后就会在这个反向管道的读端上睡眠等待有这个管道有新的内容可读。现在,InputConsumer往这个反向管道写入新的内容了,于是,InputDispatcher就被唤醒过来了,唤醒过来后,它所调用的函数是InputDispatcher.handleReceiveCallback函数,这与前面的Step 21的逻辑是一样的。
Step 40. InputDispatcher.handleReceiveCallack
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
- InputDispatcher* d = static_cast<InputDispatcher*>(data);
- { // acquire lock
- AutoMutex _l(d->mLock);
- ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- nsecs_t currentTime = now();
- sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
- ......
- status_t status = connection->inputPublisher.receiveFinishedSignal();
- if (status) {
- ......
- return 0; // remove the callback
- }
- d->finishDispatchCycleLocked(currentTime, connection);
- ......
- return 1;
- } // release lock
- }
- ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
Step 41. InputPublisher.receiverFinishedSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_t InputPublisher::receiveFinishedSignal() {
- ....
- char signal;
- status_t result = mChannel->receiveSignal(& signal);
- if (result) {
- return result;
- }
- if (signal != INPUT_SIGNAL_FINISHED) {
- .......
- return UNKNOWN_ERROR;
- }
- return OK;
- }
回到前面的Step 40中,确认了是真的收到了键盘事件处理完成的信号后,就调用InputDispatcher的finishDispatchCycleLocked函数来执行一些善后工作了。
Step 42. InputDispatcher.finishDispatchCycleLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
- ......
- // Notify other system components.
- onDispatchCycleFinishedLocked(currentTime, connection);
- // Reset the publisher since the event has been consumed.
- // We do this now so that the publisher can release some of its internal resources
- // while waiting for the next dispatch cycle to begin.
- status_t status = connection->inputPublisher.reset();
- ......
- startNextDispatchCycleLocked(currentTime, connection);
- }
一是通知其它系统,InputDispatcher完成了一次键盘事件的处理:
- // Notify other system components.
- onDispatchCycleFinishedLocked(currentTime, connection);
- // Reset the publisher since the event has been consumed.
- // We do this now so that the publisher can release some of its internal resources
- // while waiting for the next dispatch cycle to begin.
- status_t status = connection->inputPublisher.reset();
- startNextDispatchCycleLocked(currentTime, connection);
至此,InputManager分发键盘消息给应用程序的过程就分析完成了,这是一个比较复杂的过程,不过,只要我们抓住主要的线索,就不难理解了,现在我们就小结一下这个过程的四个主要线索:
A. 键盘事件发生,InputManager中的InputReader被唤醒,此前InputReader睡眠在/dev/input/event0这个设备文件上;
B. InputReader被唤醒后,它接着唤醒InputManager中的InputDispatcher,此前InputDispatcher睡眠在InputManager所运行的线程中的Looper对象里面的管道的读端上;
C. InputDispatcher被唤醒后,它接着唤醒应用程序的主线程来处理这个键盘事件,此前应用程序的主线程睡眠在Client端InputChannel中的前向管道的读端上;
D. 应用程序处理处理键盘事件之后,它接着唤醒InputDispatcher来执行善后工作,此前InputDispatcher睡眠在Server端InputChannel的反向管道的读端上,注意这里与第二个线索处的区别。
----
下接:Android应用程序键盘(Keyboard)消息处理机制分析(四)