第四板块:Android 输入系统与触控事件 | 第十五篇:InputReader 与 InputDispatcher 的触控流水线

37 阅读6分钟

第四板块: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 DriverLinux Kernel将物理触摸转换为二进制数据流,写入设备节点。
InputReaderSystem Server读取设备节点,解析原始数据,生成 InputEvent。
InputDispatcherSystem 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)含义
t0EV_ABSABS_MT_TRACKING_ID0手指按下,ID=0
t0EV_ABSABS_MT_POSITION_X150X 坐标=150
t0EV_ABSABS_MT_POSITION_Y300Y 坐标=300
t0EV_SYNSYN_REPORT0同步(本次输入结束)
t1EV_ABSABS_MT_POSITION_X151手指移动
t2EV_ABSABS_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)的窗口协同