Binder
通信架构简介
Binder
采用 C/S
架构,是 Android
提供的一种通信机制,通过 ServiceManager
集中管理系统中的有名服务。
使用服务的大致过程:
-
Server
端首先向ServiceManager
注册服务以便Client
可以使用(此时Server
是Client
端,ServiceManager
是服务端) -
Client
向ServiceManager
请求它要使用的服务(此时Client
是Client
端,ServiceManager
是服务端)。 -
Client
根据得到的Service
信息,和Server
进行通信(此时Client
是Client
端,Server
是服务端)。
以上三步均通过 Binder
通信机制实现,只是封装的层次可能有所不同,理解其中任意即可知道其它。
如图:
binder_arch.png通信过程
这里先以 MediaServer
向 ServiceManager
注册 MediaPlayerService
服务为例,进行其流程的大致描述,每步后面都会对其中一些难以理解的地方进一步说明。
注: MediaPlayerService
只是 MediaServer
向 serviceManager
注册的众多服务之一。
serviceManager
启动
注册服务前首先要启动好 serviceManager
服务程序,该程序是掌管服务的服总控管理服务程序,比较特殊,它的启动没有使用 Android
的封装机制而是直接和 binder
交互。
大致过程就是:
- 设置自己的
handle
,该handle
为宏值BINDER_SERVICE_MANAGER
,用来标示serviceManager
服务程序,也就是其它程序请求服务时的目的端。 - 打开
binder
设备映射binder
所需缓存 - 通过
binder
的ioctl
命令设置自身为serviceManager
,整个系统中只有一个serviceManager
。 - 进入消息循环,根据
handle
判断消息目标,如果是自身的handle
,则处理接收到的消息。
注:其它服务程序的启动一般使用 android
的封装机制,后面讲述服务启动的时候会讲述利用 android
封装机制如何启动一个普通的服务。
MediaServer
向 serviceManager
注册 MediaPlayerService
服务
1、业务层实现
打包数据,即将标示“注册服务”的 AddService
关键字打包,至此业务层内容完毕,余下的交由通信层处理。
注: Android
将通信和处理过程通过其封装机制,划分为“业务层”和“通信层”两个部分(这点至关重要!)。
- “业务层”专注对业务流程的处理,依据不同的应用功能而不同;
- “通信层”专注对消息通信的处理,采用
Binder
机制实现,这也意味着也可用其它的通信机制实现此部分的功能例如“socket”、“管道”等。
2、通信层实现层次1- BpBinder
代理类的处理
通信层可借助 BpBinder
这个工具类来实现,通过 BpBinder
的 Transact
函数最终传递数据给 ServerManager
处理。 BpBinder
通过“人手一份”的 IPCThreadState
,以线程局部变量的方式,将 BpBinder
自身、 BBinder
对应的 handler
与数据等信息交由其 transact
函数处理。
注: BpBinder
和 BBinder
都是 Android
中与 binder
通信的代表,它们都继承自 IBinder
类。 BpBinder
是客户端和服务端交互的代理类, p
即 proxy
的意思; BBinder
则是与 BpBinder
相对的一端,是 proxy
的目的端。两者一个是客户端,一个是服务端,并且一一对应,和 BpBinder
对应的 BBbinder
用一个 Bpbinder
的 handler
成员( mHandler
)来索引到。
3、通信层实现层次2- 和驱动的交互
IPCThreadState
对象包含:
-
mIn
,包含用于接收数据的缓存和操作。 -
mOut
,包含用于发送数据的缓存和操作。 -
mProcess
,包含binder
通信所需的具体文件描述符内存
IPCThreadState
的 transact
函数首先将数据发送至其 mOut
成员中,然后通过 talkWithDriver
函数与 binder
驱动交互(即发送请求到 binder
设备并接收回复到 mIn
中)后,从 mIn
中取出相应的回复信息,并调用 executeCommand
函数进行进一步的处理。
注: talkWithDriver
中,通过 ioctl
的方式与驱动交互。这里使用 BINDER_WRITE_READ
命令将 mOut
的数据发送给 driver
,然后接收消息到 mIn
中。(这里,我们需要注意,一般在处理不同命令的分支中,发送给设备驱动的分支命令码是 BC_XXX
,设备回复的命令码是 BR_XXX
)
4、通信层实现层次3- BBinder
的处理
在 executeCommand
函数中,借助回复得到的 BBinder
这个工具类对象,调用其 transact
函数进行处理(若 server
死掉,则由 BpBinder
处理)。
注:此时客户端接收回复,相当于服务器的“服务端”,这个 BBinder
也是客户端做为服务服务端的代表,具体这个 BBinder
的处理情况,可参考后面服务端的处理过程。
5、通信层实现层次4- 服务端的工作
客户端程序发送信息后,服务端在接收消息循环中接收到消息并开始处理。这里因为是向 ServerManager
发送注册服务请求,而 ServerManager
这个服务程序比较特殊,没有使用 BBinder
、 BnXXX
之类的封装工具接口,它是直接使用操作 binder
提供的相关接口完成这个过程的。
至此,我们分两种方式讲解此处内容:
5.1、在 ServerManager
中实际的处理
直接在其循环中调用 binder
的 ioctl
接口接收到消息,然后再进行相关处理,再通过 binder
的 ioctl
接口回复消息给请求方。
5.2、正常 Server
程序的处理
一般 Server
都至少有一个线程处于接收消息的循环中,假设其中一个线程接收到客户端发送来的消息,最终会调用到 executeCommand
函数进一步处理。
处理过程如前所述:
- 从接收到的消息中,取得代表自己的
BBinder
对象, - 进入
BBinder::transact
函数, - 再调用
onTransact
处理通信的内容, - 在
onTransact
中调用业务函数处理业务逻辑的内容。
注:这里调用的 BBinder::onTransact
,其实指向的是其子类对象的函数,即 BnXXX
;而其中调用的业务函数,也是其子类对象自己实现的函数,即 XXXService
。具体是什么子类,依据服务有所不同,以刚刚注册的 MediaPlayerService
为例,其它类似,涉及的相关类如下图:
我们实现 MediaPlayerService
的业务功能(如 createMediaRecorder
)时,就实现 MediaPlayerService
子类的函数。处理通信信息时(如根据不同类型的信息,调用不同的业务函数),实现 BnMediaPlayerService
子类的函数。
服务端启动
前面讲述的服务注册过程只是服务程序启动的一个阶段,这个阶段服务程序做为 serviceManager
的客户端,向 serviceManager
程序请求注册服务。当注册完服务后,服务程序本身便可做为服务端,进入自己的消息循环,接收客户端的请求,和 serviceManager
不同的是, serviceManager
启动时直接与 binder
交互,而一般服务端通过 android
封装的机制来启动。
这里还是以 MediaServer
的启动为例,介绍启动的大致过程:
1、获得 ProcessState
单实例对象
每个进程启动时,都通过单实例方式创建一个唯一的 ProcessState
,它主要打开 binder
设备文件,以及通过 mmap
映射好通信所需的内存地址,相关信息在其成员中保存。后面使用 binder
通信时,最终会用到这里的内容。
2、获得 IServiceManager
单实例对象以便和 serviceManager
进程交互
这里通过 defaultServiceManager
函数,以单实例方式进行。
- 首先创建
BpBinder
对象,该对象由serviceManager
对应的handle
初始化,完成通信层功能; - 然后通过该
BpBinder
,转换生成IServiceManager
对象(其实是子类BpServerManager
对象),完成业务层功能; -
BpBinder
对象做为IServiceManager
对象的成员存在,以这种方式将业务层和通信层相关联。
交互实现的关键
-
通信层、业务层、通信业务关联
-
通信层相关内容
根据前面,
serviceManager
的handle
是BINDER_SERVICE_MANAGER
,一般就是0,这个为系统所周知。借助该handle
做为成员构成的BpBinder
代理对象,来向serviceManager
发送消息协助完成通信层的功能。服务端会通过接受到消息中的handle
比对,判断出是否为发送给自己的消息。 -
业务层相关内容
生成的
BpBinder
对象,会最终通过interface_cast
,转换成IServiceManager
对象,完成serviceManager
应用程序对应的业务功能(如:getService
、addService
等)。 -
通信层和业务层的关联
是利用
BpBinder
创建BpServiceManager
对象,使用BpBinder
是通过BpServiceManager
对象的mRemote
成员来做到的。
期间所涉及的类关系如下:
-
-
实现通信层、业务层类的关系
对于前面的类图,我们还是从“业务层”和“通信层”两个方面来看。
-
业务层
BpServiceManager
、BnServiceManager
都继承自IServiceManager
,通过IServiceManager
完成业务逻辑功能,通过其子类实现业务逻辑,其中BnServiceManager
的功能需要又由子类MyServiceManager
来实现。 -
通信层
通过
IBinder
完成通信相关逻辑,具体实现由其子类:BpBinder
完成客户代理功能,BBinder
完成服务端功能。而实现又是借助于封装的BpServiceManager
和BnServiceManager
完成的。BnServiceManager
继承自BBinder
;而BpServiceManager
通过父类BpInterface
的父类BpRefBase
的mRemote
成员,与BpBinder
对象关联。
-
总结
结合前面描述“正常
server
程序的处理”中的“MediaPlayerService
家谱”图,我们可大致理清Android
封装机制对“业务层”和“通信层”的封装机制。而两者间的关联,正是BnServerXXX
和BpServiceXXX
即能涉及业务相关的内容,也能涉及通信相关内容的原因。
-
服务端启动后,与客户端的交互过程,与服务程序本身做为客户端向 `serviceManager` 注册服务的过程类似,参见后面讲述“客户端和服务端交互”时的内容。这里着重讲述 `Android` 系统中,大部分服务程序是如何利用 `Android` 的封装机制实现启动,以便后续的客户端能向注册服务一般向该服务程序请求服务的。
3、向 serviceManager
注册各类服务
前面注册的 MediaPlayerService
,只是 MediaServer
的众服务之一,它使用 MediaPlayerService::instantiate
函数,调用通过 defaultServiceManager
函数返回的 IServiceManager
的 addService
业务接口实现。
注册期间 MediaServer
做为 serviceManager
的客户端,向 serviceManager
程序请求注册服务;其它服务的注册类似,其详细过程参考前面讲述的 “ MediaServer
向 serviceManager
注册 MediaPlayerService
服务” 相关内容。
4、服务端进入自己的消息循环
通过 StartThreadPool
和 JoinThreadPool
实现。
启动的这些线程,进入消息循环统一为前面各类服务工作。如果任务不繁重,可以不用 StartThreadPool
,使用主线程即可。
客户端和服务端交互
这里,以客户端与MediaPlayerService服务的交互为例
1、客户端向 ServiceManager
查询 MediaPlayerService
服务
- 首先客户端通过
defaultServiceManage
函数获取到代表serviceManage
的IServiceManager
接口; - 然后通过
IServerManager
的getService
业务接口,获取到MediaPlayerService
的BpBinder
; - 最后将获取的
BpBinder
通过interface_cast
转换成IMediaPlayerService
接口,做为获取的结果。
2、客户端向服务端发送服务请求
ImediaPlayerService
接口包含了 MediaPlayerService
可提供的各种业务接口函数供客户端使用,大致过程是:
- 客户端的业务层(
BpMediaPlayerService
相关)打包数据递交给通信层; - 客户端通信层(
BpBinder
相关)将数据发送给Binder
驱动。
这里客户端发送数据时涉及到从业务层到通信层的过程(类似数据打包),之后我们可以看到,通过 Binder
驱动,在服务端接收数据时会经历从通信层到业务层的过程(类似数据解包)。
注:这些业务接口目前还是在客户端被调用,实际调用的是子类 BpMediaPlayerService
,这是一个代理接口,客户端通过继承自 IMediaPlayerService
的 BpMediaPlayerService
代理接口来调用各种业务接口请求服务端的服务,在代理接口的业务函数中将封装好的信息借助其通信层的代理 BpBinder
类发送给内核 Binder
设备的驱动,之后的过程在服务端的处理中可以看到。
3、服务端处理收到的客户端请求
这里的内容在前面讲述注册服务过程时的 “正常 Server
程序的处理” 中已经详细讲述,可参考相关内容。
大致过程是:
- 服务端的通信层接收到请求(
BBinder
相关); - 递交给服务端的业务层处理(
BnMediaPlayerService
相关)。
这里,服务端通过调用同样继承自 IMediaPlayerService
的 BnMediaplayerService
业务接口,来实现客户端用 BpMediaPlayerService
业务接口中的对应的各种业务接口,客户端调用时采用的是代理接口的业务函数,和服务端服务时对应的真正实现的业务函数,因为来自同一父类,一般都是相同的函数签名。
注:
Binder
驱动通过客户端通过 BpBinder
发送来的 handle
找到在驱动中对应的 Server
端通信层的 BBinder
,将数据传送到服务端的业务层,在服务端有一个和 BpMediaPlayerService
继承自同一个父类的 BnMediaPlayerservice
接口,其中的业务函数才是真正的业务实现,该业务接口的业务函数收到 BBinder
通信端传上来的信息后,调用相应的真正实现了的业务函数进行业务处理。
其他
参考资料:
- 《深入理解Android 卷I》
网友评论