在之前,整理了输入系统服务InputManagerService(服务的生成、启动),EventHub(读取原始输入事件、设备增删)。接着来了解一下InputReader,InputReader主要工作是从EventHub读取事件、进行加工、将加工好的事件发送到InputDispatcher。
由InputManagerService这篇博客中,可知InputManagerService初始化的时候,一层层调用,最终在InputManager中初始化InputReader和InputReaderThread。
先看下InputReader的构造函数
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); { // acquire lock AutoMutex _l(mLock); refreshConfigurationLocked(0); updateGlobalMetaStateLocked(); } // release lock }初始化必要的变量,mEventHub对应EventHub对象,mPolicy对应NativeInputManager对象,mGlobalMetaState表示控制键的状态,mGeneration表示输入设备的状态,mQueuedListener用来将加工后的按键事件传到InputDispatcher。
InputManagerService的start() 层层调用 最后调用到 InputManager的start()中。
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
InputReaderThread开始运行,以下是InputReaderThread的线程循环,返回true则循环不断的调用threadLoop()方法,返回false则退出循环。
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
该线程中会循环不断的执行mReader->loopOnce();看一下loopOnce中具体干了些什么。
void InputReader::loopOnce() { int32_t oldGeneration; int32_t timeoutMillis; bool inputDevicesChanged = false; Vector<InputDeviceInfo> inputDevices; { // acquire lock AutoMutex _l(mLock); oldGeneration = mGeneration; timeoutMillis = -1; //查看InputReader配置是否修改,如界面大小、方向、键盘布局重新加载、指针速度改变等 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 //获取输入事件、设备增删事件,count为事件数量。 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 // 发送一个消息,该消息描述已更改的输入设备。 if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } mQueuedListener->flush(); //将事件传到InputDispatcher. }
接着判断count的值,如果有读到事件(count大于0),则调用processEventsLocked(mEventBuffer, count)处理事件。
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; } processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; //count减少已处理事件个数,表示剩余事件个数 rawEvent += batchSize; //rawEvent指针向后移动batchSize个RawEvent对象,也就是指到该处理的事件上。 } }
processEventsLocked()函数中会遍历所有的事件,分别进行处理。其处理的事件类型分为四种:原始输入事件、设备加载事件、设备卸载事件及FINISHED_DEVICE_SCAN事件。
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { // 通过设备id(deviceId)获取mDevices中该设备下标,从而判断是否包含该设备。 ssize_t deviceIndex = mDevices.indexOfKey(deviceId); //查看mDevices是否包含该设备,-2表示没有包含, 大于等于0表示包含。 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); //创建设备inputDevice。 InputDevice* device = createDeviceLocked(deviceId, 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()); } //将设备添加到mDevices字典中。 mDevices.add(deviceId, device); bumpGenerationLocked(); }
addDeviceLocked()函数中主要通过设备厂商信息、类型来创建InputDevice,配置InputDevice,并将device添加到mDevices中。其中createDeviceLocked()函数用来创建InputDevice对象,并根据设备类别设置不同的mapper,如(INPUT_DEVICE_CLASS_SWITCH对应SwitchInputMapper)。Mapper用来处理输入事件(这个稍后再说)。
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);//从mDevices移除对应的设备 bumpGenerationLocked(); if (device->isIgnored()) { ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), device->getName().string()); } else { ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), device->getName().string(), device->getSources()); } device->reset(when);//设备重置 delete device; //释放。 }
设备卸载事件很简单,将其从mDevices中移除该设备。
void InputReader::handleConfigurationChangedLocked(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaStateLocked(); // 将事件封装成NotifyConfigurationChangedArgs对象 NotifyConfigurationChangedArgs args(when); //将该对象放到mQueuedListener队列中。mQueuedListener->flush()时传到InputDispstcher线程 mQueuedListener->notifyConfigurationChanged(&args); }
在设备加载事件或设备卸载事件后会跟着FINISHED_DEVICE_SCAN,用来表示设备加载事件或设备卸载事件已完毕。
type < EventHubInterface::FIRST_SYNTHETIC_EVENT,当满足该条件时表示原始输入事件,对同一设备的原始输入事件调用processEventsForDeviceLocked()函数进行处理。
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { //通过设备id获取mDevices中存储的下标 ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { //没有对应设备 ALOGW("Discarding event for unknown deviceId %d.", deviceId); return; } //通过下标从mDevices取出对应的设备。 InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) { //ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; } //设备处理事件 device->process(rawEvents, count); }
void InputDevice::process(const RawEvent* rawEvents, size_t count) { size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { if (mDropUntilNextSync) { ...... } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } } } }
之前createDeviceLocked()函数创建InputDevice的时候,会对InputDevice对象调用addMapper,添加到字典mMappers(一个InputDevice可能有一个或多个mapper,主要取决与设备类型)。InputDevice不知道、也不管哪个InputMapper可以处理这些事件,只需要让所有的InputMapper都去加工这些事件,InputMapper中会对事件进行判断是否是自己该处理的事件,如果不是则什么都不做,如果是则进行相应处理。
InputMapper有多个子类:SwitchInputMapper、VibratorInputMapper、KeyboardInputMapper、CursorInputMapper、MultiTouchInputMapper、SingleTouchInputMapper、JoystickInputMapper等。
这里只说一下KeyboardInputMapper。
void KeyboardInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { //事件类型:按键类型 int32_t scanCode = rawEvent->code; int32_t usageCode = mCurrentHidUsage; mCurrentHidUsage = 0; //排除鼠标按键,鼠标按键由CursorInputMapper处理。 if (isKeyboardOrGamepadKey(scanCode)) { int32_t keyCode; uint32_t flags; //通过EventHub调用mapKey()函数,将扫描码映射出键值。scanCode为扫描码,keyCode用来存键值。 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; } } } }
如何映射呢?
EventHub创建设备、加载设备时调用openDeviceLocked函数,其中如何设备类型为INPUT_DEVICE_CLASS_KEYBOARD或INPUT_DEVICE_CLASS_JOYSTICK时,会调用EventHub::loadKeyMapLocked函数为此设备加载配置文件,键盘配置文件路径/system/usr/input/或/system/usr/keylayout,不同设备可能会稍有差别。该目录下的文件后缀都是.kl,其中一个处理实体按键的文件内容如下:
key 116 POWER WAKE
key 102 HOME WAKE
key 158 BACK WAKE
key 212 CAMERA WAKE
key 114 VOLUME_DOWN
key 30 A
。。。。
第一列关键字key,第二列表示扫描码,第三列表示虚拟键值的名称,第四列表示此按键的功能。
frameworks/base/include/androidfw/KeycodeLabels.h中数组存储着个虚拟键名和键值。
loadKeyMapLocked函数将虚拟键值的名转换为键值存在结构体中,以扫描码为键。通过mapKey()函数可以获取到扫描码对应的键值和flag。
电源键扫描码为116,键值为26,flags为1。
接着看processKey()函数对事件进行加工
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) { //按键 按下 if (down) { // 根据屏幕方向,转换键值 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { keyCode = rotateKeyCode(keyCode, mOrientation); } //KeyboardInputMapper中的mKeyDown结集合用来存储KeyDown结构体,记录按下的键。 ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { //表示该扫描码之前被按下,也就是现在是重复按下。 //确保多次按下键值一致。 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; } else { // POLICY_FLAG_VIRTUAL 不做处理 if ((policyFlags & POLICY_FLAG_VIRTUAL) && mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) { return; } //通过扫描码和键值生成keyDown对象,添加到mKeyDowns集合中。 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) { // mKeyDowns移除抬起的键 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; mKeyDowns.removeAt(size_t(keyDownIndex)); } else { //如果按键没有被按下就只被抬起,则事件忽略不处理。 return; } } bool metaStateChanged = false; //控制键的状态、控制键包括alt、shift、ctrl、meta、NumLock、ScrollLock、CapsLock等。 int32_t oldMetaState = mMetaState; //检查是否是控制键,并返回控制键状态。 int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState); if (oldMetaState != newMetaState) {//与之前状态对比,判断控制键状态是否更改 mMetaState = newMetaState; metaStateChanged = true; updateLedState(false); } nsecs_t downTime = mDownTime; if (down && getDevice()->isExternal() && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) { policyFlags |= POLICY_FLAG_WAKE_DROPPED; } if (metaStateChanged) {//更新控制状态 getContext()->updateGlobalMetaState(); } if (down && !isMetaKey(keyCode)) { getContext()->fadePointer(); } //按键信息封装到NotifyKeyArgs对象中。 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); }
。还有控制键状态的更新。最后将按键事件封装在NotifyKeyArgs对象中。之后就是向InputDispatcher中发送。
getListener() -> InputListenerInterface* InputReader::ContextImpl::getListener() 该函数返回的对象是InputReader构造函数中的mQueuedListener,调用其notifyKey()函数并不会马上发送到InputDispatcher中,而是在InputReader::loopOnce()中调用mQueuedListener->flush(),这才会将这次所有已加工的事件发送到InputDispatcher中。
除了NotifyKeyArgs按键类型事件,还有其他mapper加工封装的事件,其对应的提交方法如下:
NotifyKeyArgs封装按键类型事件 notifyKey
NotifySwitchArgs封装开关类型事件 notifySwitch
NotifyMotionArgs封装手势类型事件 notifyMotion
InputMapper有多个子类,用来处理不同设备,具体分析过程类似。