今天趁有时间说下我对Binder的理解,不对之处欢迎指正!!
宏观上看来,binder的主要组成部分是:client(客户端),server(服务端),一个Service Manager和binder底层驱动。整体的框图如下。从图中可以清晰的发现,在Android的应用层中Client和Server所谓的IPC,其实真正的工作均由底层的Binder驱动来完成。Service Manager做为一个守护进程,主要来处理客户端的服务请求,管理所有的服务项。
Binder通信是通过Binder驱动来实现的。Binder的用户空间为每个进程维护着一个可用的线程池,线程池用于处理到来的IPC以及执行进程的本地消息,Binder通信是同步的。
Binder通信是基于服务器(Service)与客户端(Client)的,所以需要Binder 通信的进程都必须创建一个Binder接口。系统中有一个名为Service Manager的守护进程管理着系统中的各个服务,它负责监听是否有其他程序向其发送请求,如果有请求就响应,如果没有则继续监听等待。每个服务都要在Service Manager中注册,而请求服务的客户端则向Service Manager请求服务。在Android虚拟机启动之前,系统会先启动Service Manager进程,Service Manager就会打开Binder驱动,并通知Binder Kernel驱动程序,这个进程将作为System Service Manager,然后该进程将进入一个循环,等待处理来自其他进程的数据。因此,我们也可以将Binder的实现大致分为:Binder驱动、Service Manager、Service、Client 这几个部分。
与其它IPC不同,Binder使用了面向对象的思想来描述作为访问接入点的Binder及其在Client中的入口:Binder是一个实体位于 Server中的对象,该对象提供了一套方法用以实现对服务的请求,就像类的成员函数。遍布于client中的入口可以看成指向这个binder对象的“指针”,一旦获得了这个“指针”就可以调用该对象的方法访问server。在Client看来,通过Binder“指针”调用其提供的方法和通过指针调用其它任何本地对象的方法并无区别,尽管前者的实体位于远端Server中,而后者实体位于本地内存中。“指针”是C++的术语,而更通常的说法是引用,即Client通过Binder的引用访问Server。而软件领域另一个术语“句柄”也可以用来表述Binder在Client中的存在方式。从通信的角度看,Client中的Binder也可以看作是Server Binder的“代理”,在本地代表远端Server为Client提供服务。
Binder的工作流程:
1)客户端首先获得服务器端的代理对象。所谓的代理对象实际上就是在客户端建立一个服务端的“引用”,该代理对象具有服务端的功能,使其在客户端访问服务端的方法就像访问本地方法一样。
2)客户端通过调用服务器代理对象的方式向服务器端发送请求。
3)代理对象将用户请求通过Binder驱动发送到服务器进程。
4)服务器进程处理用户请求,并通过Binder驱动返回处理结果给客户端的服务器代理对象。
5)客户端收到服务器端的返回结果。
Binder是一种架构,这种架构提供了服务端接口、Binder驱动、客户端接口三个模块,和一个守护进程Service Manager。
首先来看服务端。一个Binder服务端实际上就是一个Binder类的对象,该对象一旦创建,内部就启动一个隐藏线程。该线程接下来会接收Binder驱动发送的消息,收到消息后,会执行到Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务代码。因此,要实现一个Binder服务,就必须重载onTransact()方法。而重载onTransact()函数的主要内容是把onTransact()函数的参数转换为服务函数的参数,而onTransact()函数的参数来源是客户端调用transact()函数时输入的,因此,如果transact()有固定格式的输入,那么onTransact()就会有固定格式的输出。
下面再看Binder驱动。任意一个服务端Binder对象被创建时,同时会在Binder驱动中创建一个mRemote对象,该对象的类型也是Binder类。客户端要访问远程服务时,都是通过mRemote对象。
最后来看应用程序客户端。客户端要想访问远程服务,必须获取远程服务在Binder对象中对应的mRemote引用。获得该mRemote对象后,就可以调用其transact()方法,而在Binder驱动中,mRemote对象也重载了transact()方法,重载的内容主要包括以下几项。
以线程间消息通信的模式,向服务端发送客户端传递过来的参数。
挂起当前线程,当前线程正是客户端线程,并等待服务端线程执行完指定服务函数后通知(notify)。
接收到服务端线程的通知,然后继续执行客户端线程,并返回到客户端代码区。
从这里可以看出,客户端似乎是直接调用远程服务对应的Binder,而事实上则是通过Binder驱动进行了中转。即存在两个Binder对象,一个是服务端的Binder对象,另一个则是Binder驱动中的Binder对象,所不同的是Binder驱动中的对象不会再额外产生一个线程。
MediaPlayer首先创建一个service代理对象BpMediaPlayerService,通过该代理对象的create()方法去call IPC,对MediaPlayerService发出创建player的请求。BnMediaPlayerService则在获取IPC的调用请求后,直接调用MediaPlayerService的create方法,分配一个Client对象,然后通过IPC返回该client对象的asBinder()的返回结果。BpMediaPlayerService在得到BnMediaPlayerService返回的Player->asBinder()的reply后,会利用readStrongBinder()去读出IBinder对象,将其作为参数调用interface_cast创建一个BpMediaPlayer。得到了BpMediaPlayer的MediaPlayer对象,将其保存入mPlayer,之后App就可以调用其完成一些列操作。
本DvbPlayer媒体框架是采用在原Service中创建子服务的方式来获取DvbPlayer子服务的,获取过程如图所示。DvbPlayer首先获取service代理对象BpMediaPlayerService,在该代理对象中添加createDvbPlayerClient()方法对MediaPlayerService发出创建player的请求。BnMediaPlayerService则在获取IPC的调用请求后,直接调用MediaPlayerService的createDvbPlayerClient()方法,分配一个DvbPlayerClient对象,然后通过IPC返回该DvbPlayerClient对象的asBinder()的返回结果。BpMediaPlayerService得到BnMediaPlayerService返回的Player->asBinder()的reply后,会利用readStrongBinder()去读出IBinder对象,将其作为参数调用interface_cast创建一个BpDvbPlayer,并保存为dPlayer。