InputReader读取键盘消息过程分析

在Android输入子系统之启动过程分析中,InputManagerService启动之后,会调用start函数,之后调用native层的nativeStart函数,然后调用InputManager::start函数,该函数会调用InputReaderThread的threadLoop函数,该函数会调用InputReader的loopOnce函数从EventHub中读取一次键盘事件。
Android输入子系统之InputReader读取键盘消息过程分析_第1张图片

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

更多相关文章

  1. View事件分发机制
  2. Android ViewPager多页面滑动切换以及单页卡内添加事件
  3. Android sql数据库的Android包里面的函数介绍
  4. Android中的文本框,图片以及点击事件的设置
  5. Android事件拦截机制
  6. Android 6.0耳机hook按键接听和挂断电话;音乐中短按下一首,长按
  7. Android中调用C++函数的一个简单Demo

随机推荐

  1. android点击事件的四种方式
  2. android 正则
  3. Android手机开发:Menu功能
  4. AndroidManifest 合并出错 tools:replace
  5. Android(安卓)获取系统应用信息
  6. Android(安卓)获取设备的物理尺寸
  7. Android(安卓)中设置全屏的方法
  8. Android(安卓)RadioButton 图片位置和大
  9. Android(安卓)设置View背景图网络url
  10. Android(安卓)AudioTrack实时播放