Android的窗口机制分析(2)

在ViewRoot和WMS(WindowManagerService)建立起连接之前首先会创建一个InputChannel对象,同样的WMS端也会创建一个InputChannel对象,不过WMS的创建过程是在ViewRoot调用add()方法时调用的。InputChannel的构造不做任何操作,所以在ViewRoot中创建InputChannel时尚未初始化,它的初始化过程是在调用WMS方法add()时进行的,看到上面代码中将mInputChannel作为参数传递给WMS,目的就是为了初始化。下面转到WMS代码看看InputChannel的初始化过程。

addWindow()@WindowManagerService.java

 

if (outInputChannel != null) {       String name = win.makeInputChannelName();       InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);       win.mInputChannel = inputChannels[0];       inputChannels[1].transferToBinderOutParameter(outInputChannel);              mInputManager.registerInputChannel(win.mInputChannel);   }  

outInputChannel为ViewRoot传递来的InputChannel对象,上述代码主要的工作其实就是创建一对InputChannel,这一对InputChannel中实现了一组全双工管道。 在创建InputChannel对的同时,会申请共享内存,并向2个InputChannel对象中各自保存一个共享内存的文件描述符。InputChannel创建完成后,会将其中一个的native InputChannel 赋值给outInputChannel,也就是对ViewRoot端InputChannel对象的初始化,这样随着ViewRoot和WMS两端的InputChannel对象的创建,事件传输系统的管道通信也就建立了起来。

创建InputChannel pair的过程以及管道建立,共享内存申请的过程就不再列出它的代码了,请参考openInputChannelPair()@InputTransport.cpp。下图为ViewRoot和WMS两端创建InputChannel pair之后的结构。

Android的窗口机制分析

    1.2 InputChannel的注册过程

上一节介绍了InputChannel对象的创建过程,这个过程将管道通信建立了起来,但是我们需要清楚的一点是,一个管道通信只是对应一个Activity的事件处理,也就是当前系统中有多少个Activity就会有多少个全双工管道,那么系统需要一个管理者来管理以及调度每一个管道通信,因此我们在创建完InputChannel对象后,需要将其注册到这个管理者中去。

明白了InputChannel对象需要注册的原因之后,我们再看ViewRoot和WMS端的InputChannel对象各自需要注册到哪里?其实也很好理解,两个InputChannel对象WMS端的是管道通信的sender, ViewRoot端的是Receiver(尽管创建的全双工,但是目前只使用到了它的一向的通信,另一方向的通信尚未使用),那么着两个InputChannel对象肯定需要被两个不同的管理者来管理。ViewRoot端的一般情况下会注册到一个NativeInputQueue对象中(这是一个Native的对象,而JAVA端的InputQueue类仅仅是提供了一些static方法与NativeInputQueue通信),只要当用到NativeActivity时,会是另外一种处理机制,这里我们不管它,NativeActivity毕竟很少用到;WMS端注册在InputManager对象中。其实从NativeInputQueue和InputManager的名字中也就能知道各自的功能了。

    1.2.1 注册到NativeInputQueue

ViewRoot端InputChannel对象在向NativeInputQueue注册时,需要注册3个参数:

1. 将InputChannel对象对应的Native InputChannel传递给NativeInputQueue;

2. 将ViewRoot的成员变量InputHandler传递给NativeInputQueue,这个InputHandler则是事件的处理函数,传递它的作用主要是明确当前ViewRoot的事件处理函数;

3. 还有一个很重要的参数需要传递给NativeInputQueue,那就是当前Application的主进程的MessageQueue。

其实,android在实现事件传输时,很大程度上借用了线程Looper和MessageQueue的轮询(poll)机制,通过它的轮询机制来检测管道上是否有消息通知事件发生,借用Looper机制能够很大限度的保证事件能够第一时间被Application知晓, Looper这块会单独分析一下。

在注册过程中,android会将InputChannel对象中保存的管道的文件描述符交给MessageQueue的native looper去监听,同时向native looper指示一个回调函数,一旦有事件发生,native looper就会检测到管道上的数据,同时会去调用指示的回调函数。这个回调函数为handleReceiveCallback()@android_view_InputQueue.cpp.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyszzx.html