3. Android输入子系统基础
在车载 Android 系统中,触摸屏、物理按键、旋钮、方向盘按键、红外遥控等输入设备最终都要经过 Android 原生输入子系统,才能变成应用可消费的 MotionEvent 或 KeyEvent。理解 InputManagerService、EventHub、InputReader、InputDispatcher 四个核心组件及其数据流,是后续做 CarInputService 定制、按键映射、焦点策略、输入注入与排障的基础。
一、核心组件与职责边界
Android 输入子系统运行在 system_server 进程中,由 Native 层与 Java 层共同组成。Java 层的入口是 InputManagerService(IMS),它负责生命周期管理、与 WindowManagerService 协作、向应用分发策略配置;Native 层则由 InputManager、InputReader、InputDispatcher、EventHub 构成实际的数据处理管线。
- EventHub:直接通过
epoll监听/dev/input/下的设备节点,读取原始input_event,并负责设备热插拔的发现与移除。 - InputReader:从 EventHub 取出原始事件,结合设备能力(
InputDevice、InputMapper)做协议解析、坐标变换、去抖、多点触控合成,输出标准化的NotifyMotionArgs/NotifyKeyArgs。 - InputDispatcher:接收 InputReader 的标准化事件,结合窗口焦点、触摸目标、ANR 超时、输入通道(InputChannel)状态,决定把事件投递给哪个窗口。
- InputManagerService:Java 层门面,负责启动 Native 输入线程、注册输入设备监听、处理
monitorInput、注入事件、与 WMS 同步焦点窗口。
二、输入事件完整数据流
下面这张图展示了从硬件中断到应用回调的完整链路,也是本节最需要建立的整体心智模型。
三、关键参数与线程模型
InputReader 与 InputDispatcher 各自运行在独立线程中,通过 InputListener 接口解耦。InputReader 线程负责阻塞读取 EventHub,InputDispatcher 线程负责分发与超时监控。两者通过 mInboundQueue 传递事件,避免读设备被分发阻塞拖慢。
| 组件 | 所在线程 | 核心输入 | 核心输出 | 典型排障点 |
|---|---|---|---|---|
| EventHub | InputReader 线程 | /dev/input/eventX | RawEvent | 设备节点权限、热插拔丢失 |
| InputReader | InputReader 线程 | RawEvent + 设备能力 | NotifyArgs | 坐标错乱、按键码不识别 |
| InputDispatcher | InputDispatcher 线程 | NotifyArgs + 焦点窗口 | InputChannel 投递 | ANR、焦点窗口为空、通道阻塞 |
| InputManagerService | system_server 主线程 | 系统调用 / WMS 回调 | 服务接口 | 注入失败、监听未注册 |
四、车载场景案例:旋钮事件如何到达应用
假设车机有一个旋钮,硬件上报 EV_KEY / KEY_VOLUMEUP。EventHub 读取后交给 InputReader,InputReader 通过 KeyboardInputMapper 生成 NotifyKeyArgs。InputDispatcher 根据当前焦点窗口决定投递目标。如果应用未处理,事件会继续冒泡到 PhoneWindowManager 或 CarInputService 的拦截逻辑。
// 查看输入设备与事件节点
adb shell getevent -lp /dev/input/event2
// 实时观察原始事件
adb shell getevent -lt /dev/input/event2
// 查看输入设备列表
adb shell dumpsys input | grep -A 5 "Input Devices"
// 查看分发器状态与焦点窗口
adb shell dumpsys input | grep -A 20 "Input Dispatcher State"
KEYCODE_DPAD_* 或自定义按键码。若应用收不到事件,先用 getevent 确认内核层有上报,再用 dumpsys input 确认 InputReader 是否识别,最后检查焦点窗口与 InputChannel 是否正常。
五、常见误区与复盘
- 误区一:把 IMS 当成事件处理核心。IMS 只是门面,真正解析与分发在 Native 层,排障要看 InputReader / InputDispatcher 日志。
- 误区二:忽略设备能力配置。如果
.idc或kl文件缺失,InputReader 无法正确映射按键码,表现为“设备存在但无事件”。 - 误区三:焦点窗口为空仍期待应用收到事件。InputDispatcher 必须有有效焦点窗口或触摸目标,否则事件会被丢弃或触发 ANR。
- 误区四:在应用层做全局按键拦截。车载全局按键应优先在 CarInputService 或 InputDispatcher 策略层处理,避免多应用竞争。
getevent 有输出只代表 EventHub 能读到;dumpsys input 中 RecentQueue 有记录才代表 InputReader 已解析;应用收到回调才代表 InputDispatcher 投递成功。三层逐一确认,才能快速定位问题层级。