在Android输入子系统之启动过程分析中,InputManagerService启动之后,会调用start函数,之后调用native层的nativeStart函数,然后调用InputManager::start函数,该函数会调用InputReaderThread的threadLoop函数,该函数会调用InputReader的loopOnce函数从EventHub中读取一次键盘事件。
该函数定义在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函数就会进入等待状态。
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函数返回。
下面先分析扫描输入设备的过程
该函数定义在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目录
该函数定义在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打开该设备文件
该函数定义在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文件
该函数定义在frameworks/native/services/inputflinger/EventHub.cpp
status_t EventHub::loadKeyMapLocked(Device* device) {
return device->keyMap.load(device->identifier, device->configuration);
}
函数调用Device的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=458792
EventHub: /dev/input/event2 got: time=4383.680195, type=1, code=28, value=1
EventHub: /dev/input/event2 got: time=4383.680195, type=0, code=0, value=0
EventHub: /dev/input/event2 got: time=4383.760186, type=4, code=4, value=458792
EventHub: /dev/input/event2 got: time=4383.760186, type=1, code=28, value=0
EventHub: /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。
该函数定义在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
该函数定义在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函数
该函数定义在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对象。
该函数定义在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来进一步处理
该函数定义在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函数
该函数定义在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);
该函数定义在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