在之前,整理了输入系统服务InputManagerService(服务的生成、启动),EventHub(读取原始输入事件、设备增删)。接着来了解一下InputReader,InputReader主要工作是从EventHub读取事件、进行加工、将加工好的事件发送到InputDispatcher。
由InputManagerService这篇博客中,可知InputManagerService初始化的时候,一层层调用,最终在InputManager中初始化InputReader和InputReaderThread。
先看下InputReader的构造函数
InputReader::InputReader(const sp& eventHub,
const sp& policy,
const sp& 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 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有多个子类,用来处理不同设备,具体分析过程类似。