前言
本章将继续探究InputReader线程,该线程负责从eventhub获取事件,转换成EventEntry事件并将事件加入到InputDispatcher的mInboundQueue。
threadLoop
InputReaderThread线程启动后,将调用一个thredLoop
方法,该方法不断从eventhub获取事件,并进行后续处理,相关代码位于frameworks/native/services/inputflinger/reader/InputReader.cpp
:
// 启动InputReader,调用loopOnce
status_t InputReader::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
return OK;
}
void InputReader::loopOnce() {
...
// 从eventhub获取事件(EVENT_BUFFER_SIZE = 256)
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
// 处理事件
processEventsLocked(mEventBuffer, count);
}
...
// 如果输入设备发生改变,则重新获取当前输入设备
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// 发送输入设备改变的通知
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// 发送事件到nputDispatcher
mQueuedListener->flush();
}
在上述代码中,有三个关键节点需要重点关注,他们分别是:mEventHub->getEvents
,processEventsLocked
,mQueuedListener->flush
,下面将重点介绍下这几个方法。
mEventHub->getEvents [获取事件]
getEvents方法主要负责获取kernel的event, 这里事件不仅包括input,还包括输入设备的add/remove等相关事件。
加入的输入设备在没有事件的时候,会block在EventHub中的epoll处,当有事件产生后,epoll_wait就会返回,然后针对变化的事件进行处理。相关代码位于frameworks/native/services/inputflinger/reader/EventHub.cpp
:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
...
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// 扫描设备
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;
}
...
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
// 从设备读取事件,放入到readBuffer
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
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];
// 将input_event信息封装成RawEvent
event->when = processEventTimestamp(iev);
event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
}
...
}
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
//poll之前先释放锁 等待input事件的到来
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
} else {
// Some events occurred.
mPendingEventCount = size_t(pollResult);
}
}
// All done, return the number of events we read.
return event - buffer;
}
EventHub采用INotify + epoll机制实现监听目录/dev/input下的设备节点,经过EventHub将input_event结构体 + deviceId 转换成RawEvent结构体,RawEvent结构体的声明位于frameworks/native/services/inputflinger/reader/include/EventHub.h
,其结构如下:
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
struct RawEvent {
// Time when the event happened
nsecs_t when;
// Time when the event was read by EventHub. Only populated for input events.
// For other events (device added/removed/etc), this value is undefined and should not be read.
nsecs_t readTime;
int32_t deviceId;
int32_t type;
int32_t code;
int32_t value;
};
struct input_event {
struct timeval time; //事件发生的时间点
__u16 type;
__u16 code;
__s32 value;
};
processEventsLocked [处理事件]
processEventsLocked
方法负责设备的添加、移除与删除,以及事件的处理,相关代码位于frameworks/av/media/libstrming/input/key_injector.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;
}
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;
rawEvent += batchSize;
}
}
processEventsForDeviceLocked
processEventsForDeviceLocked
方法用于处理输入设备事件,更具体的来说,是对输入事件的相关信息进行核验,该方法位于frameworks/native/services/inputflinger/reader/InputReader.cpp
:
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
size_t count) {
// 使用eventHubId查找是哪一个设备发送的事件
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);
}
InputDevice::process
InputDevice::process
方法负责将输入事件进行映射处理,按设备顺序处理所有事件,这是因为每个设备处理之间可能有依赖关系。相关代码位于frameworks/native/services/inputflinger/reader/InputDevice.cpp
:
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
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;
}
}
KeyboardInputMapper::process
上面提到InputDevice::process
方法会使用不同的处理方式处理输入事件,这些事件包括但不限于触控事件、键盘事件、传感器事件等等,总结下来共有以下几种处理方法
class SwitchInputMapper : public InputMapper {
class VibratorInputMapper : public InputMapper {
class KeyboardInputMapper : public InputMapper {
class CursorInputMapper : public InputMapper {
class RotaryEncoderInputMapper : public InputMapper {
class TouchInputMapper : public InputMapper {
class ExternalStylusInputMapper : public InputMapper {
class JoystickInputMapper : public InputMapper {
在这其中,键盘事件处理最为简单,也最容易分析,触控事件最复杂,所以这里以键盘事件为例进行分析,相关代码位于frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.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->readTime, 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::processKey
KeyboardInputMapper::processKey
方法用于处理按键相关事件,相关代码位于frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
:
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
// 将事件的扫描码(scanCode)转换成键盘码(Keycode)
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
&keyCode, &keyMetaState, &policyFlags)) {
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
if (down) {
...
mDownTime = when;
} else {
...
}
// 创建NotifyKeyArgs对象, when记录eventTime, downTime记录按下时间
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
// 发送key事件
getListener()->notifyKey(&args);
}
EventHub::mapKey
EventHub::mapKey
负责将事件的扫描码(scanCode)转换成键盘码(Keycode),相关代码位于frameworks/native/services/inputflinger/reader/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 {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
if (device != nullptr) {
// Check the key character map first.
const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap();
if (kcm) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0;
status = NO_ERROR;
}
}
// Check the key layout next.
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) {
kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
} else {
*outMetaState = metaState;
}
}
}
if (status != NO_ERROR) {
*outKeycode = 0;
*outFlags = 0;
*outMetaState = metaState;
}
return status;
}
总结
以上就是InputReader的全部流程,现给出InputReader事件的流程图供大家参考
尾声
一转眼时间真的过的飞快。我们各奔东西,也各自踏上了自己的旅途,但是即使多年不见,也因为这份情谊我们依旧如从前那般“亲密”。不忘初心方得始终。加油吧,程序员们,在我看来35岁,40岁从来不是危机,只要永远不要忘记自己为何踏上征程!
最后需要同款资料的,可以 私信我回复【学习】或者扫描下方二维码我愿意分享给你!
为了让更多在学习中或者最近要准备面试的朋友们看到这篇文章,希望你们能多多评论,点赞+转发!
**再次感谢所有给我提供过题目的朋友们,感谢一路有你!