Android Binder机制(五) addService详解01之请求的发送
有了前面篇章的铺垫,我想读者对Binder应该有了一定的了解了,那么我们接着继续深入了解。本篇章终于要开始讲解Client-Server交互了,若标题所示,本文要讲解的是addService请求,即添加服务请求。本文选取的题材是MediaPlayerService服务通过addService请求注册到ServiceManager中。在这个请求中,MediaPlayerService是Client,而ServiceManager是Server。由于涉及到的过程比较复杂,这里会将addService请求分为3篇进行说明,这3篇的主题分别是:请求的发送,请求的处理,以及请求的反馈。和以往一样,在讲解详细的代码之前,先做个整体介绍。
注意:本文是基于Android 7.xx版本进行介绍的!
1.addService流程的时序图
上面是addService流程的精简时序图,理解这个图的前提是理解图中的三种角色之间的关系:
(01) MediaPlayerService和ServiceManager是两个不同的进程。它们都位于用户空间,都有各自的内存单元,两者之间不能直接进行通信;因此,需要Binder驱动的帮助才能通信。
(02) Binder驱动位于内核空间,它映射到节点"/dev/binder"上。MediaPlayerService和ServiceManager都有通过open("/dev/binder")打开该节点,并通过mmap()将内存映射到各自所在的进程中;这也就是说MediaPlayerService能和Binder驱动通信,而且ServiceManager也能和Binder驱动通信。而在Binder驱动中,有一个全局变量,依靠这个全局变量,就能实现MediaPlayerService和ServiceManager之间的通信。 依靠的这个全局变量,就是Android Binder机制(四) ServiceManager守护进程中介绍过的binder_context_mgr_node变量,它是ServiceManager的Binder实体。
搞清楚了上面三者之间的关系之后(不是三角恋),再回到时序图,来看看三者之间的交互命令:
(1) WAIT:这表示ServiceManager进程进入中断等待状态,等待客户端的到来。它进入等待状态的详细流程,在Android Binder机制(四) ServiceManager守护进程篇有详细介绍过。
(2) BC_TRANSACTION:这是MediaPlayerService进程向ServiceManager发送addService请求对应的事务。这个事务是请求,而不是回复,因此BC开头,B代表Binder,而C代表Command。如果是回复,则会以BR开发,R表示Reply。Binder驱动在收到BC_TRANSACTION之后,会将分配内存,将请求数据保存到所分配的内存中。
(3) WAKE_UP:MediaPlayerService通过BC_TRANSACTION提交一个请求,该请求是交给ServiceManager来处理的。因此,Binder驱动在收到该请求后,会将其发送到ServiceManager的待处理事务队列中,并将ServiceManager唤醒。
(4) BR_TRANSACTION_COMPLETE:MediaPlayerService在发起了一个请求之后,它需要知道该请求是否发送成功。因此,Binder驱动在将该请求提交给ServiceManager之后,会反馈一个BR_TRANSACTION_COMPLETE给MediaPlayerService,表示MediaPlayerService发送的请求已经被Binder驱动收到了。
(5) WAIT:MediaPlayerService在知道自己的请求发送成功之后,就会进入中断等待状态,等待请求的反馈。
(6)BR_NOOP和BR_TRANSACTION:ServiceManager被唤醒之后,收到Binder驱动的BR_NOOP和BR_TRANSACTION指令。BR_NOOP指令什么也不会做;而对于BR_TRANSACTION指令时,ServiceManager在解析出该事务是添加服务请求,会将MediaPlayerService的相关信息保存到一个链表中。
(7) BC_FREE_BUFFER和BC_REPLY:ServiceManager在保存了MediaPlayerService的相关信息之后,便处理完毕了MediaPlayerService的请求。此时,它便反馈BC_FREE_BUFFER和BC_REPLY给Binder驱动。Binder驱动在收到BC_FREE_BUFFER之后,会释放保存请求数据所申请的内存;收到BC_REPLY之后,Binder驱动则知道ServiceManager已经处理完了MediaPlayerService的请求。
(8) WAKE_UP:Binder驱动发送WAKE_UP唤醒MediaPlayerService进程。
(9) BR_NOOP和BR_REPLY:Binder驱动唤醒MediaPlayerService后,继续BR_NOOP和BR_REPLY给MediaPlayerService,告诉MediaPlayerService请求已经处理完毕。
(10) BR_TRANSACTION_COMPLETE:同时,Binder驱动会发送一个BR_TRANSACTION_COMPLETE给ServiceManager,告诉ServiceManager该事务已经处理完毕。 MediaPlayerService在收到BR_REPLY反馈之后,知道addService请求已经成功处理;接着,它会再次进入等待状态,等待Client的请求。
(11) WAIT:最后,ServiceManager处理MediaPlayerService的请求之后,没有其他事务可处理,也再次进入了等待状态。
IMediaPlayerService的类图
本文是以MediaPlayerService为例,对addService进行解析。下面让我们一起看看MediaPlayerService相关联的类图(是不是觉得有点熟悉,在前面的篇章里面也有见过不是)。
MediaPlayerService的类图和Android Binder机制(五) defaultServiceManager()的实现中IServiceManager的类图类似。这里就不再逐一对每个类进行介绍了。
需要知道的是,对于一个MediaPlayerService而言,它存在一个"远程BpBinder对象"和"本地BBinder对象"。
(01) 远程BpBinder对象的作用,是和Binder驱动进行交互。例如,当本文所讲到的addService请求,就是通过defaultServiceManager()调用到远程BpBinder对象的transact()方法,而该方法又会调用到IPCThreadState::transact()接口,通过IPCThreadState类来和Binder驱动交互。
(02) MediaPlayerService是"本地BBinder的子类"。当Client向MediaPlayerService发起请求时,会调用BBinder的onTransact()方法,而BnServiceManager又重写了该方法,从而调用onTransact()完成对请求的处理。