InputReaderThread 线程负责读取事件。InputReaderThread 启动后会执行 threadLoop 函数。threadLoop 函数返回 true,InputReaderThread 就会循环执行 threadLoop 函数。具体可以参见关于 Native Thread 实现一节《Android 源码 Native Thread 分析》。InputReaderThread(称为“ InputReader”)读取并预处理原始输入事件,应用策略,并将消息发布到由 InputDispatcherThread 管理的队列中。
InputReader 从 EventHub 读取原始事件数据,并将其处理为输入事件,并将其发送到 InputListener。 InputReader 的某些功能(例如低功耗状态下的早期事件过滤)由单独的策略对象控制。
InputReader 拥有 InputMappers 的集合。它所做的大部分工作都在 InputReader 线程上进行,但是 InputReader 可以接收在任意线程上运行的其他系统组件的查询。为了使事情易于管理,InputReader 使用单个 Mutex 来保护其状态。互斥对象可以在调用 EventHub 或 InputReaderPolicy 时持有,但从不在调用 InputListener 时持有锁。
threadLoop() 函数实际上调用了 InputReader loopOnce() 方法。
frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
loopOnce 从方法名可知是轮训一次的意思。
从 EventHub 中读取未处理的事件列表。这些事件分为两类,一类是从设备节点中读取的原始输入事件;另一类则是设备事件。
通过 processEventsLocked() 对事件进行处理。对于设备事件,此函数对根据设备的可用性加载或移除设备对应的配置信息。对于原始输入事件,则在进行转译、封装与加工后将结果暂存到 mQueuedListener 中。
所有事件处理完毕后,调用 mQueuedListener.flush() 将所有暂存的输入事件一次性地交付给 InputDispatcher。
frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
// 刷新配置
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// 计算当前距离下次超时的时间差
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
// 1.获取原始输入事件。当 EventHub 中无事件可以读取时,此函数调用将会阻塞直到事件到来或者超时。
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
// 2.处理事件
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
// 获取输入设备
getInputDevicesLocked(inputDevices);
}
} // release lock
// 发送一条消息,描述已更改的输入设备。
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// 3.将排队的事件刷新给 listener。
// 这必须在锁之外发生,因为 listener 可能会回调到 InputReader 的方法(如 getScanCodeState),
// 或者被另一个线程阻塞,类似地等待获取 InputReader 锁,从而导致死锁。
// 这种情况实际上是很合理的,因为 listener 实际上是 InputDispatcher,
// 它调用窗口管理器,而窗口管理器偶尔调用 InputReader。
mQueuedListener->flush();
}
先分析 1.获取原始输入事件。
getEvents() 函数使用 Epoll 机制的核心是 mPendingEventItems 数组,它是一个事件池。getEvents() 函数会优先从这个事件池获取 Epoll 事件进行处理,并将读取相应的原始输入事件返回给调用者。当因为事件池枯竭而导致调用者无法获得任何事件时,会调用 epoll_wait() 函数等待新事件的到来,将事件池重新注满,然后再重新处理事件池中的 Epoll 事件。从这个意义来说,getEvents() 函数的调用过程,就是消费 epoll_wait() 所产生的 Epoll 事件的过程。因此可以从 epoll_wait() 的调用开始,到 Epoll 事件消费完毕的过程称为 EventHub 的一个监听周期。依据每次 epoll_wait() 产生的 Epoll 事件的数量以及设备节点中原始输入事件的数量,一个监听周期包含一次或多次 getEvents() 调用。周期中的第一次调用会因为事件池枯竭而直接进入 epoll_wait(),而周期中的最后一次调用一定会将最后的事件取走。
getEvents() 采用事件池机制的根本原因是 buffer 的容量限制。由于一次 epoll_wait() 可能返回多个设备节点的可读事件,每个设备节点又有可能读取多条原始输入事件,一段时间内原始输入事件的数量可能大于 buffer 的容量。因此需要一个事件池以缓存因 buffer 容量不够而无法处理的 Epoll 事件,以便在下次调用时可以将这些事件优先处理。
当有 INotify 事件可以从 mINotifyFd 中读取时,会产生一个 Epoll 事件,EventHub 便得知设备节点发生了增删操作。在 getEvents() 将事件池中的所有事件处理完毕后,便会从 mINotifyFd 中读取 INotify 事件,进行输入设备的加载/卸载操作,然后生成对应的 RawEvent 结构体并返回给调用者。
在一个监听周期内的设备增删事件与 Epoll 事件的优先级,设备事件的生成逻辑位于 Epoll 事件的处理之前,因此 getEvents() 将优先生成设备增删事件,完成所有设备增删事件的生成之前不会处理 Epoll 事件。getEvents() 包含了原始输入事件读取、输入设备加载/卸载等操作。这几乎是 EventHub 的全部工作了。
frameworks/native/services/inputflinger/EventHub.cpp
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);
// 需要时重新打开输入设备
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
ALOGI("Reopening all input devices due to a configuration change.");
// 关闭所有设备
closeAllDevicesLocked();
mNeedToScanDevices = true;
break; // 在重新扫描之前返回给调用者
}
// 报告最近添加/删除的设备。
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;
}
}
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
// 扫描设备
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
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;
}
}
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
if (--capacity == 0) {
break;
}
}
// 获取下一个输入事件。
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;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
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));
} else {
ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
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)) {
// 设备在 INotify 注意到之前就被移除。
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];
ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
// 某些输入设备可能比实际仅在输入 evdev 时为所有事件加时间戳的内核更好地定义了实际生成输入事件的时间。
// 这是输入协议的自定义 Android 扩展,主要用于基于 uinput 的设备驱动程序。
if (iev.type == EV_MSC) {
if (iev.code == MSC_ANDROID_TIME_SEC) {
device->timestampOverrideSec = iev.value;
continue;
} else if (iev.code == MSC_ANDROID_TIME_USEC) {
device->timestampOverrideUsec = iev.value;
continue;
}
}
if (device->timestampOverrideSec || device->timestampOverrideUsec) {
iev.time.tv_sec = device->timestampOverrideSec;
iev.time.tv_usec = device->timestampOverrideUsec;
if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
device->timestampOverrideSec = 0;
device->timestampOverrideUsec = 0;
}
ALOGV("applied override time %d.%06d",
int(iev.time.tv_sec), int(iev.time.tv_usec));
}
// 使用事件中指定的时间而不是当前时间,以便从事件入队到evdev客户端缓冲区开始,
// 下游代码可以获得事件分发延迟的更准确估计。
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ nsecs_t(iev.time.tv_usec) * 1000LL;
ALOGV("event time %" PRId64 ", now %" PRId64, event->when, now);
// Bug 7291243:添加一个保护,以防内核生成的时间戳看起来很遥远,因为它们是使用错误的时钟源生成的。
if (event->when >= now + 10 * 1000000000LL) {
// 再检查一遍,时间可能已经过去了。
nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
if (event->when > time) {
ALOGW("An input event from %s has a timestamp that appears to "
"have been generated using the wrong clock source "
"(expected CLOCK_MONOTONIC): "
"event time %" PRId64 ", current time %" PRId64
", call time %" PRId64 ". "
"Using current time instead.",
device->path.string(), event->when, time, now);
event->when = time;
} else {
ALOGV("Event time is ok but failed the fast path and required "
"an extra call to systemTime: "
"event time %" PRId64 ", current time %" PRId64
", call time %" PRId64 ".",
event->when, time, now);
}
}
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
// 结果缓冲区已满。 重置待处理的事件索引,以便我们在下一次迭代时尝试再次读取设备。
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() 将修改设备列表,因此必须在处理所有其他事件之后执行此操作,
// 以确保在关闭设备之前读取所有剩余事件。
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// 报告立即添加或删除设备。
if (deviceChanged) {
continue;
}
// 如果我们收集了任何事件或被明确唤醒,请立即返回。
if (event != buffer || awoken) {
break;
}
// Poll 事件。
// 我们在除 epoll_wait() 期间之外的所有时间都保持唤醒锁。
// 这是由于一些微妙的编排。当设备驱动程序发生挂起(未读)事件时,它会获得一个内核唤醒锁。
// 然而,一旦最后一个挂起事件被读取,设备驱动程序将释放内核唤醒锁。
// 为了防止这种情况发生时系统进入睡眠状态,
// EventHub 在客户端处理事件时保持自己的用户唤醒锁。
// 因此,只有在没有挂起的事件或当前正在处理的事件时,系统才能休眠。
// 超时仅为建议。如果设备处于睡眠状态,它将不会只为服务超时而唤醒。
mPendingEventIndex = 0;
mLock.unlock(); // poll 之前释放锁,必须在 release_wake_lock 之前
release_wake_lock(WAKE_LOCK_ID);
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mLock.lock(); // poll 后重新获取锁定,必须在 acquire_wake_lock 之后
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// 发生错误。
mPendingEventCount = 0;
// 错误后进入睡眠状态,以避免锁定系统。希望该错误是暂时的。
if (errno != EINTR) {
ALOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// 发生了一些事件。
mPendingEventCount = size_t(pollResult);
}
}
// 完成所有操作后,返回读取的事件数。
return event - buffer;
}
再来分析 2.处理事件。
处理事件是在 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;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %d Count: %d", batchSize, count);
#endif
// 1.处理设备原始输入事件
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
// 2.处理设备添加事件
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
// 3.处理设备移除事件
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
// 4.处理扫描结束事件,所有添加/删除设备从最近的扫描已报告
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
1.处理设备原始输入事件。
使用 deviceId 在 mDevices(KeyedVector
接着使用 deviceIndex 获取 InputDevice,如果此设备标记为忽略,这些事件也被丢弃。
不满足以上两种情况,则事件进一步处理,这是调用 InputDevice 对象的 process 实现的。
frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
按每个映射器的顺序处理所有事件。这些映射器是在 InputReader 对象 createDeviceLocked 方法中被添加的。而 createDeviceLocked 方法是在 addDeviceLocked 方法中调用的,在 processEventsLocked 函数中处理设备添加事件时会调用 addDeviceLocked 方法。
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) {
......
} 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);
}
}
}
}
下面我们以键盘按键事件处理为例来分析。按下按键会生成按下事件和同步事件,抬起按键的时候会生成抬起事件和同步事件。EV_KEY 就表示按下或抬起事件,具体可以通过 RawEvent 结构体的 value 做判断,value 为 0 即抬起,1 为按下。
按下和抬起事件类型为 EV_KEY,EV_SYN 表示同步事件。
Linux 中输入设备的事件类型有:
EV_SYN 0x00 同步事件
EV_KEY 0x01 按键事件
EV_REL 0x02 相对坐标, 如鼠标移动,报告相对最后一次位置的偏移
EV_ABS 0x03 绝对坐标,如触摸屏或操作杆,报告绝对的坐标位置
EV_MSC 0x04 其它
EV_SW 0x05 开关
EV_LED 0x11 LED
EV_SND 0x12 声音
EV_REP 0x14 重复
EV_FF 0x15 力反馈
EV_PWR 0x16 电源
EV_FF_STATUS 0x17 状态
处理按键按下与抬起事件时,先判断是否属于键盘或游戏手柄按钮键值,接着调用 processKey 进一步处理。
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)) {
processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
}
break;
}
case EV_MSC: {
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: {
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
processKey 函数处理流程:
frameworks/native/services/inputflinger/InputReader.cpp
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
// 1.mapKey 获得 keyCode 等
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
&keyCode, &keyMetaState, &policyFlags)) {
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
if (down) {
......
// 添加按键按下
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
......
} else {
// 按键按下,第一次按下进入此分支,向 mKeyDowns 中添加一个 KeyDown 对象,
// 此对象包括了按键扫描码和键码
......
mKeyDowns.push();
KeyDown& keyDown = mKeyDowns.editTop();
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
}
mDownTime = when;
} else {
// 按键抬起,从按键按下 mKeyDowns Vector 中删除对应项
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;
}
}
......
nsecs_t downTime = mDownTime;
// 按下外部键盘将设备唤醒。
// 我们不对内置键盘执行此操作,以防止它们从口袋里醒来。
// 对于内部键盘,键布局文件应分别为每个唤醒键指定策略标志。
if (down && getDevice()->isExternal()) {
policyFlags |= POLICY_FLAG_WAKE;
}
......
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
// 2.将 NotifyKeyArgs 添加到 QueuedInputListener 内部 mArgsQueue 中
getListener()->notifyKey(&args);
}
1.mapKey 获得 keyCode 等
(1) 首先检查 KeyCharacterMap
(2) KeyCharacterMap 不存在的情况下,检查 KeyLayoutMap
frameworks/native/services/inputflinger/EventHub.cpp
status_t EventHub::mapKey(int32_t deviceId,
int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
AutoMutex _l(mLock);
// 通过 deviceId 查找 Device
Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
if (device) {
// 1.首先检查 KeyCharacterMap
sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
if (kcm != NULL) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0;
status = NO_ERROR;
}
}
// 2.检查 keyLayoutMap
if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
if (!device->keyMap.keyLayoutMap->mapKey(
scanCode, usageCode, outKeycode, outFlags)) {
status = NO_ERROR;
}
}
if (status == NO_ERROR) {
if (kcm != NULL) {
kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
} else {
*outMetaState = metaState;
}
}
}
if (status != NO_ERROR) {
*outKeycode = 0;
*outFlags = 0;
*outMetaState = metaState;
}
return status;
}
getKeyCharacterMap 先判断 combinedKeyMap 是否为空,不为空直接返回;否则返回 keyMap.keyCharacterMap。
frameworks/native/services/inputflinger/EventHub.h
class EventHub : public EventHubInterface
{
......
private:
struct Device {
......
KeyMap keyMap;
sp<KeyCharacterMap> overlayKeyMap;
sp<KeyCharacterMap> combinedKeyMap;
......
const sp<KeyCharacterMap>& getKeyCharacterMap() const {
if (combinedKeyMap != NULL) {
return combinedKeyMap;
}
return keyMap.keyCharacterMap;
}
};
......
};
2.将 NotifyKeyArgs 添加到 QueuedInputListener 内部 mArgsQueue 中
mArgsQueue 是 Vector
frameworks/native/services/inputflinger/InputListener.cpp
NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags,
int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, nsecs_t downTime) :
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
metaState(metaState), downTime(downTime) {
}
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}
回到 processEventsLocked 2.处理设备添加事件,这是通过 addDeviceLocked 函数完成的。主要通过调用 createDeviceLocked 创建 InputDevice,并添加到 mDevices ( KeyedVector
frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
// 设备已经添加过,直接返回
if (deviceIndex >= 0) {
ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
return;
}
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
// 创建 InputDevice 对象
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
device->configure(when, &mConfig, 0);
device->reset(when);
if (device->isIgnored()) {
ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
identifier.name.string());
} else {
ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
identifier.name.string(), device->getSources());
}
// 添加 InputDevice 对象
mDevices.add(deviceId, device);
......
}
接下来分析 createDeviceLocked 都做了什么?
InputDevice::process 函数中按每个映射器的顺序处理所有事件,这些映射器就是在这里添加的。
frameworks/native/services/inputflinger/InputReader.cpp
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
controllerNumber, identifier, classes);
// 外部设备
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
device->setExternal(true);
}
// 带有麦克风的设备。
if (classes & INPUT_DEVICE_CLASS_MIC) {
device->setMic(true);
}
// 类似开关的设备。
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
// 添加对应的 Mapper
device->addMapper(new SwitchInputMapper(device));
}
// Vibrator-like devices.
if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
device->addMapper(new VibratorInputMapper(device));
}
// 类似键盘的设备。
uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
if (keyboardSource != 0) {
// 这里添加了 KeyboardInputMapper
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
// 类似光标的设备。
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
device->addMapper(new CursorInputMapper(device));
}
// 触摸屏和触摸板设备。
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
device->addMapper(new SingleTouchInputMapper(device));
}
// 类似操纵杆的设备。
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
device->addMapper(new JoystickInputMapper(device));
}
// 外部笔式设备。
if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
device->addMapper(new ExternalStylusInputMapper(device));
}
return device;
}
继续回到 processEventsLocked 3.处理设备移除事件,这是通过 removeDeviceLocked 函数完成的。这个函数非常简单首先从 mDevices 中移除对应项,然后调用 delete 释放对应的 InputDevice 对象。
frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
InputDevice* device = NULL;
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
return;
}
device = mDevices.valueAt(deviceIndex);
mDevices.removeItemsAt(deviceIndex, 1);
......
device->reset(when);
delete device;
}
最后回到 processEventsLocked 4.处理扫描结束事件,所有添加/删除设备从最近的扫描已报告,这是调用 handleConfigurationChangedLocked 完成的。
frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
// 重置全局元状态,因为它取决于所有已配置设备的列表。
updateGlobalMetaStateLocked();
// 入队已更改的配置。
NotifyConfigurationChangedArgs args(when);
mQueuedListener->notifyConfigurationChanged(&args);
}
类似将 NotifyConfigurationChangedArgs 添加到 QueuedInputListener 内部 mArgsQueue 中。
mArgsQueue 是 Vector
frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::notifyConfigurationChanged(
const NotifyConfigurationChangedArgs* args) {
mArgsQueue.push(new NotifyConfigurationChangedArgs(*args));
}
现在是时候回到 loopOnce() 函数继续分析 3.将排队的事件刷新给 listener。这调用了 mQueuedListener 的 flush() 方法。遍历 mArgsQueue ,然后逐个元素调用 notify 方法。
frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
接下来我们以调用 NotifyKeyArgs 对象 notify 方法继续分析。内部其实调用了 InputListenerInterface 对象的 notifyKey 方法,传入的实参是 NotifyKeyArgs 对象自身。
frameworks/native/services/inputflinger/InputListener.cpp
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
mInnerListener 对象是在构建 QueuedInputListener 对象时赋值的。如果你还有一些记忆,会想起来 《Android 源码 InputManagerService 初始化》 一节中 InputReader 构造函数中构造了 QueuedInputListener 对象。
frameworks/native/services/inputflinger/InputListener.cpp
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}
下面是 InputReader 构造函数中构造 QueuedInputListener 对象的代码。
frameworks/native/services/inputflinger/InputReader.cpp
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
......
}
InputReader 是在 InputManager 构造函数中创建的。可以看到在构造 InputReader 对象时,传入的实参是 InputDispatcher 对象 mDispatcher。这说明 InputDispatcher 继承了 InputListenerInterface 类。
frameworks/native/services/inputflinger/InputManager.cpp
namespace android {
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
// 创建 InputDispatcher 对象
mDispatcher = new InputDispatcher(dispatcherPolicy);
// 创建 InputReader 对象
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
......
}
......
} // namespace android
接着验证我们上面的猜测,然后继续分析 InputListenerInterface 对象的 notifyKey 方法。
InputDispatcher 类并没有直接继承 InputListenerInterface 类,而是继承了 InputDispatcherInterface 类。
frameworks/native/services/inputflinger/InputDispatcher.h
class InputDispatcher : public InputDispatcherInterface {
......
}
这说明 InputDispatcherInterface 类一定继承了 InputListenerInterface 类。
frameworks/native/services/inputflinger/InputDispatcher.h
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {
......
}
现在可以继续分析 InputListenerInterface 对象的 notifyKey 方法了。其目的实际上是把事件队列加入 mInboundQueue,但是在插入 mInboundQueue 队列尾部之前,调用了interceptKeyBeforeQueueing,该函数通过 jni 调用到 PhoneWindowManager 的 interceptKeyBeforeQueueing,比如 power 键就是在 interceptKeyBeforeQueueing 中处理的。插入 mInboundQueue 队列尾部成功后,就会调用 Looper wake 函数去唤醒 InputDispatcherThread。
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
......
// 验证按键事件是否有效
if (!validateKeyEvent(args->action)) {
return;
}
......
// 创建 KeyEvent 对象
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
// 在排队之前,先拦截触摸,轨迹球或其他运动事件。
// 策略可以将此方法用作执行电源管理功能和早期事件预处理(例如更新策略标志)的机会。
// 如果应将事件分派给应用程序,则此方法应设置POLICY_FLAG_PASS_TO_USER策略标志。
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
bool needWake;
{ // acquire lock
mLock.lock();
......
int32_t repeatCount = 0;
// 创建 KeyEntry 对象
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
// 将 KeyEntry 对象添加到 mInboundQueue 队列尾部
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
// 是否唤醒
if (needWake) {
mLooper->wake();
}
}
走到这里 InputReader 分析就算结束了,接下来需要分析 InputDispatcher 如何管理其队列里的事件,然后进行相应的派发。下面总结以上流程的时序图。