Android R input 之 InputReader 工作流程
Posted pecuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android R input 之 InputReader 工作流程相关的知识,希望对你有一定的参考价值。
文章托管在gitee上 Android Notes , 同步csdn
InputReader 的创建
如前所述,InputReader是在 InputManager 构造方法中通过工厂方法createInputReader创建,在此方法中,还创建了EventHub作为构造参数. 此处的policy即NativeInputManager对象,listener的值实际上是mDispatcher的封装.
/// @frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
// 直接new了对象, 注意参数
return new InputReader(std::make_unique<EventHub>(), policy, listener);
InputReader 构造
/// @frameworks/native/services/inputflinger/reader/InputReader.cpp
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
: mContext(this), // 注意到mContext的值即InputReader this指针
mEventHub(eventHub), // 初始化eventHub
mPolicy(policy), // 初始化策略
mGlobalMetaState(0),
mGeneration(1),
mNextInputDeviceId(END_RESERVED_ID),
mDisableVirtualKeysTimeout(LLONG_MIN), // #define LLONG_MIN (-__LONG_LONG_MAX__-1LL)
mNextTimeout(LLONG_MAX), // #define LLONG_MAX __LONG_LONG_MAX__
mConfigurationChangesToRefresh(0)
//queues up and defers dispatch of decoded events until flushed.
// 创建 QueuedInputListener
mQueuedListener = new QueuedInputListener(listener); // 间接持有InputDispatcher的引用
// acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
// release lock
QueuedInputListener 构造
这个类是辅助派发事件的. 当有事件时先入QueuedInputListener的mArgsQueue队列,之后调用QueuedInputListener的flush方法时才进行真正的派发.
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener)
注意参数是 InputListenerInterface 指针, 它实际上指向的是InputClassifier对象, 而InputClassifier是对InputDispatcher的封装.因此,事件实际上是派发给了InputDispatcher.
InputListenerInterface 定义
下面看一下InputListenerInterface定义:
/// @frameworks/native/services/inputflinger/include/InputListener.h
/*
* The interface used by the InputReader to notify the InputListener about input events.
*/
class InputListenerInterface : public virtual RefBase
protected:
InputListenerInterface()
virtual ~InputListenerInterface()
public:
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
virtual void notifyKey(const NotifyKeyArgs* args) = 0;
virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
;
它的实现者有:
- InputClassifierInterface , 此接口的实现类是InputClassifier
/**
* Base interface for an InputListener stage.
* Provides classification to events.
*/
class InputClassifierInterface : public virtual RefBase, public InputListenerInterface
- InputDispatcherInterface , 此接口的实现类是 InputDispatcher
/* Notifies the system about input events generated by the input reader.
* The dispatcher is expected to be mostly asynchronous. */
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface
而QueuedInputListener同样实现了InputListenerInterface,并且持有InputClassifier, 此处使用的是装饰者模式. 因此派发流程是 QueuedInputListener -> InputClassifier -> InputDispatcher
这个流程我画了一张图,如下:
创建 EventHub
EventHub 是原始input的处理类,功能包括处理input设备的添加移除,获取input事件等
class EventHub : public EventHubInterface
public:
EventHub();
...
EventHubInterface
它继承自EventHubInterface,这个接口定义了input处理的相关方法,如 getEvents 方法.
/// @frameworks/native/services/inputflinger/reader/include/EventHub.h
/*
* Grand Central Station for events.
*
* The event hub aggregates input events received across all known input
* devices on the system, including devices that may be emulated by the simulator
* environment. In addition, the event hub generates fake input events to indicate
* when devices are added or removed.
*
* The event hub provides a stream of input events (via the getEvent function).
* It also supports querying the current actual state of input devices such as identifying
* which keys are currently down. Finally, the event hub keeps track of the capabilities of
* individual input devices, such as their class and the set of key codes that they support.
*/
class EventHubInterface
public:
EventHubInterface()
virtual ~EventHubInterface()
// Synthetic raw event type codes produced when devices are added or removed.
enum
// Sent when a device is added.
DEVICE_ADDED = 0x10000000,
// Sent when a device is removed.
DEVICE_REMOVED = 0x20000000,
// Sent when all added/removed devices from the most recent scan have been reported.
// This event is always sent at least once.
FINISHED_DEVICE_SCAN = 0x30000000,
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
;
virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;
...
/*
* Wait for events to become available and returns them.
* After returning, the EventHub holds onto a wake lock until the next call to getEvent.
* This ensures that the device will not go to sleep while the event is being processed.
* If the device needs to remain awake longer than that, then the caller is responsible
* for taking care of it (say, by poking the power manager user activity timer).
*
* The timeout is advisory only. If the device is asleep, it will not wake just to
* service the timeout.
*
* Returns the number of events obtained, or 0 if the timeout expired.
*/
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0;
...
EventHub 构造
这个构造方法的工作如下:
- 初始化一些成员变量,赋值默认值
- 确保能block suspend, 确保事件能被正常处理
- 创建 epoll , 记录mEpollFd
- 初始化inotify, 并将/dev/input 目录下添加IN_DELETE | IN_CREATE监听
- 如果ro.input.video_enabled为true,即需要扫描V4L devices, 则添加VIDEO_DEVICE_PATH到inotify监听
- 添加mINotifyFd到epoll监听列表
- 创建用于wake的管道, 并将读端添加到epoll监听列表
EventHub::EventHub(void)
: mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
mNextDeviceId(1),
mControllerNumbers(),
mOpeningDevices(nullptr),
mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false),
mNeedToScanDevices(true), // 此处默认为true,需要扫描所有设备
mPendingEventCount(0),
mPendingEventIndex(0),
mPendingINotify(false)
ensureProcessCanBlockSuspend(); // 确保能block suspend
// 创建 epoll
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
// 初始化 inotify , 用于监听文件系统的变化
mINotifyFd = inotify_init();
// 添加监听DEVICE_PATH = "/dev/input" 下的创建与删除,
// 当有变化时将相关改变写入到mINotifyFd对应的文件,通过read读取相关notify
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
strerror(errno));
if (isV4lScanningEnabled())
mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
VIDEO_DEVICE_PATH, strerror(errno));
else
mVideoWd = -1;
ALOGI("Video device scanning disabled");
struct epoll_event eventItem = ;
eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = mINotifyFd;
// 将mINotifyFd添加到 epoll监听, 当有设备节点增删时,会因mINotifyFd有新数据的到来而触发epoll相关事件
// 通过相关epoll事件,可知有相关设备改变,读取mINotifyFd可获取相关设备信息变化
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
// 创建wake 管道 , 主要用于唤醒 EventHub::getEvents, 可能阻塞在read
result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0]; // 赋值读写管道
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); // 设置读 non-blocking
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); // 设置写 non-blocking
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.fd = mWakeReadPipeFd;
// 将mWakeReadPipeFd 添加到 epoll 监听. 当调用wake()向mWakeWritePipeFd写入数据,将导致读端收到数据而被唤醒
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
InputReader::start
IMS#start方法会调用nativeStart, 之后在native会进一步调用InputReader::start. 在这个方法中,会创建其InputThread任务线程. 如前所述,InputThread构造方法内部会创建一个线程,并启动此线程.
status_t InputReader::start()
if (mThread)
return ALREADY_EXISTS;
// 创建InputThread, 它是一个线程包装类, 内部会创建线程并启动
mThread = std::make_unique<InputThread>(
"InputReader", [this]() loopOnce(); , [this]() mEventHub->wake(); );
return OK;
注意到创建InputThread时有三个参数,第一个是线程的名称,第二个是线程执行threadLoop时回调的函数,此处写法是C++11的lambda表达式,第三个参数是线程销毁前调用来唤醒线程的回调.
InputReader::loopOnce
InputReader线程执行会不断的调用 loopOnce 方法,此方法的工作大致如下:
- 如果配置改变,则更新配置. 否则重新计算timeoutMillis
- 调用EventHub::getEvents获取事件,此处可能会阻塞到事件到来或者超时返回. 获取到的事件放在mEventBuffer, 一次最大可以读取EVENT_BUFFER_SIZE=256 件.
- 当获取到事件,则调用 processEventsLocked 来处理事件. 相关事件会通过notifyXXX添加到QueuedInputListener的mArgsQueue中
- 通过mGeneration判断设备变更. 当有变化时,通过getInputDevicesLocked来获取设备信息,然后通过mPolicy->notifyInputDevicesChanged通知设备变化,此处的mPolicy实际上是NativeInputManager对象,它最终会回调IMS的notifyInputDevicesChanged通知设备改变
- 最后mQueuedListener->flush 将mArgsQueue中的所有相关事件投递到InputDispatcher的队列中
void InputReader::loopOnce()
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
// 从EventHub 获取事件. event queue 定义如下
// static const int EVENT_BUFFER_SIZE = 256;
// RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
// acquire lock
AutoMutex _l(mLock);
// 通知reader还处于活跃状态. InputReader::monitor方法检测reader线程是否发生死锁
mReaderIsAliveCondition.broadcast();
if (count) // 大于0则有事件需要处理
processEventsLocked(mEventBuffer, count); // 处理events
if (mNextTimeout != LLONG_MAX)
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) // now比mNextTimeout大,则此timeout过期
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX; // timeout过期则设置mNextTimeout为最大LLONG_MAX
timeoutExpiredLocked(now); // 通知 devices timeoutExpired
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(); // 执行分发事件到listener
RawEvent
RawEvent 是EventHub中对事件的描述. 具体可以分为两类:
- 设备改变事件, 如添加/移除设备的事件
- 原始事件, 比如触摸屏幕或者按物理按键触发的事件
/// @frameworks/native/services/inputflinger/reader/include/EventHub.h
/*
* A raw event as retrieved from the EventHub.
*/
struct RawEvent
nsecs_t when; // 事件发生时的时间戳
int32_t deviceId; // 产生事件的设备id
int32_t type; // 事件类型
int32_t code; // 事件码值
int32_t value; // 事件值
;
对于事件类型,也做了相关定义. 对于设备相关事件,定义了特定的值, 如添加设备的事件类型是DEVICE_ADDED
/// @frameworks/native/services/inputflinger/reader/include/EventHub.h
class EventHubInterface ...
// Synthetic raw event type codes produced when devices are added or removed.
enum
// Sent when a device is added.
DEVICE_ADDED = 0x10000000,
// Sent when a device is removed.
DEVICE_REMOVED = 0x20000000,
// Sent when all added/removed devices from the most recent scan have been reported.
// This event is always sent at least once.
FINISHED_DEVICE_SCAN = 0x30000000,
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
;
超时计算
下面看一下如何计算系统时间与超时延时
/// @system/core/libutils/Timers.cpp
// host linux support requires Linux 2.6.39+
#if defined(__linux__)
// 获取系统时间
nsecs_t systemTime(int clock)
static const clockid_t clocks[] =
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
CLOCK_THREAD_CPUTIME_ID,
CLOCK_BOOTTIME
;
struct timespec t;
t.tv_sec = t.tv_nsec = 0;
clock_gettime(clocks[clock], &t); // 获取时间
return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; // 转换成纳秒
#else ...
// 获取延迟时间
int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
nsecs_t timeoutDelayMillis;
if (timeoutTime > referenceTime) // 大于参考时间,说明需要延时,则计算差值
uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) // delay极大
timeoutDelayMillis = -1; // 则设置为-1, 表示无限等待
else
timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL; // 转换成ms,且确保有至少有1ms
else // 否则, 超时延时为0
timeoutDelayMillis = 0;
return (int)timeoutDelayMillis;
EventHub#getEvents
这个函数是处理原始的输入事件,如设备添加移除,输入事件等. 这个函数的工作大致如下:
- 循环处理,直到break
- 处理devices变化,及合成相关的设备事件, 如重新打开/添加/关闭设备, 某些情况会break
- 处理pending 的events , 如有新事件,则会break
- 处理 mINotifyFd , 有设备状态变化,调用readNotifyLocked处理处理变更
- 处理 mWakeReadPipeFd 操作, 通常是wake()操作
- 处理 input 事件
- epoll_wait 等待新事件的到来
- 有新事件到来,更新mPendingEventCount,进行下一轮的处理
以上有新事件的地方,会转换为RawEvent, 然后返回给InputReader进一步处理
/// @frameworks/native/services/inputflinger/reader/EventHub.cpp
// bufferSize : EVENT_BUFFER_SIZE = 256;
// buffer : RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
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);
// Reopen input devices if needed.
// 调用 requestReopenDevices() 会导致 mNeedToReopenDevices = true
if (mNeedToReopenDevices) // 处理需要重新打开设备的情况
mNeedToReopenDevices = false;
ALOGI("Reopening all input devices due to a configuration change.");
closeAllDevicesLocked(); // 先关闭所有设备
mNeedToScanDevices = true; // 设置需要扫描设备
break; // return to the caller before we actually rescan
// Report any devices that had last been added/removed.
while (mClosingDevices) // 处理移除设备的事件
Device* device = mClosingDevices;
ALOGV("Reporting device closed: id=%d, name=%s\\n", device->id, device->path.c_str());
mClosingDevices = device->next; // 指向下一个device,在下一次循环继续处理。可以发现多个事件是串行处理的
event->when = now;
event->deviceId = (device->id == mBuiltInKeyboardId)
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
: device->id;
event->type = DEVICE_REMOVED; // 事件类型是 DEVICE_REMOVED
event += 1; // 移动buffer指针到event的下一个RawEvent地址
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) // 每增加一个event,则capacity-1, capacity为0时结束循环
break;
// mNeedToScanDevices 默认为true
if (mNeedToScanDevices) // 处理需要扫描设备的情况
mNeedToScanDevices = false;
scanDevicesLocked(); // 扫描设备
mNeedToSendFinishedDeviceScan = true;
while (mOpeningDevices != nullptr) // 处理新设备添加事件
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\\n", device->id, device->path.c_str());
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED; // 事件类型是 DEVICE_ADDED
event += 1;
mNeedToSendFinishedDeviceScan = true; // 设置需要结束扫描
if (--capacity == 0)
break;
if (mNeedToSendFinishedDeviceScan) // 添加设备扫描完成的事件
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN; // 事件类型是 FINISHED_DEVICE_SCAN
event += 1;
if (--capacity == 0)
break;
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) // 处理 pending 事件
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.fd == mINotifyFd) // 处理mINotifyFd, 通常是有设备变化
if (eventItem.events & EPOLLIN)
mPendingINotify = true;
else
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
continue;
if (eventItem.data.fd == mWakeReadPipeFd) // 处理mWakeReadPipeFd, 通常是调用wake()的原因
if (eventItem.events & EPOLLIN)
ALOGV("awoken after wake()");
awoken = true; // 当收到唤醒的消息,会导致getEvents 从阻塞状态返回
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;
Device* device = getDeviceByFdLocked(eventItem.data.fd); // 获取fd对应的device
if (!device) // 判断fd 对应的设备是否存在
ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
eventItem.data.fd);
ALOG_ASSERT(!DEBUG);
continue;
// 处理 videoDevice
if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd())
if (eventItem.events & EPOLLIN)
size_t numFrames = device->videoDevice->readAndQueueFrames();
if (numFrames == 0)
ALOGE("Received epoll event for video device %s, but could not read frame",
device->videoDevice->getName().c_str());
else if (eventItem.events & EPOLLHUP)
// TODO(b/121395353) - consider adding EPOLLRDHUP
ALOGI("Removing video device %s due to epoll hang-up event.",
device->videoDevice->getName().c_str());
unregisterVideoDeviceFromEpollLocked(*device->videoDevice);
device->videoDevice = nullptr;
else
ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
device->videoDevice->getName().c_str());
ALOG_ASSERT(!DEBUG);
continue;
// This must be an input event
if (eventItem.events & EPOLLIN) // 开始处理输入事件
// 使用read函数从fd读取事件,存储到readBuffer. 读取capacity个input_event
int32_t readSize =
read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
// 有事件通知但未读取到事件,设备可能INotify通知之前在被移除了
if (readSize == 0 || (readSize < 0 && errno == ENODEV))
// Device was removed before INotify noticed.
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) // 不是input_event结构体大小的整数倍
ALOGE("could not get event (wrong size: %d)", readSize);
else // 下面处理纯粹的输入事件, 将 input_event 转换为 RawEvent
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event); // 计算input_event的个数
for (size_t i = 0; i < count; i++) // 将 input_event 转换成 RawEvent
struct input_event& iev = readBuffer[i];
event->when = processEventTimestamp(iev);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
if (capacity == 0) // 为0,说明上面读取了capacity个input_event,
// 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) // 处理 EPOLLHUP
ALOGI("Removing device %s due to epoll hang-up event.",
device->identifier.name.c_str());
deviceChanged = true;
closeDeviceLocked(device);
else // 其他未知 events
ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
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.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) // 在读取完所有屏pending事件后才通知设备改变
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
// Report added or removed devices immediately.
if (deviceChanged) // 设备改变则进行下一轮循环处理
continue;
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) // 已经读取到了事件或是被唤醒, 则退出循环
// 为什么此处awoken为true时,需要break? 因为当调用wake()函数时向管道写端写入数据,会导致读端有新数据到来,
// 而导致epoll_wait从等待中返回,此时有新事件发生,在下一轮循环中读取mWakeReadPipeFd的事件,
// 从而给awoken赋值为true. 此处应该break从而使getEvents函数返回,这正是wake()的目的,
// 否则继续将陷入epoll_wait等待,不符合预期.
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
// 到此处说明pending的事件已经处理完毕,需要获取新的事件. epoll_wait 会等待新事件到来或者到了超时事件返回
// 等待事件的到来, 读取的 epoll_event 事件被存储在mPendingEventItems数组,大小是EPOLL_MAX_EVENTS = 16
// 即每次最多读取16个 epoll_event 事件, 这些事件包含设备节点的增删,设备节点有新输入事件可读等
// timeoutMillis 是等待的超时时间
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
mLock.lock(); // reacquire lock after poll
if (pollResult == 0) // 超时,没有事件发生
// Timed out.
mPendingEventCount = 0;
break;
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)
ALOGW("poll failed (errno=%d)\\n", errno);
usleep(100000);
else // 有事件发生, 下一轮循环处理
// Some events occurred.
mPendingEventCount = size_t(pollResult); // 计算事件的数量
// All done, return the number of events we read.
return event - buffer; // 与数组初始位置的偏移,计算RawEvent的个数
在EventHub的构造函数中,给mNeedToScanDevices赋值是true,因此第一次调用EventHub::getEvents时会首先扫描所有设备,具体的实现函数是scanDevicesLocked
EventHub::scanDevicesLocked
void EventHub::scanDevicesLocked()
status_t result = scanDirLocked(DEVICE_PATH); // 扫描 DEVICE_PATH /dev/input
if (result < 0)
ALOGE("scan dir failed for %s", DEVICE_PATH);
if (isV4lScanningEnabled()) // 支持 v4l ,则扫描 VIDEO_DEVICE_PATH
result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
if (result != OK)
ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) // 创建虚拟键盘
createVirtualKeyboardLocked();
scanDirLocked
这个函数扫描设备目录(如 /dev/input)下的所有节点, 分别对其执行openDeviceLocked完成打开设备操作. 如下是以 dirname 是 /dev/input 为例:
status_t EventHub::scanDirLocked(const char* dirname)
char devname[PATH_MAX];
char* filename;
DIR* dir;
struct dirent* de;
dir = opendir(dirname); // 打开 /dev/input
if (dir == nullptr) return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/'; // /dev/input/
while ((de = readdir(dir))) // 读取dir,直到返回 NULL
// 跳过 . 和 .. 目录
if (de->d_name[0] == '.' &&
(de->d_name[1] == '\\0' || (de->d_name[1] == '.' && de->d_name[2] == '\\0')))
continue;
strcpy(filename, de->d_name); // 拼接 /dev/input/ 和 d_name , 如 /dev/input/event0
openDeviceLocked(devname); // 打开设备
closedir(dir);
return 0;
EventHub::openDeviceLocked
此函数是用来完成设备的打开操作,此方法的工作大致如下:
- 打开指定设备节点
- 获取设备信息, 创建 Device
- 设备类型, keyMap 处理等
- 注册 Device 的 epoll 事件监听
- 保存device到mDevices, 并添加device到mOpeningDevices列表以通知设备添加
status_t EventHub::openDeviceLocked(const char* devicePath)
char buffer[80];
ALOGV("Opening device: %s", devicePath);
// 打开此设备
int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
if (fd < 0)
ALOGE("could not open %s, %s\\n", devicePath, strerror(errno));
return -1;
// 获取设备信息
InputDeviceIdentifier identifier;
// Get device name.
// Check to see if the device is on our excluded list 在此列表会关闭设备
// Get device driver version.
// Get device identifier.
// Get device physical location.
// Get device unique id.
// Fill in the descriptor.
assignDescriptorLocked(identifier);
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, devicePath, identifier); // 创建Device
...
// Load the configuration file for the device.
loadConfigurationLocked(device); // 加载
... // 判断类型,加载key map 等
// 添加到 epoll 监听
if (registerDeviceForEpollLocked(device) != OK)
delete device;
return -1;
configureFd(device); // 配置kernel key repeat和monotonic clock
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes,
device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(),
device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId));
addDeviceLocked(device); // 通知添加设备
return OK;
接下来先看如何给device 注册epoll事件
EventHub::registerDeviceForEpollLocked
status_t EventHub::registerDeviceForEpollLocked(Device* device)
if (device == nullptr)
if (DEBUG)
LOG_ALWAYS_FATAL("Cannot call registerDeviceForEpollLocked with null Device");
return BAD_VALUE;
status_t result = registerFdForEpoll(device->fd); // 将此设备的fd注册到epoll
if (result != OK)
ALOGE("Could not add input device fd to epoll for device %" PRId32, device->id);
return result;
if (device->videoDevice)
registerVideoDeviceForEpollLocked(*device->videoDevice);
return result;
接着调用 registerFdForEpoll , 将此设备的fd注册到epoll,当有新事件时,epoll_wait会返回相关事件信息.
status_t EventHub::registerFdForEpoll(int fd)
// TODO(b/121395353) - consider adding EPOLLRDHUP
struct epoll_event eventItem = ;
eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = fd;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) // 注册fd到epoll
ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
return -errno;
return OK;
EventHub::addDeviceLocked
这个函数完成打开设备的收尾工作.保存device到mDevices,并添加device到mOpeningDevices列表. 在getEvents中,当扫描完设备后,会处理mOpeningDevices列表生成相关设备添加的事件.
void EventHub::addDeviceLocked(Device* device)
mDevices.add(device->id, device); // 保存device到mDevices (KeyedVector<int32_t, Device*>)
device->next = mOpeningDevices; // 添加device到mOpeningDevices列表
mOpeningDevices = device;
EventHub::readNotifyLocked
当epoll监听到mINotifyFd中有可读事件时,说明设备发生变化. 之后再合适的时机调用readNotifyLocked处理变化
status_t EventHub::readNotifyLocked()
int res;
char event_buf[512];
int event_size;
int event_pos = 0;
struct inotify_event* event;
ALOGV("EventHub::readNotify nfd: %d\\n", mINotifyFd);
res = read(mINotifyFd, event_buf, sizeof(event_buf));
if (res < (int)sizeof(*event))
if (errno == EINTR) return 0;
ALOGW("could not get event, %s\\n", strerror(errno));
return -1;
while (res >= (int)sizeof(*event))
event = (struct inotify_event*)(event_buf + event_pos);
if (event->len)
if (event->wd == mInputWd) // 说明DEVICE_PATH目录下有变化
std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
if (event->mask & IN_CREATE) // 有新设备节点创建
openDeviceLocked(filename.c_str()); //打开设备
else // 否则关闭设备
ALOGI("Removing device '%s' due to inotify event\\n", filename.c_str());
closeDeviceByPathLocked(filename.c_str());
else if (event->wd == mVideoWd)
if (isV4lTouchNode(event->name))
std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name);
if (event->mask & IN_CREATE)
openVideoDeviceLocked(filename);
else
ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
closeVideoDeviceByPathLocked(filename);
else
LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
return 0;
InputReader::processEventsLocked
再次回到InputReader::loopOnce, 当通过mEventHub->getEvents获取到相关事件,即count>0时则会调用processEventsLocked处理RawEvent
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count)
for (const RawEvent* rawEvent = rawEvents; count;)
int32_t type = rawEvent->type;
size_t batchSize = 1;
// 处理type小于 FIRST_SYNTHETIC_EVENT=DEVICE_ADDED , 即处理原始事件,非合成的事件
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT)
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) // 统计batchSize
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||
rawEvent[batchSize].deviceId != deviceId)
break;
batchSize += 1;
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize); // 处理原始 RawEvent
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;
下面先看添加设备的逻辑.
InputReader::addDeviceLocked
此处的mDevices与EventHub中的不同, 它的类型是std::unordered_map<int32_t /eventHubId/, std::shared_ptr>
void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId)
if (mDevices.find(eventHubId) != mDevices.end()) // 查找是否添加过
ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
return;
// 通过 device id 获取设备的 InputDeviceIdentifier
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
// 创建 InputDevice
std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
device->configure(when, &mConfig, 0); // 配置device
device->reset(when);
if (device->isIgnored())
ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' "
"(ignored non-input device)",
device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str());
else
ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x",
device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),
device->getSources());
mDevices.emplace(eventHubId, device); // 添加到map
bumpGenerationLocked(); // 更新 mGeneration
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS)
notifyExternalStylusPresenceChanged();
InputReader::createDeviceLocked
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
int32_t eventHubId, const InputDeviceIdentifier& identifier)
// 查找是否存在与identifier.descriptor相同的键值对
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();
device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
identifier);
device->addEventHubDevice(eventHubId); // 添加EventHubDevice,填充InputMapper
return device;
InputDevice::addEventHubDevice
此方法向InputDevice的mDevices添加设备信息, 并且根据设备类型初始化 InputMapper. populateMappers 为true时需要添加对应的InputMapper.
InputMapper(输入映射器)将原始输入事件转换为android事件数据。
单个输入设备可以具有多个关联的输入映射器,以便解释不同类别的事件
/// @frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers /* 默认为true */)
if (mDevices.find(eventHubId) != mDevices.end())
return;
// 创建 InputDeviceContext 对象
std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
uint32_t classes = contextPtr->getDeviceClasses();
std::vector<std::unique_ptr<InputMapper>> mappers;
// Check if we should skip population
if (!populateMappers) // 是否需要添加InputMapper
mDevices.insert(eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers)));
return;
// 下面针对不同的class,添加对应的 InputMapper
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH)
mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
// Scroll wheel-like devices.
if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER)
mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
// Vibrator-like devices.
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;
if (keyboardSource != 0) // 可以发现, 上面4种类别对应的都是KeyboardInputMapper
mappers.push_back(
std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
// Cursor-like devices.
if (classes & INPUT_DEVICE_CLASS_CURSOR) // 如鼠标设备
mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
// Touchscreens and touchpad devices.
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));
// Joystick-like devices.
if (classes & INPUT_DEVICE_CLASS_JOYSTICK)
mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
// External stylus-like devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS)
mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
// insert the context into the devices set
// eventHubId为key, make_pair创建键
mDevices.insert(eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers)));
上面的的mDevices是在InputDevice.h中定义的:
// map from eventHubId to device context and mappers
using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;
// 等价于 unordered_map< int32_t, std::pair<InputDeviceContext*, std::vector<InputMapper*>> >
std::unordered_map<int32_t, DevicePair> mDevices;
设备类别定义
一个输入设备可能对应多个类别
/// @frameworks/native/services/inputflinger/reader/include/EventHub.h
/*
* Input device classes.
*/
enum
/* The input device is a keyboard or has buttons. */
INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001,
/* The input device is an alpha-numeric keyboard (not just a dial pad). */
INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002,
/* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
/* The input device is a cursor device such as a trackball or mouse. */
INPUT_DEVICE_CLASS_CURSOR = 0x00000008,
/* The input device is a multi-touch touchscreen. */
INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,
/* The input device is a directional pad (implies keyboard, has DPAD keys). */
INPUT_DEVICE_CLASS_DPAD = 0x00000020,
/* The input device is a gamepad (implies keyboard, has BUTTON keys). */
INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040,
/* The input device has switches. */
INPUT_DEVICE_CLASS_SWITCH = 0x00000080,
/* The input device is a joystick (implies gamepad, has joystick absolute axes). */
INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100,
/* The input device has a vibrator (supports FF_RUMBLE). */
INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200,
/* The input device has a microphone. */
INPUT_DEVICE_CLASS_MIC = 0x00000400,
/* The input device is an external stylus (has data we want to fuse with touch data). */
INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,
/* The input device has a rotary encoder */
INPUT_DEVICE_CLASS_ROTARY_ENCODER = 0x00001000,
/* The input device is virtual (not a real device, not part of UI configuration). */
INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000,
/* The input device is external (not built-in). */
INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
;
InputMapper
这个类是原始输入事件加工处理的地方
/* An input mapper transforms raw input events into cooked event data.
* A single input device can have multiple associated input mappers in order to interpret
* different classes of events.
*
* InputMapper lifecycle:
* - create
* - configure with 0 changes
* - reset
* - process, process, process (may occasionally reconfigure with non-zero changes or reset)
* - reset
* - destroy
*/
class InputMapper
public:
explicit InputMapper(InputDeviceContext& deviceContext);
virtual void process(const RawEvent* rawEvent) = 0;
...
InputReader::bumpGenerationLocked
在getEvents中,判断mGeneration改变来确定inputDevice的状态改变
int32_t InputReader::bumpGenerationLocked()
return ++mGeneration;
当添加输入设备后,就可以等待相关事件的到来. 使用 processEventsForDeviceLocked 方法来处理纯粹的输入事件,如触摸屏幕或按power键.
InputReader::processEventsForDeviceLocked
这个函数是真正处理输入事件的地方
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
size_t count)
// 先找到产生事件的device
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()) // 如果device是ignored, 不需处理
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
// 接下来device进行处理
device->process(rawEvents, count);
InputDevice::process
/// @frameworks/native/services/inputflinger/reader/InputDevice.cpp
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) // 处理drop事件
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT)
mDropUntilNextSync = false;
ALOGD("Recovered from input event buffer overrun.");
else
ALOGD("Dropped input event while waiting for next input sync.");
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); // 交给具体的InputMapper处理
);
--count;
for_each_mapper_in_subdevice 方法是遍历取出 InputMapper, 然后执行相关方法. 结合上面的代码, 实际的操作就是遍历所有InputMapper并执行其process方法.
// 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);
KeyboardInputMapper#process
对于键盘设备而言, 对应的 InputMapper 是KeyboardInputMapper, 它的process方法如下:
/// @frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
void KeyboardInputMapper::process(const RawEvent* rawEvent)
switch (rawEvent->type)
case EV_KEY: // key 事件
int32_t scanCode = rawEvent->code; // 键盘扫描码, 与Android的键值有一个映射关系
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode))
// 按下value值是1
processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode); // 处理 key 事件
break;
...
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;
// 将scanCode与Android中的keyCode做一个映射. 比如POWER KEY的扫描码是116 , 而在Android的KeyEvent中的定义是26
if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
&policyFlags))
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
if (down) // 按下事件
// Rotate key codes according to orientation if needed.
if (mParameters.orientationAware)
keyCode = rotateKeyCode(keyCode, getOrientation());
// Add key down.
ssize_t keyDownIndex = findKeyDown(scanCode); // 根据 scanCode 查找是否已经存储过
if (keyDownIndex >= 0) // 查到,说明是一个键的重复事件,确保keyCode一致
// key repeat, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[keyDownIndex].keyCode;
else // 否则是初始Down
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
getContext()->shouldDropVirtualKey(when, keyCode, scanCode))
return;
if (policyFlags & POLICY_FLAG_GESTURE)
getDeviceContext().cancelTouch(when);
KeyDown keyDown;
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
mKeyDowns.push_back(keyDown); // 存储
mDownTime = when;
else
// Remove key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) // 查到, 则此时发生的是up事件. 确保keyCode与之前一致, 键盘方向旋转可能导致键值变化
// key up, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[keyDownIndex].keyCode;
mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
else // 之前没有发生Down事件,则直接返回
// key was not actually down
ALOGI("Dropping key up from device %s because the key was not down. "
"keyCode=%d, scanCode=%d",
getDeviceName().c_str(), keyCode, scanCode);
return;
if (updateMetaStateIfNeeded(keyCode, down)) // 更新metaState, 其描述了功能键的按下状态,如Ctrl按下
// If global meta state changed send it along with the key.
// If it has not changed then we'll use what keymap gave us,
// since key replacement logic might temporarily reset a few
// meta bits for given key.
keyMetaState = mMetaState;
nsecs_t downTime = mDownTime;
// Key down on external an keyboard should wake the device.
// We don't do this for internal keyboards to prevent them from waking up in your pocket.
// For internal keyboards and devices for which the default wake behavior is explicitly
// prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
// wake key individually.
// TODO: Use the input device configuration to control this behavior more finely.
if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
!isMediaKey(keyCode)) // 是否要唤醒
policyFlags |= POLICY_FLAG_WAKE;
if (mParameters.handlesKeyRepeat) // 处理 key repeat
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
// 封装key事件到NotifyKeyArgs
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); // 此处实际调用了QueuedInputListener的notifyKey, 将args添加到它的队列中.
QueuedInputListener::notifyKey
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args)
traceEvent(__func__, args->id);
mArgsQueue.push_back(new NotifyKeyArgs(*args)); //将key事件信息添加到mArgsQueue
再次回到 InputReader::loopOnce , 当通过 processEventsForDeviceLocked 对原始事件进行加工处理后, 会将事件信息都缓存到 QueuedInputListener 的 mArgsQueue, 在方法最后通过mQueuedListener->flush()去真正的将事件投递到InputDispatcher,并清空队列.
QueuedInputListener#flush
void QueuedInputListener::flush()
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++)
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener); // 调用args的notify方法
delete args;
mArgsQueue.clear();
此处的mInnerListener是创建QueuedInputListener时传入的listener,即是创建InputReader时传入的InputClassifier对象.
对于key事件,调用的是NotifyKeyArgs::notify
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& l以上是关于Android R input 之 InputReader 工作流程的主要内容,如果未能解决你的问题,请参考以下文章
Android R input 之 InputChannel之发送事件处理反馈
Android R input 之 InputChannel之发送事件处理反馈
Android R input 之 InputDispatcher 工作流程
Android R input 之 InputDispatcher 工作流程