Android

Android输入系统-IMS

2021-12-30  本文已影响0人  阿拉贡居民

前言

上次系统学习了下WMS计算位置和大小的流程,在调整系统window窗口位置后,输入系统和UI显示对不上,最近有时间,再把Android输入系统完整分析下,如果只是解决一个问题,不用这么费劲,但是完整流程学习一遍,还是收益很多,特别是对事件处理的设计模式和多个模块协调完美配合。
学习Andrid输入系统,网上资料也基本都是参考《深入理解Android 卷III》,它写的特别好,代码/原理都写的很清楚,自己花了三天时间完整把这一章节看完,本书把输入系统核心写的很清楚,其他一些输入模块,比如鼠标绘制,View里面事件派发,Policy策略处理,以及更底层kernel输入框架(扯的有点远)等 并没有写,后面有机会补充这些子模块的分析。
看完总想留下点什么,就把部分流程图自己画下,算是学习笔记了,如果想学习Android输入系统,强烈推荐看下这本书。网上都是部分节选,完整版下载电子或者购买吧。
深入理解Android 卷III
《深入理解Android 卷III》第五章 深入理解Android输入系统

Android输入系统简介

对应用层而言,输入事件的源头是位于/dev/input下的设备节点,而输入系统的终点是WMS管理的某个窗口。最初的输入事件位内核生成的原始事件,而最终交付给窗口的则是KeyEvent或MotionEvent对象。因此Android输入系统的主要工作是读取设备节点中的原始事件,将其加工封装,然后派发给一个特点的窗口以及窗口中的控件。这个过程由InputManagerService(以下简称IMS)系统服务为核心的多个参与者共同完成。


Android输入系统的总体流程.png

输入系统中最基本的参与者和模块

IMS体系结构

IMS服务的大部分工作是在Native层完成的,Java层基本是Native层的封装,并负责和WMS服务对接。
看下面框架图,IMS的启动主要是创建InputReader线程和InputDispather线程,后面主要的读取输入事件和分发事件都是在这两个线程中完成的。


IMS框架图

三个线程、三台水泵

InputReader在其线程循环中不断地从EventHub中抽取原始输入事件,进行加工处理后将加工所得的事件放入InputDispatcher的派发队列中。InputDispatcher则在其线程循环中将派发队列的事件取出,查找合适的窗口,将事件写入创建的事件接受管道中。窗口事件接受线程的Looper从管道中将事件取出,交由事件处理函数进行事件的响应。整个过程共有三个线程收尾相连,像三台水泵似的一层一层将事件交付给事件处理函数。


IMS三个线程,三台水泵

IMS成员关系

IMS内部做了很多的抽象工作,EventHub、InputReader以及InputDispatcher等实际上都是继承自相应的名为XXXInterface接口,并且仅通过接口进行相互之间的引用。下图左侧部分为Reader子系统作为第一台水泵,右侧为Dispatcher子系统,作为第二台水泵。


IMS成员关系

EventHub事件生成流程

EventHub的直译是事件的集线器,顾名思义,它将所有的输入事件通过一个接口getEvents()把从多个输入设备节点中读取的事件交给InputReader,它是输入系统最底层的一个组件。


EventHub的事件生成流程

InputMapper分配

Device结构体的事件位掩码描述了4种类型的输入事件:

InputReader原始事件的读取与加工过程

Reader子系统分为读取(EventHub)和价格处理(ImputReader)两个部分。


InputReader原始事件加工

InputDispatcher通用事件派发流程

按键事件往往携带系统功能,例如HOME键,POWER键以及Volume键等,InputDispatcher需要对按键事件做更多附件工作,很多工作都是在Policy里面做的,先说明下通用事件派发流程总结。

InputChannel对工作原理

InputChannel本质是一对SocketPair(非网络套接字)。SocketPair用来使用本机进程间的通信。一对SocketPair通过socketpair()接口创建。使用者可以因此而得到两个相互连接的文件描述符。这两个描述符可以通过套接字接口send()和recv()进行写入和读取,并且向其中一个文件描述符中写入的数据,可以从另一个描述符中读取。同pipe()所创建的管道不同,SocketPair的两个文件描述符是双向通信的,因此非常适合进程间的交付通信。
InputChannel就是SocketPair描述符及其操作的封装,而且是成对使用的。匹配的两个InputChannel分别保有一个SocketPair的描述符,并分别分配给InputDispatcher与窗口。因此InputDispatcher向保有的InputChannel中写入输入事件,可以由窗口从自己的InputChannel中读取。并且窗口可以将事件处理完毕的反馈写入到InputChannel中,InputDispatcher再将反馈进行读取。


InputChannel对工作原理

Connection工作原理

在InputDispatcher中,InputChannel被封装成一个Connection对象。Connection描述了从InputDispatcher到目标窗口中的一个链接,其中保存了向窗口发送的事件状态信息。在Connection中,重要的成员有:

窗口端的连接

当窗口端通过addWindow()接口获取InputChannel后,便会使用它创建一个InputEventReceiver对象,InputEventReceiver对象可以接收来之InputChannel的输入事件,并触发其onInputEvent()回调。


窗口端的连接

总结

以上只是根据《深入理解Android 卷III》学习记录,很多细节没有整理出来,有兴趣学习的建议翻阅书本。

上一篇下一篇

猜你喜欢

热点阅读