第四板块:Android 输入系统与触控事件 | 第十五篇:InputReader 与 InputDispatcher 的触控流水线
所属板块:第四板块 — Android 输入系统与触控事件
前置知识:第十三篇中的 SurfaceFlinger 合成机制、VSYNC 信号、第十四篇中的 RenderThread 渲染流程
本篇定位:这是 Android 交互系统的神经末梢。如果说图形渲染是视觉,那么输入系统就是触觉。本篇将彻底拆解 Linux 输入子系统(evdev)、InputReader 的原始事件解析、InputDispatcher 的投递策略、ANR 的超时机制、Touch 事件的预测与插值。我们将深入 System Server 的输入模块,揭示从手指触摸屏幕到应用收到 MotionEvent 的完整链路。
1. 核心结论先行(Thesis Statement)
Android 的输入系统是一个事件驱动的生产者-消费者模型。
- InputReader 的本质:原始数据翻译官。它运行在 System Server 的独立线程中,不断从
/dev/input/eventX节点读取二进制数据,将其翻译成 Android 定义的 InputEvent(如 KeyEvent, MotionEvent)。 - InputDispatcher 的本质:交通警察。它维护着一个 Inbound Queue(待处理队列)和一个 Outbound Queue(待发送队列),根据窗口的焦点状态和 Z-order,决定将事件发给哪个应用进程。
- ANR 的本质:超时惩罚。如果应用进程在 5 秒内没有处理完 Input 事件,InputDispatcher 会向 AMS 报告,触发 ANR 弹窗。
- 事件同步:输入事件必须与 VSYNC 信号同步,否则会出现点击与画面不同步的现象。
2. 输入系统的全链路架构
2.1 从硬件中断到应用回调
graph TB
subgraph Hardware ["硬件层"]
Touch["触摸屏"]
IRQ["硬件中断 (IRQ)"]
end
subgraph Kernel ["Linux 内核"]
Driver["Input Driver (evdev)"]
Node["/dev/input/event0"]
end
subgraph SystemServer ["System Server 进程"]
Reader["InputReader 线程"]
Dispatcher["InputDispatcher 线程"]
Policy["InputPolicy (PhoneWindowManager)"]
end
subgraph AppProc ["应用进程"]
ViewRoot["ViewRootImpl"]
DecorView["DecorView"]
View["View"]
end
Touch -->|"触摸"| IRQ
IRQ -->|"中断处理"| Driver
Driver -->|"写入"| Node
Node -->|"poll()"| Reader
Reader -->|"翻译事件"| Dispatcher
Dispatcher -->|"策略拦截"| Policy
Policy -->|"确认"| Dispatcher
Dispatcher -->|"Binder IPC"| ViewRoot
ViewRoot -->|"dispatchInputEvent()"| DecorView
DecorView -->|"onTouchEvent()"| View
2.2 核心角色职责表
| 角色 | 运行进程 | 职责 |
|---|---|---|
| Input Driver | Linux Kernel | 将物理触摸转换为二进制数据流,写入设备节点。 |
| InputReader | System Server | 读取设备节点,解析原始数据,生成 InputEvent。 |
| InputDispatcher | System Server | 管理窗口焦点,分发 InputEvent 到目标进程。 |
| ViewRootImpl | 应用进程 | 接收系统事件,分发到 View 树。 |
3. InputReader:原始数据的解析
3.1 Linux evdev 协议
触摸屏在 Linux 中被视为一个 Character Device。
学术定义:
- 设备节点:
/dev/input/event0,event1... - 事件结构:
struct input_event { timeval time; unsigned short type; unsigned short code; unsigned int value; } - 事件类型:
EV_KEY: 按键事件(电源键、音量键)。EV_ABS: 绝对坐标事件(触摸屏的 X/Y 轴)。EV_SYN: 同步事件(表示一次输入结束)。
3.2 InputReader 的读取循环
InputReader 使用 epoll 监听多个设备节点。
// frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::loopOnce() {
// 1. 使用 epoll_wait 等待设备节点可读
int pollResult = epoll_wait(mEpollFd, mPendingEvents, EPOLL_MAX_EVENTS, -1);
// 2. 遍历所有可读的设备
for (int i = 0; i < pollResult; i++) {
int fd = mPendingEvents[i].data.fd;
// 3. 读取 raw_event
RawEvent rawEvent;
read(fd, &rawEvent, sizeof(rawEvent));
// 4. 处理 raw_event
processEvent(fd, &rawEvent);
}
// 5. 将处理后的事件发送给 Dispatcher
flush();
}
3.3 触摸屏事件的解析
以触摸屏为例,一次点击会产生一系列事件:
| 时间戳 | 类型 (Type) | 代码 (Code) | 值 (Value) | 含义 |
|---|---|---|---|---|
| t0 | EV_ABS | ABS_MT_TRACKING_ID | 0 | 手指按下,ID=0 |
| t0 | EV_ABS | ABS_MT_POSITION_X | 150 | X 坐标=150 |
| t0 | EV_ABS | ABS_MT_POSITION_Y | 300 | Y 坐标=300 |
| t0 | EV_SYN | SYN_REPORT | 0 | 同步(本次输入结束) |
| t1 | EV_ABS | ABS_MT_POSITION_X | 151 | 手指移动 |
| t2 | EV_ABS | ABS_MT_TRACKING_ID | -1 | 手指抬起 |
学术定义:
- Slot (槽位):多点触控时,每个手指对应一个 Slot。
- Tracking ID:手指的唯一标识,按下时分配,抬起时置为 -1。
4. InputDispatcher:事件的投递与 ANR
4.1 窗口管理与焦点
InputDispatcher 需要知道当前哪个窗口拥有焦点。
学术定义:
- Focus Window: 当前接收按键和触摸事件的窗口。
- Touch Window: 触摸事件发生区域的窗口(可能是多个,如壁纸和应用窗口)。
- Z-order: 窗口的层级,决定事件的派发顺序。
4.2 事件分发流程
sequenceDiagram
participant Reader as InputReader
participant Dispatcher as InputDispatcher
participant AMS as ActivityManagerService
participant App as 应用进程
Reader->>Dispatcher: notifyMotion()
Dispatcher->>Dispatcher: 查找 Focus Window
Dispatcher->>Dispatcher: 检查窗口是否就绪
alt 窗口未就绪或超时
Dispatcher->>AMS: notifyANR()
AMS->>App: 弹出 ANR 弹窗
else 窗口就绪
Dispatcher->>App: dispatchMotionEvent() (Binder IPC)
App->>App: 处理事件
App->>Dispatcher: finishedInputEvent() (Binder IPC)
end
4.3 ANR 机制(5秒超时)
InputDispatcher 维护一个 Wait Queue。
学术定义:
- 分发时间戳:
dispatchStartedTime。 - 超时阈值:5 秒(按键)/ 5 秒(触摸)。
- ANR 触发条件:事件发出后 5 秒内没有收到
finishedInputEvent()回调。
5. 输入事件与 VSYNC 的同步
5.1 为什么需要同步?
如果输入事件处理过快,而屏幕刷新慢,会导致点击位置与画面不一致。
学术定义:
- Input-VSYNC Alignment: 输入事件的处理应该与 VSYNC 信号对齐。
- Prediction (预测): 根据历史轨迹,预测手指在下一帧的位置,减少感知延迟。
5.2 Choreographer 的介入
应用进程收到输入事件后,会交给 Choreographer 处理。
// ViewRootImpl.java
public void dispatchInputEvent(InputEvent event) {
// 将事件交给 Choreographer
mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mInputEventReceiver, event);
}
6. 多点触控与手势
6.1 触摸事件的封装(MotionEvent)
系统将原始事件封装为 MotionEvent。
| 属性 | 含义 |
|---|---|
getActionMasked() | 动作类型(DOWN, MOVE, UP, POINTER_DOWN, POINTER_UP) |
getPointerCount() | 触点数量 |
getX(int pointerIndex) | 第 N 个触点的 X 坐标 |
getHistoricalX() | 历史坐标(用于平滑) |
6.2 手势识别
手势识别发生在应用进程,但系统提供了辅助类。
学术定义:
- GestureDetector: 识别单击、双击、长按。
- ScaleGestureDetector: 识别缩放手势。
- VelocityTracker: 计算滑动速度。
7. 关键源码解析
7.1 InputDispatcher 的分发逻辑
// frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
// 1. 从 InboundQueue 取出事件
EventEntry* eventEntry = mInboundQueue.head;
// 2. 查找目标窗口
sp<InputWindowHandle> windowHandle = findFocusedWindow(eventEntry);
// 3. 将事件放入 OutboundQueue
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, windowHandle);
mOutboundQueue.enqueueAtTail(dispatchEntry);
// 4. 通过 Binder 发送
status_t status = windowHandle->inputChannel->sendMessage(&message);
}
7.2 ViewRootImpl 的事件接收
// ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
@Override
public void onInputEvent(InputEvent event) {
// 1. 将 InputEvent 包装为 QueuedInputEvent
QueuedInputEvent q = obtainQueuedInputEvent(event);
// 2. 放入队列
mPendingInputEventQueue.enqueue(q);
// 3. 处理队列
doProcessInputEvents();
}
}
8. 输入系统的性能瓶颈
8.1 常见卡顿原因
| 原因 | 学术解释 |
|---|---|
| InputReader 慢 | 设备节点读取阻塞,或触摸采样率过低。 |
| InputDispatcher 慢 | 窗口焦点计算复杂,或 Wait Queue 堆积。 |
| 应用处理慢 | UI 线程在 onTouchEvent() 中执行耗时操作,导致 ANR。 |
| VSYNC 不同步 | 输入事件处理与屏幕刷新不同步,导致视觉滞后。 |
8.2 系统优化手段
| 手段 | 学术定义 |
|---|---|
| Batch (批处理) | 将连续的 MOVE 事件合并,减少 IPC 次数。 |
| Resample (重采样) | 根据历史数据预测位置,平滑轨迹。 |
| Throttle (节流) | 当应用处理不过来时,丢弃部分 MOVE 事件。 |
9. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| InputReader 的本质 | 原始数据翻译官,将 evdev 二进制流转换为 InputEvent。 |
| InputDispatcher 的本质 | 交通警察,根据窗口焦点和 Z-order 分发事件。 |
| ANR 机制 | 5 秒超时惩罚,确保系统响应性。 |
| VSYNC 同步 | 输入事件处理与屏幕刷新对齐,保证视觉一致性。 |
| 事件流 | 硬件中断 -> 内核驱动 -> InputReader -> InputDispatcher -> 应用进程 -> View 树。 |
下一篇预告:第四板块:Android 输入系统与触控事件 | 第十六篇:按键分发与软键盘(IME)的窗口协同