Android2.3中的消息获取过程如下所示:
这里涉及到以下名词:
(1) 客户窗口ViewRoot:应用程序添加窗口时,会在本地创建一个ViewRoot对象,也就是说ViewRoot对象的数量与窗口数量一致;
(2) Pipe:Linux的Pipe机制,也就是管道,Android2.3使用Pipe传递ViewRoot和InputDispatcher之间的消息;
(3) JNI:Java Native Interface,Java本地接口,实现Java和其他语言的交互,在Android里主要是和C语言的交互;
(4) WindowManagerService:简称WmS,窗口管理服务;
(5) InputReader:对应一个线程,该线程会持续调用输入设备的驱动,读取所有用户输入的消息,该线程在系统进程system process空间中运行;
(6) InputDispatcher:对应一个线程,InputReader读取到用户输入消息后,将消息传入InputDispatcher的消息队列中;
(7) NativeInputManager:InputManager.java对应的c对象com_android_server_InputManager.cpp中定义的一个类,主要用来存储窗口信息;
(8) InputManager:上文提到的InputManager.jara对象,Java代码通过InputManager的方法访问NativeInputManager获取窗口信息;
(9) InputMonitor:WmS中用于保存窗口信息的对象。
从添加窗口开始分析。
应用程序添加窗口时,会在本地创建一个ViewRoot对象,然后通过IPC调用WmS中的Session对象的addWindow方法,从而请求WmS创建一个窗口。
WmS创建窗口时,把窗口信息保存在InputMonitor内,然后通过InputManager把窗口信息提交给InputDispatcher,同时也存储在NativeInputManager中。
过程如下图所示:
窗口创建完成后,则等待用户消息。
上面提到过,InputReader线程会持续调用输入设备的驱动来读取用户消息,然后把用户消息传递给InputDispatcher线程,InputDispatcher中保存了窗口信息,所以可以根据用户消息找到对应的窗口信息,找到后连同窗口信息一起传给NativeInputManager。
NativeInputManager获取到消息及窗口信息后,与内部保存的窗口信息比对,判断是否按键消息, 若是按键消息,则传递给WmS,否则返回客户窗口。
WmS获取到按键消息后,通过InputMonitor内部保存的窗口信息比对及内部的一些函数,判断是否是系统按键,若不是,则返回给InputDispatcher,InputDispatcher通过Pipe返回ViewRoot;若是系统按钮,则直接调用内部函数处理,不再返回用户窗口。
过程如下所示:
由上文可知,InputDispatcher和用户窗口之间存在两个管道(Pipe),用来实现InputDispatcher和ViewRoot之间的双向交互。
补充一点Pipe的知识:Pipe是Linux的一种系统调用,Linux会在内核地址空间中开辟一段共享内存,并产生一个Pipe对象,每个Pipe对象内部都会自动创建两个文件描述符,一个用于读,一个用于写。文件描述符是全局唯一的,从而使得两个进程之间可以借助这两个描述符,一个往管道中写数据,另一个从管道中读取数据,故而,管道是单向的,这也是为什么说InputDispatcher和用户窗口之间的双向通信需要借助两个管道。