上一篇文章分析了Input系统的启动之后会通过INotify与Epoll监听dev/input/
目录下文件的创建和删除,并且启动两个线程InputReader
和InputDispatcher
,InputReader
启动之后调用其loopOnce()
函数,InputDispatcher
启动之后调用其dispatchOnce
函数,它们都是死循环的调用,这篇文章就先来看看InputReader
的loopOnce()
函数:
loopOnce
//InputReader.cpp
void InputReader::loopOnce() {
//(1)
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::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
//(2)
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
//(3)
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
//(4)
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}
这个函数比较复杂,我们分为四部分来依次分析,首先来看第一部分(1):
void InputReader::loopOnce() {
//(1)
int32_t oldGeneration;
int32_t timeoutMillis;
//dev/input目录下的设备节点是否发生变化,增加或删除
bool inputDevicesChanged = false;
//InputDeviceInfo描述了dev/input目录下的设备节点信息,inputDevices为
//InputDeviceInfo集合
std::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
...
//(2)
...
//(3)
...
//(4)
...
}
第一部分首先定义了一些变量,inputDevicesChanged
用来描述dev/input目录下的设备节点是否发生变化(增加或删除),通过adb shell getevent查看dev/input目录下的设备节点:
比如我自己的手机有7个设备节点,每一个设备节点都对应了一张kl(key layout)表,如果外接一个键盘或游戏手柄就可能会增加设备节点,这时inputDevicesChanged
就会发生变化,变量inputDevices
代表一个InputDeviceInfo
的集合,InputDeviceInfo
描述了dev/input目录这些输入设备节点的特性和功能(例如设备ID,kl表名称),变量mGeneration
会在dev/input设备节点增加或删除时发生变化,变量mConfigurationChangesToRefresh
描述了一些input配置信息的变化,由函数requestRefreshConfiguration
进行修改,
void InputReader::requestRefreshConfiguration(uint32_t changes) {
AutoMutex _l(mLock);
if (changes) {
bool needWake = !mConfigurationChangesToRefresh;
mConfigurationChangesToRefresh |= changes;
if (needWake) {
mEventHub->wake();
}
}
}
参数changes
可以是以下枚举值
struct InputReaderConfiguration {
// Describes changes that have occurred.
enum {
// The pointer speed changed.
CHANGE_POINTER_SPEED = 1 << 0,
// The pointer gesture control changed.
CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1,
// The display size or orientation changed.
CHANGE_DISPLAY_INFO = 1 << 2,
// The visible touches option changed.
CHANGE_SHOW_TOUCHES = 1 << 3,
// The keyboard layouts must be reloaded.
CHANGE_KEYBOARD_LAYOUTS = 1 << 4,
// The device name alias supplied by the may have changed for some devices.
CHANGE_DEVICE_ALIAS = 1 << 5,
// The location calibration matrix changed.
CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
// The presence of an external stylus has changed.
CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,
// The pointer capture mode has changed.
CHANGE_POINTER_CAPTURE = 1 << 8,
// The set of disabled input devices (disabledDevices) has changed.
CHANGE_ENABLED_STATE = 1 << 9,
// All devices must be reopened.
CHANGE_MUST_REOPEN = 1 << 31,
};
什么情况下Input的配置信息会发生变化呢?比如我们在手机开发者选项中开关"显示按键反馈"就对应CHANGE_SHOW_TOUCHES
的设置,其他的值我没测试过也不太清楚怎么操作,但从注释也能直观感受,比如CHANGE_POINTER_SPEED
修改指针速度,CHANGE_DISPLAY_INFO
屏幕大小或方法变化,CHANGE_KEYBOARD_LAYOUTS
键盘重布局等,待以后有空来测试一下这些值然后再修改文章…
当Input配置信息改变之后则调用refreshConfigurationLocked
进行更新,refreshConfigurationLocked
这部分细节不是我们分析重点,就不细看了。
接着来分析loopOnce
第二部分:
void InputReader::loopOnce() {
//(1)
...
//(2)
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
...
//(3)
...
//(4)
...
}
这部分就是InputReader
的核心,从EventHub读取事件,参数mEventBuffer
是一个存储RawEvent
的数组,大小为EVENT_BUFFER_SIZE
(256):
//InputReader.h
// The event queue.
static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
RawEvent
描述了一个输入事件的原始事件结构体,
/*
* A raw event as retrieved from the EventHub.
*/
//EventHub.h
struct RawEvent {
nsecs_t when; //事件发生的事件
int32_t deviceId; //事件发生的设备节点ID
int32_t type; //事件的类型
int32_t code; //扫描码scancode
int32_t value;
};
EventHub->getEvents
继续来看EventHub
的getEvents
函数:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
....
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;
//关闭所有设备
closeAllDevicesLocked();
mNeedToScanDevices = true;
break; // return to the caller before we actually rescan
}
// 是否删除所有设备
while (mClosingDevices) {
Device* device = mClosingDevices;
mClosingDevices = device->next;
event->when = now;
event->deviceId = (device->id == mBuiltInKeyboardId)
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
: device->id;
//添加设备删除事件
event->type = DEVICE_REMOVED;
event += 1;
//删除
delete device;
mNeedToSendFinishedDeviceScan = true;
//设备数量达到256则break
if (--capacity == 0) {
break;
}
}
//是否需要扫描并打开设备,初始化为true
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
//扫描并打开设备
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
//是否正在打开的设备不为空
while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
//指向下一个打开的设备
mOpeningDevices = device->next;
//当前时间
event->when = now;
//设备节点ID
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;
}
}
// Grab the next input event.
bool deviceChanged = false;
//mPendingEventCount描述了从dev/input目录下各个设备节点发生的事件个数,
//初始化为0,
//mPendingEventIndex 描述了正在处理的事件下标,初始化为0
//这个while循环作用就是依次处理dev/input目录下各个设备节点
//发生的所有事件,首次到这里时因为没有任何事件,则为fasle
while (mPendingEventIndex < mPendingEventCount) {
//mPendingEventItems是一个epoll_event类型数组,size为16,
//epoll_event是用来描述通过epoll_wait监听到的内核事件,
//这里的事件也就是监听mINotifyFd和mWakeReadPipeFd获取到的
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//是否是监听mINotifyFd获取到的事件
if (eventItem.data.fd == mINotifyFd) {
//是否可以读取事件
if (eventItem.events & EPOLLIN) {
//设置mPendingINotify为true,后面处理
mPendingINotify = true;
} else {
...
}
continue;
}
//是否是监听mWakeReadPipeFd获取到的事件
if (eventItem.data.fd == mWakeReadPipeFd) {
//从mWakeReadPipeFd读取到的事件不是我们分析重点,省略
.......
}
//根据fd类型获取对应设备,可以是输入设备或者视频设备(不太清楚视频设备相关)
//Device是用来描述dev/input目录下设备节点信息的结构体
Device* device = getDeviceByFdLocked(eventItem.data.fd);
if (!device) {
...
continue;
}
//是否是视频设备
if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
//不是重点,省略
....
continue;
}
//可读取的input事件
if (eventItem.events & EPOLLIN) {
//通过read函数读取dev/input目录下各个设备节点发生的事件,device->fd
//的值是在打开设备时赋值的,其实就是dev/input目录下的各个设备节点
//将事件放入readBuffer数组
//readSize / sizeof(struct input_event) = 事件个数,必须为整数倍,否则
//读取异常。
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.
...
deviceChanged = true;
closeDeviceLocked(device);
//异常情况
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
}
//异常情况
} else if ((readSize % sizeof(struct input_event)) != 0) {
...
} else {//处理事件
//mBuiltInKeyboardId是一个枚举值NO_BUILT_IN_KEYBOARD,具体含义不是
//太清楚,但从dump的input信息看,一般device->id不会等于mBuiltInKeyboardId
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
//读取到的事件个数
size_t count = size_t(readSize) / sizeof(struct input_event);
//for循环分别处理每一个事件,将input_event转换为RawEvent
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
//将每一个事件都封装为原始事件RawEvent
event->when = processEventTimestamp(iev);
//事件的设备节点ID
event->deviceId = deviceId;
//事件类型
event->type = iev.type;
//事件code
event->code = iev.code;
//事件value
event->value = iev.value;
//指向下一个事件
event += 1;
//容量-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) {
deviceChanged = true;
//关闭设备
closeDeviceLocked(device);
} else {
//异常情况,发生不合法事件
device->identifier.name.c_str());
}
}
// 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.
//mPendingINotify 为true代表在mINotifyFd上读取到了dev/input目录下设备节点的
//删除或者创建,mPendingEventIndex >= mPendingEventCount代表当前这一轮input
//事件已经处理完成
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
//通知更新dev/input目录下设备节点
readNotifyLocked();
deviceChanged = true;
}
// 报告dev/input目录下设备节点发生了增加或者删除
if (deviceChanged) {
continue;
}
// 读取到事件,结束最开始的for(;;)
if (event != buffer || awoken) {
break;
}
// Poll for events.
// When a device driver has pending (unread) events, it acquires
// a kernel wake lock. Once the last pending event has been read, the device
// driver will release the kernel wake lock, but the epoll will hold the wakelock,
// since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait
// is called again for the same fd that produced the event.
// Thus the system can only sleep if there are no events pending or
// currently being processed.
//
// The timeout is advisory only. If the device is asleep, it will not wake just to
// service the timeout.
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll
//通过epoll_wait等待mEpollFd上事件发生,没有则阻塞,mEpollFd添加了mINotifyFd和
//mWakeReadPipeFd监听,实际上就是监听mINotifyFd和mWakeReadPipeFd上发生的事件,
//事件发生之后放入mPendingEventItems数组,返回值pollResult为事件的数量
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
mLock.lock(); // reacquire lock after poll
//如果pollResult 为0,说明超时了,因为不超时会一直阻塞在epoll_wait
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
//pollResult < 0,发生异常
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) {
usleep(100000);
}
} else {
//发生事件的数量
mPendingEventCount = size_t(pollResult);
}
}
//返回获取到的事件数量
return event - buffer;
}
getEvents
这个函数非常的复杂,建议先对INotify与Epoll机制有所了解再来看,可以参考AndroidR Input子系统(1)INotify与Epoll机制,大部分的注释都已经写清楚了,耐心看,一定能看明白的,整个方法逻辑很简单,主要可以分为两大部分,
- 首次进入此函数时
mNeedToScanDevices
为true,会调用scanDevicesLocked
扫描并打开设备,这个函数非常重要且复杂,下一篇文章单独分析。 - 通过
epoll_wait
等待mEpollFd
上的事件发生,mEpollFd
添加了mINotifyFd
和mWakeReadPipeFd
监听,epoll_wait
实际上就是等待mINotifyFd
和mWakeReadPipeFd
上发生事件,事件发生之后放入mPendingEventItems
数组,然后由一个while循环来处理这些事件,对于mINotifyFd
发生的事件(设备节点的增删)则调用readNotifyLocked
函数更新设备,对于input事件,则将事件封装为RawEvent
。
到此,getEvents
函数已经看完了,下一篇文章我们会单独分析其中的scanDevicesLocked
和readNotifyLocked
这两个函数。
接着我们再回到loopOnce
函数
void InputReader::loopOnce() {
//(1)
...
//(2)
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
...
//(3)
...
//(4)
...
}
mEventHub->getEvents
执行完成之后,mEventBuffer
中已经填充好了input事件,第三部分就开始处理这些事件了:
//InputReader.cpp
void InputReader::loopOnce() {
//(1)
...
//(2)
...
//(3)
if (count) {
processEventsLocked(mEventBuffer, count);
}
...
//(4)
...
}
processEventsLocked
核心函数processEventsLocked
:
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
//遍历RawEvent数组
for (const RawEvent* rawEvent = rawEvents; count;) {
//事件类型
int32_t type = rawEvent->type;
size_t batchSize = 1;
//小于FIRST_SYNTHETIC_EVENT代表除DEVICE_ADDED,DEVICE_REMOVED,
//FINISHED_DEVICE_SCAN的其他事件
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) {
//如果事件类型是DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN,
//或者不是发生在同一设备节点的事件则break
break;
}
//同一设备节点的事件数量
batchSize += 1;
}
//处理事件
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
//如果事件类型为DEVICE_ADDED
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
//如果事件类型为DEVICE_REMOVED
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
//如果事件类型为FINISHED_DEVICE_SCAN
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
事件类型:
enum {
// 设备添加
DEVICE_ADDED = 0x10000000,
// 设备移除
DEVICE_REMOVED = 0x20000000,
// 设备扫描
FINISHED_DEVICE_SCAN = 0x30000000,
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};
processEventsLocked
函数比较简单,就是根据事件的类型调不同的函数,我们先来看addDeviceLocked
函数:
void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
if (mDevices.find(eventHubId) != mDevices.end()) {
//如果要添加的设备已经存在则return
ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
return;
}
//InputDeviceIdentifier用来标识设备
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
//通过设备ID和InputDeviceIdentifier创建InputDevice
std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
device->configure(when, &mConfig, 0);
device->reset(when);
....
//将InputDevice和设备ID一一对应到mDevices这个map中
mDevices.emplace(eventHubId, device);
...
}
通过adb shell getevent可以查看InputDeviceIdentifier
的名称,每个设备节点都会对应一个InputDeviceIdentifier
,
InputReader::createDeviceLocked
接着再来看看createDeviceLocked
函数创建InputDevice
:
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
int32_t eventHubId, const InputDeviceIdentifier& identifier) {
//通过find_if判断要创建的InputDevice是否已经存在
auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&
devicePair.second->getDescriptor() == identifier.descriptor;
});
std::shared_ptr<InputDevice> device;
//已经存在
if (deviceIt != mDevices.end()) {
device = deviceIt->second;
} else {
//不存在则需要创建
int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
//构造InputDevice传入了4个参数,mContext指向InputReader
device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
identifier);
}
//将设备ID添加到InputDevice
device->addEventHubDevice(eventHubId);
return device;
}
InputDevice::addEventHubDevice
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
if (mDevices.find(eventHubId) != mDevices.end()) {
//如果已经添加过了直接return
return;
}
//创建InputDeviceContext,这个类主要提供一些访问EventHub的函数
std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
uint32_t classes = contextPtr->getDeviceClasses();
//mappers是一个InputMapper类型的集合,
//InputMapper是原始事件加工的类,不同类型事件对应不同InputMapper,
//这里的类型有键盘,鼠标,触摸屏等,都是InputMapper子类
std::vector<std::unique_ptr<InputMapper>> mappers;
//populateMappers默认值为true
if (!populateMappers) {
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
return;
}
// 开关类型InputMapper
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
}
// 滑动类型InputMapper
if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
}
//震动类型InputMapper
if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
}
// Keyboard-like devices.
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;
}
//键盘类型InputMapper
if (keyboardSource != 0) {
mappers.push_back(
std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
}
//鼠标类型InputMapper
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
}
//触摸屏类型InputMapper
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));
}
// 操纵杆类型InputMapper
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
}
// 外部触控笔类型InputMapper
if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
}
// mDevices是一个map,提供了eventHubId,contextPtr,InputMapper集合的一一映射,
//即一个eventHubId对应一个InputDeviceContext对应一个InputMapper集合
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}
createDeviceLocked
和addEventHubDevice
函数主要功能就是创建了InputDevice
,每一个eventHubId
对应一个InputDevice
,并将InputReader
的mContext
传给了InputDevice
,然后创建InputDeviceContext
,此类提供一系列访问EventHub
的函数,接着根据eventHubId
,获取设备类型,根据设备类型创建不同的InputMapper
,用于处理该设备的原始事件,每个InputMapper
构造函数中都接收一个contextPtr
用于访问EventHub
,最后再InputDevice
的mDevices
成员变量中提供eventHubId,contextPtr,mappers
的一一映射。
再回到前面的addDeviceLocked
函数, InputDevice
创建完成之后便以eventHubId
为key,InputDevice
为value存入InputReader
的mDevices
中。
到此addDeviceLocked
这个函数就已经分析完了,我们已经大致清楚了当RawEvent
的事件类型为DEVICE_ADDED
时系统所作的事情,主要就两个,1.创建InputDevice
,2.创建对应设备类型的InputMapper
用于处理事件。
对于事件类型DEVICE_REMOVED
和FINISHED_DEVICE_SCAN
我们就不去分析了,本篇重点还是Input事件的处理,接着来看看对于除DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN
的其他事件处理processEventsForDeviceLocked
:
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
size_t count) {
auto deviceIt = mDevices.find(eventHubId);
if (deviceIt == mDevices.end()) {
ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
return;
}
std::shared_ptr<InputDevice>& device = deviceIt->second;
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
这个函数就很简单了,根据eventHubId
,找到对应的InputDevice
,然后调用其process
函数处理对应设备节点发生的输入事件。
InputDevice::process
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
//遍历原始事件
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
} else {
...
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
mapper.process(rawEvent);
});
}
--count;
}
}
这个函数会遍历所有原始事件,依次进行处理,首先会对事件进行过滤,根据RawEvent
的type和code决定如何处理,这个type和code是什么?
我们可以通过命令adb shell getevent -l进行查看,比如我点了一下power键亮屏就会有如下输出:
EV_KEY
这一列就是type,KEY_POWER
这一列就是code,DOWN
这一列就是value,具体的含义可以查阅Linux 驱动输入子系统相关资料,我们继续看else分支的处理:
// run a function against every mapper on a specific subdevice
inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
std::function<void(InputMapper&)> f) {
auto deviceIt = mDevices.find(eventHubDevice);
if (deviceIt != mDevices.end()) {
auto& devicePair = deviceIt->second;
auto& mappers = devicePair.second;
for (auto& mapperPtr : mappers) {
f(*mapperPtr);
}
}
}
这个函数我们首先看mDevices
这个变量,
/*
using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;
std::unordered_map<int32_t, DevicePair> mDevices;
*/
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
......
// insert the context into the devices set
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}
我们在前面分析addEventHubDevice
函数时已经知道了,mDevices
是一个map,提供了eventHubId,contextPtr,InputMapper集合的一一映射(其中contextPtr,InputMapper被封装成了DevicePair
,用作mDevices
的value),忘了的可以回过头去看看,所以for_each_mapper_in_subdevice
函数里的逻辑就是根据eventHubId
,找到DevicePair
,再从DevicePair
中获取InputMapper集合,最后遍历mappers
,并调用InputMapper
的process
函数处理具体事件,InputMapper
的种类有很多,键盘类型,鼠标类型,触摸类型等等,一个设备节点可能产生不同类型的事件,就需要不同的InputMapper
处理,到此我们已经知道了原始事件最终其实是交给不同的InputMapper
来处理的,所以InputMapper
就是原始事件的加工厂。
我们接着以KeyboardInputMapper
为例继续分析事件的处理:
KeyboardInputMapper::process
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;
}
}
}
}
这里把KeyboardInputMapper
处理的事件分成了三类,EV_KEY
按键事件,EV_MSC
其他事件,EV_SYN
同步事件,我们重点关注按键事件:
KeyboardInputMapper::processKey
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
&policyFlags)) {
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
//按下事件
if (down) {
...
// Add key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
//重复事件
keyCode = mKeyDowns[keyDownIndex].keyCode;
} else {
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
//需要丢弃
return;
}
if (policyFlags & POLICY_FLAG_GESTURE) {
getDeviceContext().cancelTouch(when);
}
//构造KeyDown
KeyDown keyDown;
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
//放入mKeyDowns
mKeyDowns.push_back(keyDown);
}
mDownTime = when;
} else {//抬起事件
// Remove key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// 一个按键事件抬起之后将该事件以及之前的所以事件从mKeyDowns移除
keyCode = mKeyDowns[keyDownIndex].keyCode;
mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
} else {
//该事件只有抬起没有按下,异常情况
return;
}
}
......
nsecs_t downTime = mDownTime;
...
NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
}
这个函数有个非常重要的操作就是getDeviceContext().mapKey
,它会将按键扫描码scanCode转换为keyCode,scanCode是驱动提供的,上层java使用的就是转换之后的keyCode,扫描码定义在kl(key layout)文件中,例如:
这是我们公司的测试手机中的一张kl文件,定义了很多按键扫描码,如POWER
对应扫描码116,我们可以通过命令adb shell getevent查看,当我点击POWER
键时有如下输出:74是十六进制,对应十进制刚好等于116,并且注意其事件发生的设备节点为/dev/input/event1,而/dev/input/event1下的kl表名称就是" mtk-kpd.kl",所以POWER
扫描码定义在" mtk-kpd.kl"中。
scanCode到keyCode的映射限于篇幅,本篇不会分析,后面分析".kl"文件的解析时来看。
接着看processKey
函数,变量down
描述按键按下还是抬起,大于0代表按下,等于0代表抬起,然后对按下和抬起分别做处理,mKeyDowns
是一个存储KeyDown
结构体集合,KeyDown
结构体用来封装一个按键的scanCode
和keyCode
,
struct KeyDown {
int32_t keyCode;
int32_t scanCode;
};
findKeyDown
函数作用是从mKeyDowns
集合中查找KeyDown
结构体,processKey
函数对按下和抬起事件处理很简单,即按下时添加到mKeyDowns
,抬起时从mKeyDowns
移除,函数最后根据RawEvent
解析出的按键信息构造了一个NotifyKeyArgs
,并调用QueuedInputListener
的notifyKey
将NotifyKeyArgs
发送出去,
QueuedInputListener::notifyKey
//InputListener.cpp
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
traceEvent(__func__, args->id);
mArgsQueue.push_back(new NotifyKeyArgs(*args));
}
这个函数做的事情就跟简单了,仅仅就是将NotifyKeyArgs
放入mArgsQueue
集合,
std::vector<NotifyArgs*> mArgsQueue;
到此RawEvent
的加工就已经完成,说起来也很简单就是转换成了NotifyKeyArgs
,接着我们需要再回到InputReader::loopOnce函数的第四部分:
//InputReader.cpp
void InputReader::loopOnce() {
//(1)
...
//(2)
...
//(3)
...
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}
QueuedListener::flush
//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();
}
这里会遍历mArgsQueue
,并调用NotifyArgs
的notify
函数,NotifyArgs
是一个父类,不同事件类型对应不同的子类,有如下几种类型:
NotifyConfigurationChangedArgs
NotifyKeyArgs
NotifyMotionArgs
NotifySwitchArgs
NotifyDeviceResetArgs
因为我们分析的是按键事件,对应的是NotifyKeyArgs
,即NotifyKeyArgs::notify
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);//this代表NotifyKeyArgs
}
这里继续调用InputListenerInterface
的notifyKey
函数,InputListenerInterface
是一个父类,我们需要找其子类的具体实现,子类其实就是InputDispatcher
,
class InputDispatcher : public android::InputDispatcherInterface{
...
}
到此,输入事件就顺理成章的从InputReader
发送到了InputDispatcher
,本篇文章也接近了尾声,不得不说InputReader
线程对事件的处理确实非常复杂,InputReader
对input事件处理过程大致可以分为三大步:
EventHub
通过INotify与Epoll监听/dev/input下的事件,在读取到事件之后放入mEventBuffer
,此步骤将input_event
转换为了RawEvent
。- 拿到原始事件
RawEvent
之后调用processEventsLocked
对事件进行加工,不同事件类型有不同的加工厂(InputMapper),此步骤将RawEvent
转换为了NotifyKeyArgs
。 - 通过
QueuedListener
的flush
函数将事件发送到InputDispatcher
线程。