输入事件的源头位于/dev/input/下的设备节点,输入事件的终点是WMS管理的某个窗口。所以输入系统的主要工作是读取设备节点中的原始事件,接着进行加工封装,然后派发给一个特定的窗口或者窗口中的控件。整个流程由InputManagerService系统服务为核心的多个参与者共同完成,如下图所示。
流程大致为:
- 内核将原始事件写入设备节点
- InputReader不断地通过EventHub将原始事件取出来并翻译加工成Android输入事件,然后交给InputDispather
- InputDispather根据WMS提供的窗口信息将事件交给合适的窗口
- 窗口的ViewRootImpl对象再沿着控件树将事件派发给感兴趣的控件
- 控件对齐收到的事件做出响应,更新自己的画面、执行特定的动作
下面介绍下参与者:
- Linux内核:
接收输入设备的中断,将原始事件的数据写入设备节点中。 - 设备节点:
内核与IMS的桥梁,它将原始事件暴露给用户空间,以便IMS可以从中读取事件。 - InputManagerService:
一个Android的系统服务,分为Java层和Native层。
Java层负责与WMS通信。
Native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器。 - EventHub:
通过getevents访问设备节点,并把访问到的原始输入事件以及设备节点的增删返回给使用者。 - InputReader:
运行在一个独立的线程中。通过线程循环不断的从EventHub中读取原始事件,然后进行加工处理封装为包含更多信息、更具可读性的输入事件,然后交给InputDispatcher进行派发。
当设备节点有增删时,更新输入设备列表和配置。 - InputReaderPolicy:
为InputReader加工处理原始事件,提供策略配置信息。例如:键盘布局。 - InputDispatcher:
运行在一个独立的线程中。保管来自WMS的所有窗口的信息,其收到来自InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口。 - InputDispatcherPolicy:
为InputDispatcher派发过程提供策略。例如截取某些特定的输入事件用作特殊用途,或者阻止将某些事件派发给目标窗口。
示例:截取HOME键到PhoneWindowManager中进行处理,阻止窗口收到HOME键按下的事件。 - WMS:
当新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。
WMS实时更新窗口的可点击区域、焦点窗口等信息给IMS的InputDispatcher。 - ViewRootImpl:
对某些窗口,如壁纸窗口、SurfaceView的窗口来说,窗口就是输入事件派发的终点。而其他的,比如说Activity、对话框等使用了Android控件系统的窗口来说,输入事件的终点是控件(View)。ViewRootImpl将窗口所接收的输入事件沿着控件树将事件派发给感兴趣的控件。