EventHub:从内核设备到原始事件
EventHub:从内核设备到原始事件
上一章建立了输入主链。这一章进入第一段,回答:内核的输入事件是怎么被系统读出来的, getevent 看到的数据到底长什么样?
EventHub 面向的是 /dev/input/eventX 和内核 input_event,不是 Android 的 MotionEvent。它负责发现设备、读取事件和报告设备变化,不解释触摸手势,也不选择接收窗口。
getevent 看到的不是 MotionEvent
| 常见误解 | 正确理解 |
|---|---|
| 输入事件由 IMS 主动“轮询内核” | EventHub 阻塞读 /dev/input/eventX,内核有事件时唤醒 |
getevent 看到的就是 Android 的触摸事件 | 它是内核原始事件,还没有变成 MotionEvent |
| 设备是静态的,打开一次就行 | 设备可热插拔,EventHub 用 inotify 监听增删并重新扫描 |
触摸屏一次动作通常对应多条 type、code、value 记录,并以同步事件划分报告边界。EventHub 通过 epoll 等待设备节点,通过 inotify 处理热插拔,再把批量原始记录交给 InputReader。
核心结论
- EventHub 扫描
/dev/input/eventX打开设备,并用 inotify 监听设备增删。 - 原始事件是
input_event结构:type(事件类型)、code(按键/轴编号)、value(数值)。 - EventHub 通过
getEvents()批量返回原始事件与设备变化,阻塞等待内核事件。 - 设备打开时会读取设备能力(按键表、触摸参数等),为后续加工做准备。
getevent命令直接展示这些原始事件,是验证“硬件有没有上报”的第一现场。
读取主链
逐步解释:
- 设备扫描:EventHub 启动时扫描
/dev/input/,逐个打开eventX并读取设备能力。 - 设备监听:inotify 监视目录变化,插入或拔出设备时触发重新扫描。
- 阻塞读取:
getEvents()在read系统调用上等待,内核有事件时批量返回。 - 交给加工:原始事件连同设备信息交给 InputReader 做下一步处理。
原始事件长什么样
一次触摸按压,内核可能上报多个 input_event,例如触摸屏的 ABS 轴事件(坐标)与 BTN_TOUCH(按下)。getevent -lt 会打印时间戳、设备、type/code 与 value:
[ 123.456789] /dev/input/event2: EV_ABS ABS_MT_POSITION_X 000002f4
[ 123.456789] /dev/input/event2: EV_ABS ABS_MT_POSITION_Y 000004b2
[ 123.456789] /dev/input/event2: EV_KEY BTN_TOUCH DOWN
[ 123.456789] /dev/input/event2: EV_SYN SYN_REPORT 00000000SYN_REPORT 表示一批事件结束,InputReader 以它为边界把一组原始事件组织成一次完整输入。 触摸位置此时还是设备坐标,距离屏幕坐标还差一层变换(见 InputReader 章节)。
源码证据
阅读目标:确认设备打开与事件读取的入口。
正文指针:EventHub.cpp scanDevicesLocked()/openDeviceLocked()/getEvents(); 内核输入子系统提供 /dev/input/eventX。
// EventHub.cpp(伪代码,行号以 r75 为准)
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
// 阻塞读取 input_event,转成 RawEvent 返回
}
int EventHub::openDeviceLocked(const char* devicePath) {
// open /dev/input/eventX,读取设备能力
}这段代码证明: getEvents() 是 EventHub 与内核之间的唯一读取口;openDeviceLocked() 负责建立设备句柄并记录能力。InputReader 每轮循环都从这里拿原始事件。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell getevent -lt
adb shell cat /proc/bus/input/devices
adb shell ls -l /dev/input/getevent -lt 实时打印所有输入设备事件;/proc/bus/input/devices 列出内核注册的设备 与能力;/dev/input/ 确认设备节点。触摸失灵时先在这里确认“硬件层到底有没有事件”: 有事件说明问题在后段,没有事件说明问题在设备、驱动或节点权限。
常见误区
- “
getevent看到的就是应用收到的坐标”:原始坐标还要经过变换与加工。 - “设备节点固定是 event0”:节点编号由内核分配,不同设备可能变化。
- “EventHub 会解释事件含义”:它只读取和缓存,分类与加工在 InputReader。
- “拔插设备 EventHub 不知道”:inotify 监听会触发重新扫描。
延伸问题
getevent -lt与-c、-p参数分别查看什么?- 设备能力(
ABS_*轴、按键位图)在 EventHub 里如何保存? - inotify 事件与设备扫描的竞态如何处理?
- 为什么说
SYN_REPORT是“一批事件”的边界?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
EventHub.cpp | scanDevicesLocked() | 扫描设备目录 |
EventHub.cpp | openDeviceLocked() | 打开设备并读取能力 |
EventHub.cpp | getEvents() | 阻塞读取原始事件 |
EventHub.cpp | readNotifyLocked() | 处理 inotify 设备变化 |
公共路径:frameworks/base/services/inputflinger/reader/。行号以 r75 检索为准。
原始记录如何变成统一输入事件,见 InputReader。