Android InputManagerService

发布于:2025-09-06 ⋅ 阅读:(22) ⋅ 点赞:(0)

整个流程可以概括为以下核心架构图,它展示了输入事件的数据流和核心组件:

第一阶段:内核空间 - /dev/input/eventX

  1. 硬件中断:当用户触摸屏幕、按下物理按键或移动鼠标时,硬件设备(触摸屏、键盘控制器等)会产生一个硬件中断(IRQ)
  2. 设备驱动:对应的输入设备驱动会处理这个中断,将原始的硬件信号(如触摸点的X、Y坐标、按键码、压力值等)封装成一个标准格式的数据结构(struct input_event
    struct input_event {
        struct timeval time; // 时间戳
        __u16 type;          // 事件类型 (e.g., EV_KEY, EV_ABS, EV_SYN)
        __u16 code;          // 事件代码 (e.g., BTN_TOUCH, ABS_X, KEY_VOLUMEDOWN)
        __s32 value;         // 事件值 (e.g., 坐标值, 0/1表示按下/松开)
    };
  3. 写入设备节点:驱动将这个 input_event 写入到对应的 /dev/input/eventX (X通常是数字,如event0)字符设备节点中。这个节点是内核空间与用户空间进行交互的接口

第二阶段:用户空间 - EventHub 和 InputReader

这两个组件在 system_server 进程中,是 InputManagerService 的核心组成部分

1. EventHub

  • 职责监控和读取所有 /dev/input/ 目录下的输入设备节点。它是硬件事件的直接来源
  • 工作机制
    ○ 使用 inotify 监控 /dev/input/ 目录,以便在设备热插拔(如USB键盘插入拔出)时动态添加或移除设备
    ○ 使用 epoll 机制轮询所有已打开的输入设备节点。当某个设备有数据可读时(即用户有输入动作),epoll 会通知 EventHub
    ○ EventHub 从对应的设备节点中读出原始的 input_event 数据,并将其简单封装为一个 RawEvent 对象
    ○ InputReader 线程会不断地从 EventHub 中 getEvents(),获取这些 RawEvent 队列

2. InputReader

  • 职责解析和加工 RawEvent。它是理解输入事件含义的“翻译官”
  • 工作机制
    ○ 它运行在一个独立的线程(InputReader Thread)中,不断循环调用 EventHub->getEvents(),拿到一揽子 RawEvent
    ○ 它持有所有输入设备的配置信息(InputDevice),如键盘布局、触摸屏校准参数、按键映射等
    ○ 根据 RawEvent 的 type 和 code将多个连续的原始事件组合成一个有逻辑意义的输入事件
        ◎ 例如
    :一个触摸操作通常会产生多个 RawEvent:一个 EV_ABS (ABS_X) 事件报告X坐标,一个 EV_ABS (ABS_Y) 事件报告Y坐标,一个 EV_KEY (BTN_TOUCH) 事件报告按下状态,最后是一个 EV_SYN (SYN_REPORT) 事件表示报告结束。InputReader 会等待 SYN_REPORT 到来后,才认为一个完整的触摸点数据准备好了
    ○ 加工完成后,InputReader 会生成更高级的、Android框架定义的事件对象,如 KeyEvent(按键事件)、MotionEvent(触摸/运动事件)
    ○ 策略处理:在这个过程中,它会应用一些输入策略,如:
        ◎ 设备映射:将游戏手柄的某个按键映射为“返回”键
        ◎ 输入校准:对触摸屏坐标进行校准
        ◎ 虚拟键处理:处理一些设备的电容导航键
    ○ 最后,InputReader 调用 InputDispatcher->notifyXXX() 方法,将加工好的事件放入 InputDispatcher 的队列中

第三阶段:用户空间 - InputDispatcher

  • 职责事件的派发和仲裁。它是输入事件的“交通警察”,决定事件最终发给哪个应用窗口
  • 工作机制
    ○ 它运行在另一个独立的线程(InputDispatcher Thread)中
    ○ 它维护了一个来自 InputReader 的输入事件队列
    ○ 寻找目标窗口:当一个新事件到来时,InputDispatcher 会根据当前系统的状态(哪些窗口是活动的、它们的布局位置、焦点状态等)来计算事件应该派发给哪个窗口(WindowState
        ◎ 焦点窗口:按键事件通常派发给当前获得焦点的窗口(如输入框)
        ◎ 触摸命中测试:触摸事件会根据窗体的位置和触摸点坐标进行命中测试(Hit Test)InputDispatcher 会向 WindowManagerService (WMS) 查询,找到包含该坐标点的、最顶层的、可见的窗口
    ○ 应用策略:在此阶段,会应用一些系统策略,如:
        ◎ 输入超时:防止应用ANR(Application Not Responding)。如果窗口在5秒内没有处理完一个输入事件,系统会弹出ANR对话框
        ◎ 事件过滤:过滤掉一些系统级快捷键(如Power键、Volume键),这些事件可能会被系统优先消费
        ◎ 虚拟键处理:Home、Back、Recents键的处理逻辑
    ○ 派发事件
        ◎ 目标窗口确定后,InputDispatcher 会通过 SocketPair(一个双向的IPC通道)将事件发送到目标窗口所在的应用进程
        ◎ 派发是异步的。InputDispatcher 会等待应用处理完毕的“反馈”(finishInputEvent
        ◎ 如果事件是按键事件(如Back键),InputDispatcher 会先执行一个 “预派发” (Pre-dispatching)流程,将事件先发给当前焦点View,如果它处理了,流程结束;如果没处理,再继续正常的派发流程,可能会最终交给Activity处理

第四阶段:应用进程 - 从 ViewRootImpl 到 View

事件现在离开了 system_server,进入了目标应用进程

  1. Socket监听与接收
    ○ 每个应用的UI主线程都通过 Looper 监听一个特殊的 InputChannel (它封装了SocketPair
    ○ 当 InputDispatcher 将事件写入Socket后,应用端的 InputChannel 就会收到通知
  2. ViewRootImpl$WindowInputEventReceiver
    ○ 在应用端,ViewRootImpl 内部的 WindowInputEventReceiver 的 onInputEvent() 方法被调用,它接收到了原始的输入事件
  3. InputEventReceiver 和 InputStage
    ○ ViewRootImpl 内部有一个 InputStage 责任链模式的处理管道。事件会依次经过不同的 InputStage,每个阶段都有机会处理或消费事件
    ○ 阶段示例
        ◎ NativePreImeStage:处理本地预输入法事件(如手柄按键)
        ◎ ViewPreImeStage:View树的预输入法阶段
        ◎ ImeStage将事件派发给输入法(IME)。如果当前有输入法窗口,按键事件会先到这里。输入法可以消费掉事件(如输入文字),也可以选择不消费并让事件继续传递(如按下的方向键)
        ◎ EarlyPostImeStage:早期后输入法阶段,处理一些原始事件
        ◎ ViewPostImeStage这是最关键的一步。在这里,事件被封装成Java层的 KeyEvent 或 MotionEvent,并开始进入View树的分发流程
  4. View树分发
    ○ 起点:分发从 DecorView(根View)的 dispatchPointerEvent() 开始
    ○ 传递路径DecorView -> PhoneWindow -> ContentView (通常是FrameLayout) -> ... -> 最终的目标View
    ○ 分发规则
        ◎ 触摸事件 (MotionEvent):遵循 onInterceptTouchEvent 和 onTouchEvent 的机制。从父View到子View传递,父View可以拦截(onInterceptTouchEvent返回true),子View可以消费(onTouchEvent返回true)
        ◎ 按键事件 (KeyEvent):从子View到父View传递。首先会尝试分发给当前获得焦点的View,如果它没有消费,则会依次向上传递给它的父View
  5. 事件消费与反馈
    ○ 当事件被View树中的某个View的 onTouchEvent 或 onKeyEvent 方法处理(返回 true)后,处理流程结束
    ○ 反馈:处理完成后,会沿着原路返回一个“完成”的信号(finishInputEvent),通过 InputChannel 和SocketPair最终回传给 InputDispatcher
    ○ InputDispatcher 收到反馈后,才会继续派发下一个输入事件。如果超时未收到反馈,就会触发ANR

总结与特点

  • 生产者-消费者模型InputReader 是生产者,不断生产事件;InputDispatcher 是消费者和二次生产者;应用是最终的消费者
  • 多线程设计InputReader 和 InputDispatcher 是两个独立的线程,避免了事件读取阻塞事件派发
  • 异步非阻塞:派发过程是异步的,通过SocketPair进行IPC,效率高
  • 中心化仲裁InputDispatcher 和 WindowManagerService 协同工作,是输入事件的唯一仲裁中心,确保了系统级策略的统一应用
  • ANR机制:超时机制保证了系统的响应性

网站公告

今日签到

点亮在社区的每一天
去签到