Android输入子系统之InputReader读取键盘消息过程分析
InputReader读取键盘消息过程分析
在Android输入子系统之启动过程分析中,InputManagerService启动之后,会调用start函数,之后调用native层的nativeStart函数,然后调用InputManager::start函数,该函数会调用InputReaderThread的threadLoop函数,该函数会调用InputReader的loopOnce函数从EventHub中读取一次键盘事件。
Step 1. InputReader.loopOnce
该函数定义在frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() { // size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { processEventsLocked(mEventBuffer, count); } if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) { mNextTimeout = LLONG_MAX; timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; getInputDevicesLocked(inputDevices); } } // release lock}
loopOnce通过EventHub来读取键盘事件,如果当前有键盘事件发生或者有键盘事件等待处理,则调用getEvents函数就可以得到这个事件,然后调用processEventsLocked函数处理;如果没有键盘事件发生,那么调用getEvents函数就会进入等待状态。
Step 2. EventHub.getEvents
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ALOG_ASSERT(bufferSize >= 1); AutoMutex _l(mLock); struct input_event readBuffer[bufferSize]; RawEvent* event = buffer; size_t capacity = bufferSize; bool awoken = false; for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); // Reopen input devices if needed. //第一次进入该函数,mNeedToReopenDevices为false if (mNeedToReopenDevices) { mNeedToReopenDevices = false; closeAllDevicesLocked(); mNeedToScanDevices = true; break; // return to the caller before we actually rescan } // Report any devices that had last been added/removed. //第一次进入该函数,mClosingDevices为false while (mClosingDevices) { Device* device = mClosingDevices; ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.string()); mClosingDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id; event->type = DEVICE_REMOVED; event += 1; delete device; mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } //第一次进入,mNeedToScanDevices为true if (mNeedToScanDevices) { mNeedToScanDevices = false; scanDevicesLocked(); mNeedToSendFinishedDeviceScan = true; } //第一次进入,mOpeningDevices 为NULL while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string()); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; event->type = DEVICE_ADDED; event += 1; mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } //第一次进入,由于mNeedToScanDevices未true,mNeedToSendFinishedDeviceScan会被置为true if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; event->when = now; event->type = FINISHED_DEVICE_SCAN; event += 1; if (--capacity == 0) { break; } } // Grab the next input event. //第一次进入mPendingEventIndex == mPendingEventCount,均为0 bool deviceChanged = false; while (mPendingEventIndex < mPendingEventCount) { const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; if (eventItem.data.u32 == EPOLL_ID_INOTIFY) { if (eventItem.events & EPOLLIN) { mPendingINotify = true; } continue; } if (eventItem.data.u32 == EPOLL_ID_WAKE) { if (eventItem.events & EPOLLIN) { ALOGV("awoken after wake()"); awoken = true; char buffer[16]; ssize_t nRead; do { nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); } continue; } ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); if (deviceIndex < 0) { ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.", eventItem.events, eventItem.data.u32); continue; } Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity); if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %" PRId32 " bufferSize: %zu capacity: %zu errno: %d)\n", device->fd, readSize, bufferSize, capacity, errno); deviceChanged = true; closeDeviceLocked(device); } else if (readSize < 0) { if (errno != EAGAIN && errno != EINTR) { ALOGW("could not get event (errno=%d)", errno); } } else if ((readSize % sizeof(struct input_event)) != 0) { ALOGE("could not get event (wrong size: %d)", readSize); } else { int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; size_t count = size_t(readSize) / sizeof(struct input_event); for (size_t i = 0; i < count; i++) { struct input_event& iev = readBuffer[i]; event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL; event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; event->value = iev.value; event += 1; capacity -= 1; } if (capacity == 0) { // The result buffer is full. Reset the pending event index // so we will try to read the device again on the next iteration. mPendingEventIndex -= 1; break; } } } else if (eventItem.events & EPOLLHUP) { ALOGI("Removing device %s due to epoll hang-up event.", device->identifier.name.string()); deviceChanged = true; closeDeviceLocked(device); } else { ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, device->identifier.name.string()); } } // readNotify() will modify the list of devices so this must be done after // processing all other events to ensure that we read all remaining events // before closing the devices. if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { mPendingINotify = false; readNotifyLocked(); deviceChanged = true; } // Report added or removed devices immediately. if (deviceChanged) { continue; } // Return now if we have collected any events or if we were explicitly awoken. //如果收集到任何的输入事件,则执行break命令,退出for死循环 if (event != buffer || awoken) { break; } mPendingEventIndex = 0; mLock.unlock(); // release lock before poll, must be before release_wake_lock release_wake_lock(WAKE_LOCK_ID); //调用epoll_wait等待按键事件,如果没有按键事件,将睡眠 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock if (pollResult == 0) { // Timed out. mPendingEventCount = 0; break; } if (pollResult < 0) { // An error occurred. mPendingEventCount = 0; // Sleep after errors to avoid locking up the system. // Hopefully the error is transient. if (errno != EINTR) { ALOGW("poll failed (errno=%d)\n", errno); usleep(100000); } } else { // Some events occurred. mPendingEventCount = size_t(pollResult); } } // All done, return the number of events we read. return event - buffer;}
该函数第一次进入时,mNeedToReopenDevices和mClosingDevices为false,mNeedToScanDevices为true,所以会调用scanDevicesLocked来打开输入设备节点。之后由于是第一次进入,mPendingEventIndex和mPendingEventCount为0,所以while循环不执行。之后会调用epoll_wait等待按键事件的发生。当有按键事件发生后,会读取到按键事件,然后再走到for死循环中,此时由于mPendingEventCount>0,因此会进入while循环,其中会读出发生的键盘事件,并保存在buffer数组中,然后event != buffer所以退出for死循环,getEvents函数返回。
下面先分析扫描输入设备的过程
Step 3. EventHub::scanDevicesLocked
该函数定义在frameworks/native/services/inputflinger/EventHub.cpp
void EventHub::scanDevicesLocked() { status_t res = scanDirLocked(DEVICE_PATH); if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) { ALOGE("-- createVirtualKeyboardLocked"); createVirtualKeyboardLocked(); }}
函数主要调用scanDirLocked来扫描/dev/input目录
Step 4. EventHub::scanDirLocked
该函数定义在frameworks/native/services/inputflinger/EventHub.cpp
status_t EventHub::scanDirLocked(const char *dirname){ char devname[PATH_MAX]; char *filename; DIR *dir; struct dirent *de; dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); openDeviceLocked(devname); } closedir(dir); return 0;}
函数调用readdir函数扫描/dev/input下的文件,该目录下一般是event0、mice和mouse0三个文件存在,在Mstar的电视芯片上一般还有event1表示遥控器设备。然后调用openDeviceLocked打开该设备文件
Step 5. EventHub::openDeviceLocked
该函数定义在frameworks/native/services/inputflinger/EventHub.cpp
status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("-- Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR | O_CLOEXEC); if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } InputDeviceIdentifier identifier; ... //该段是获取设备的一些信息,初始化identifier的一些属性,以及加载 ... // Load the key map. // We need to do this for joysticks too because the key layout may specify axes. status_t keyMapStatus = NAME_NOT_FOUND; if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { // Load the keymap for the device. //加载kl和kcm文件 keyMapStatus = loadKeyMapLocked(device); } ... //将前面打开的设备的文件描述符加入到epoll监听中 if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; }
该函数打开扫描到的/dev/input下的设备文件,然后获取该设备文件的name,bus,product,vendor,version,location,uniqueId,descriptor等,以及设备类型,如是否是键盘,是否是虚拟按键等。如果是INPUT_DEVICE_CLASS_KEYBOARD
这个类型,则调用loadKeyMapLocked来加载kl文件
Step 6. EventHub.loadKeyMapLocked
该函数定义在frameworks/native/services/inputflinger/EventHub.cpp
status_t EventHub::loadKeyMapLocked(Device* device) { return device->keyMap.load(device->identifier, device->configuration);}
函数调用Device的KeyMap结构体的load函数
Step 7. KeyMap.load
frameworks/native /libs/input/Keyboard.cpp
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); } if (isComplete()) { return OK; } } // Try searching by device identifier. if (probeKeyMap(deviceIdenfifier, String8::empty())) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { return OK; } // Try the Virtual key map as a last resort. if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { return OK; } // Give up! return NAME_NOT_FOUND;}
如果configuration不为空,即存在idc文件,则根据idc文件中指定的keyboard.layout和keyboard.characterMap来加载指定的kl和kcm文件
如果configuration为空,则根据deviceIdenfifier来加载kl和kcm文件(这个会根据vendor,product,version三个属性来决定加载哪个文件)
如果deviceIdenfifier无法找到配置文件,则根据名字Generic来加载文件,即Generic.kl和Generic.kcm文件
如果Generic.kl和Generic.kcm无法找到,则根据名字Virtual来加载文件,即Virtual.kl和Virtual.kcm文件
至此输入设备扫描完成,并加入epoll中,监听事件。从前面的getEvents函数分析得知,当按键事件发生后,getEvents函数返回,返回值为输入事件的个数,以一次键盘按键为例,得到下面的6个事件
EventHub: /dev/input/event2 got: time=4383.680195, type=4, code=4, value=458792EventHub: /dev/input/event2 got: time=4383.680195, type=1, code=28, value=1EventHub: /dev/input/event2 got: time=4383.680195, type=0, code=0, value=0EventHub: /dev/input/event2 got: time=4383.760186, type=4, code=4, value=458792EventHub: /dev/input/event2 got: time=4383.760186, type=1, code=28, value=0EventHub: /dev/input/event2 got: time=4383.760186, type=0, code=0, value=0
上面的type是linux的输入系统里的事件,具体的值可以查看
可以查看input.h,可以事业locate查找,有很多的头文件,找到一个查看一下即可
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */#define EV_SYN 0x00 同步事件#define EV_KEY 0x01 按键事件#define EV_REL 0x02 相对坐标#define EV_ABS 0x03 绝对坐标/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */#define EV_MSC 0x04 其它#define EV_SW 0x05 #define EV_LED 0x11 LED#define EV_SND 0x12 声音/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */#define EV_REP 0x14 Repeat#define EV_FF 0x15 力反馈 #define EV_PWR 0x16 电源#define EV_FF_STATUS 0x17 状态
上面6个事件,只有两个type为1的事件,是我们需要处理的按键事件,一个down,一个up
返回到InputReader的loopOnce函数
void InputReader::loopOnce() { size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); //当有按键事件发生时,count将不为0,以一次按键为例,这里应该是6个事件 if (count) { processEventsLocked(mEventBuffer, count); } } // release lock}
当有按键事件发生时,count将不为0,以一次按键为例,这里应该是6个事件,之后会调用processEventsLocked来处理RawEvent。
Step 8. InputReader.processEventsLocked
该函数定义在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; processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } count -= batchSize; rawEvent += batchSize; }}
该函数调用processEventsForDeviceLocked依次处理rawEvent
Step 9. InputReader.processEventsForDeviceLocked
该函数定义在frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); InputDevice* device = mDevices.valueAt(deviceIndex); device->process(rawEvents, count);}
这里根据deviceId获取到InputDevice,然后调用InputDevice的process函数
Step 10. InputDevice.process
该函数定义在frameworks/native/services/inputflinger/InputReader.cpp
void InputDevice::process(const RawEvent* rawEvents, size_t count) { size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } } } }
这里的mMappers成员变量保存了一系列输入设备事件处理对象,例如负责处理键盘事件的KeyboardKeyMapper对象以及负责处理触摸屏事件的TouchInputMapper对象, 它们是在InputReader类的成员函数createDevice中创建的。这里查询每一个InputMapper对象是否要对当前发生的事件进行处理。由于发生的是键盘事件,真正会对该事件进行处理的只有KeyboardKeyMapper对象。
Step 11. KeyboardInputMapper.process
该函数定义在frameworks/native/services/inputflinger/InputReader.cpp
void KeyboardInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { int32_t scanCode = rawEvent->code; int32_t usageCode = mCurrentHidUsage; mCurrentHidUsage = 0; if (isKeyboardOrGamepadKey(scanCode)) { int32_t keyCode; uint32_t flags; if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) { keyCode = AKEYCODE_UNKNOWN; flags = 0; } processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags); } break; } case EV_MSC: { if (rawEvent->code == MSC_SCAN) { mCurrentHidUsage = rawEvent->value; } break; } case EV_SYN: { if (rawEvent->code == SYN_REPORT) { mCurrentHidUsage = 0; } } }}
函数首先调用isKeyboardOrGamepadKey来判断键盘扫描码是否正确,如果正确则调用processKey来进一步处理
Step 12. KeyboardInputMapper.processKey
该函数定义在frameworks/native/services/inputflinger/InputReader.cpp
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) { if (down) { // Rotate key codes according to orientation if needed. if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { keyCode = rotateKeyCode(keyCode, mOrientation); } // Add key down. ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { // key repeat, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; } else { // key down if ((policyFlags & POLICY_FLAG_VIRTUAL) && mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) { return; } if (policyFlags & POLICY_FLAG_GESTURE) { mDevice->cancelTouch(when); } mKeyDowns.push(); KeyDown& keyDown = mKeyDowns.editTop(); keyDown.keyCode = keyCode; keyDown.scanCode = scanCode; } mDownTime = when; } else { // Remove key down. ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { // key up, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; mKeyDowns.removeAt(size_t(keyDownIndex)); } else { // key was not actually down ALOGI("Dropping key up from device %s because the key was not down. " "keyCode=%d, scanCode=%d", getDeviceName().string(), keyCode, scanCode); return; } } int32_t oldMetaState = mMetaState; int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState); bool metaStateChanged = oldMetaState != newMetaState; if (metaStateChanged) { mMetaState = newMetaState; updateLedState(false); } nsecs_t downTime = mDownTime; // Key down on external an keyboard should wake the device. // We don't do this for internal keyboards to prevent them from waking up in your pocket. // For internal keyboards, the key layout file should specify the policy flags for // each wake key individually. // TODO: Use the input device configuration to control this behavior more finely. if (down && getDevice()->isExternal()) {// MStar Android Patch Begin#ifdef ENABLE_STR char value[PROPERTY_VALUE_MAX]; property_get("mstar.str.suspending", value, "0"); if (atoi(value) == 0) { policyFlags |= POLICY_FLAG_WAKE; }#else policyFlags |= POLICY_FLAG_WAKE;#endif// MStar Android Patch End } if (mParameters.handlesKeyRepeat) { policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; } if (metaStateChanged) { getContext()->updateGlobalMetaState(); } if (down && !isMetaKey(keyCode)) { getContext()->fadePointer(); } NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); getListener()->notifyKey(&args);}
这个函数首先对按键作一些处理,例如,当某一个DPAD键被按下时,根据当时屏幕方向的不同,它所表示的意义也不同,因此,这里需要根据当时屏幕的方向来调整键盘码。
最后函数会调用:
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);getListener()->notifyKey(&args);
这里getListener是InputReader初始化时传入的对象,即InputDispatcher,则会调用InputDispatcher的notifyKey函数
Step 13. InputDispatcher.notifyKey
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { if (!validateKeyEvent(args->action)) { return; } uint32_t policyFlags = args->policyFlags; int32_t flags = args->flags; int32_t metaState = args->metaState; if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { policyFlags |= POLICY_FLAG_VIRTUAL; flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; } if (policyFlags & POLICY_FLAG_FUNCTION) { metaState |= AMETA_FUNCTION_ON; } policyFlags |= POLICY_FLAG_TRUSTED; int32_t keyCode = args->keyCode; if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) { int32_t newKeyCode = AKEYCODE_UNKNOWN; if (keyCode == AKEYCODE_DEL) { newKeyCode = AKEYCODE_BACK; } else if (keyCode == AKEYCODE_ENTER) { newKeyCode = AKEYCODE_HOME; } if (newKeyCode != AKEYCODE_UNKNOWN) { AutoMutex _l(mLock); struct KeyReplacement replacement = {keyCode, args->deviceId}; mReplacedKeys.add(replacement, newKeyCode); keyCode = newKeyCode; metaState &= ~AMETA_META_ON; } } else if (args->action == AKEY_EVENT_ACTION_UP) { // In order to maintain a consistent stream of up and down events, check to see if the key // going up is one we've replaced in a down event and haven't yet replaced in an up event, // even if the modifier was released between the down and the up events. AutoMutex _l(mLock); struct KeyReplacement replacement = {keyCode, args->deviceId}; ssize_t index = mReplacedKeys.indexOfKey(replacement); if (index >= 0) { keyCode = mReplacedKeys.valueAt(index); mReplacedKeys.removeItemsAt(index); metaState &= ~AMETA_META_ON; } } KeyEvent event; event.initialize(args->deviceId, args->source, args->action, flags, keyCode, args->scanCode, metaState, 0, args->downTime, args->eventTime); mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); bool needWake; { // acquire lock mLock.lock(); if (shouldSendKeyToInputFilterLocked(args)) { mLock.unlock(); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } mLock.lock(); } int32_t repeatCount = 0; KeyEntry* newEntry = new KeyEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); }}
该函数首先调用validateKeyEvent来判断是否是有效按键事件,实际判断是否是UP/DOWN事件
然后构造一个KeyEvent对象,调用mPolicy的interceptKeyBeforeQueueing函数,该函数最后会调用到java层的PhoneWindowManagerService函数
KeyEvent event; event.initialize(args->deviceId, args->source, args->action, flags, keyCode, args->scanCode, metaState, 0, args->downTime, args->eventTime); mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
之后会调用构造一个KeyEntry对象,调用enqueueInboundEventLocked函数将按键事件加入队列,如果返回true,则调用mLooper.wake函数唤醒等待的InputDispatcher,进行按键分发。
KeyEntry* newEntry = new KeyEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime);needWake = enqueueInboundEventLocked(newEntry);
Step 14. InputDispatcher.enqueueInboundEventLocked
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked(); switch (entry->type) { 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(entry); if (isAppSwitchKeyEventLocked(keyEntry)) { if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { mAppSwitchSawKeyDown = true; } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { if (mAppSwitchSawKeyDown) { mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; mAppSwitchSawKeyDown = false; needWake = true; } } } break; } } return needWake;}
将EventEntry加入到mInboundQueue中,该函数两种情况下会返回true,一是当加入该键盘事件到mInboundQueue之前,mInboundQueue为空,这表示InputDispatc herThread线程正在睡眠等待InputReaderThread线程的唤醒,因此,它返回true表示要唤醒InputDispatccherThread线程;二是加入该键盘事件到mInboundQueue之前,mInboundQueue不为空,但是此时用户按下的是Home键等需要切换APP的按键,我们知道,在切换App时,新的App会把它的键盘消息接收通道注册到InputDispatcher中去,并且会等待InputReader的唤醒,因此,在这种情况下,也需要返回true,表示要唤醒InputDispatccherThread线程。如果不是这两种情况,那么就说明InputDispatccherThread线程现在正在处理前面的键盘事件,不需要唤醒它。
至此,InputDispatcherThread被唤醒,开始进行按键分发。
参考
http://blog.csdn.net/luoshengyang/article/details/6882903
更多相关文章
- View事件分发机制
- Android ViewPager多页面滑动切换以及单页卡内添加事件
- Android sql数据库的Android包里面的函数介绍
- Android中的文本框,图片以及点击事件的设置
- Android事件拦截机制
- Android 6.0耳机hook按键接听和挂断电话;音乐中短按下一首,长按
- Android中调用C++函数的一个简单Demo