Android Framework中Input事件的传递流程

Table of Contents

以下是 Android Framework 中 Input 事件传递流程说明,聚焦硬件层、系统服务层和应用进程层的关键组件与流程

1. 硬件层 & Linux 内核

关键组件与流程

  1. 硬件中断

    • 定义:用户触摸屏幕、按下物理按键或移动鼠标时,硬件设备(如触摸屏控制器、键盘驱动)会触发电子信号,生成硬件中断
    • 作用:通知 CPU 有输入事件需要处理,中断当前任务,优先处理输入事件。
  2. 内核驱动(如evdev

    • 角色:Linux 内核中的输入设备驱动(如evdev)负责将硬件中断转换为标准输入事件
    • 数据格式:事件包含原始信息,例如:
      • 触摸事件:坐标(X/Y)、压力值、时间戳。
      • 按键事件:按键码(KeyCode)、按下/释放状态。
    • 写入节点:驱动将事件写入/dev/input/eventX(X 为设备编号)字符设备节点,供用户空间程序读取。
  3. /dev/input节点

    • 功能:Linux 内核通过虚拟文件系统(如sysfsdevfs)暴露输入设备的接口。
    • 多设备管理:每个物理输入设备(如触摸屏、物理键盘)对应一个独立的/dev/input/eventX节点。

2. 系统服务层(Native 层)

关键组件与流程

  1. EventHub

    • 作用:监听/dev/input目录下的设备节点,管理输入设备的增删(如 USB 设备热插拔)。
    • 实现机制
      • 使用epollinotify监控设备节点变化。
      • 读取设备的配置信息(如屏幕分辨率、按键映射)。
  2. InputReader

    • 线程模型:运行在SystemServer进程中的独立线程,负责持续从EventHub读取原始事件。
    • 事件解析
      • 将原始数据转换为 Android 标准事件对象(如MotionEventKeyEvent)。
      • 处理设备校准、坐标转换(如将物理坐标转换为屏幕逻辑坐标)。
    • 输出:解析后的事件发送给InputDispatcher
  3. InputDispatcher

    • 核心职责:将事件分发给正确的应用窗口。
    • 关键流程
      1. 确定目标窗口
        • 调用WindowManagerService (WMS),根据窗口的 Z-order、可见性、焦点状态,选择当前接收输入的窗口(如前台 Activity 的根视图)。
      2. 事件策略处理
        • ANR 检测:若应用 5 秒内未处理完事件,触发Application Not Responding (ANR)错误。
        • 输入过滤:根据系统策略丢弃无效事件(如防误触算法过滤边缘触摸)。
      3. 跨进程通信
        • 通过InputChannel将事件发送到目标应用进程。每个窗口对应一个InputChannel,本质上是基于Socket共享内存的 IPC 机制。
  4. InputChannel

    • 实现原理
      • 服务端InputDispatcher持有InputChannel的服务端,负责写入事件。
      • 客户端:应用进程通过ViewRootImpl注册InputChannel的客户端,用于接收事件。
    • 性能优化:使用共享内存(ashmem)减少数据拷贝开销。

3. 应用进程层

关键组件与流程

  1. ViewRootImpl

    • 角色:连接应用窗口与系统服务的桥梁,每个窗口(如 Activity、Dialog)对应一个ViewRootImpl实例。
    • 初始化InputChannel:在窗口创建时,通过WindowManagerGlobal与系统服务协商建立InputChannel
  2. WindowInputEventReceiver

    • 继承关系:继承自InputEventReceiver,负责监听InputChannel的事件。
    • 事件接收
      1. InputChannel读取事件(底层通过Looper监听文件描述符的可读状态)。
      2. 将事件封装为InputEvent对象(如MotionEvent)。
  3. 主线程事件处理

    • 线程切换:通过Handler将事件包装为Message,发送到主线程的MessageQueue
    • 执行逻辑:主线程的LooperMessageQueue取出事件,调用ViewRootImpldispatchInputEvent()方法,开始 View 层级分发。

关键流程总结

  1. 硬件到内核

    硬件中断 → 内核驱动 → /dev/input节点
    
  2. 系统服务处理

    InputReader(读取&解析) → InputDispatcher(确定目标&分发) → InputChannel(跨进程)
    
  3. 应用进程接收

    InputChannel → ViewRootImpl → 主线程Handler → View层级分发
    

深度问答

  • Q1: 为什么需要EventHub
    A1: 直接操作/dev/input节点需处理设备热插拔、多设备并发等问题,EventHub封装了这些复杂性,提供统一的事件监听接口。

  • Q2: InputDispatcher如何避免事件被错误分发?
    A2: 通过 WMS 实时获取窗口状态(如焦点窗口、可见性),仅将事件发送给符合条件的窗口,并在窗口失去焦点时终止后续事件。

  • Q3: InputChannel为何选择 Socket 或共享内存?
    A3: Socket 通用性强,共享内存性能更高。Android 根据不同场景选择:按键事件多用 Socket(低频率),触摸事件可能用共享内存(高吞吐量)。

通过以上流程,Android 实现了从硬件输入到应用响应的完整链路,确保高效、可靠的事件传递。

明天了解一下文中提到的 Linux 驱动究竟是个什么东西