一、首先分析一下ServiceManager内容:ServiceManager提供的业务函数主要是4种:
getServie();
checkService() ;
addService();
listServices().
已经知道,ServiceManager和Server在不同的两个进程中,所以两者之间的通信便会使用binder进行。ServiceManager和Server的关系是ServiceManager是服务端,
Server是客户端,两者之间的业务是Server端首先会向ServiceManager中注册具体的Services,这时沟通要靠binder了。
在这里应该注意的是binder在驱动上对应着一个binder驱动设备,这个binder驱动会在内存上划分出一块共享内存块,实现数据的交互。
现在说说MediaPlayerService这项具体的服务是如何完成在ServiceManager中的注册,binder是如何工作的。在这里还是要注意的是理解binder在业务层上的运用。
在MediaPlayerService.cpp中首先MediaPlayerService要得到这个BpServiceManager对象,使用它才能调用addservice()完成注册。在MediaPlayerService的init函数中
实现:void MediaPlayerService::instantiate(){
defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
//这个函数体描述:status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);这个remote()的返回值是BpBinder,这里就是用BpBinder代理工作
这里,已经进入到通信层中的Binder了,这时候就是BpBinder和BBinder的正式工作了。
}
其实业务层用这条语句已经完成了注册任务,表面的工作已经完成,但是要理解的是真正的Binder的BpBinder和BBinder是如何工作的。在这里,MediaPlayerService的是IServiceManager.cpp中得到BpServiceManager,对于MediaPlayerService这个客户来说这时工作已经完成。剩下的就是这个BpServiceManager和BnServiceManager的工作。 总结:
(1)调用BpServiceManager中的addService()函数,这个是业务层的函数。
(2)在 addService()函数这个业务的函数中把客户端的请求打包成数据包data,然后传给BpBinder的transact()函数,注意!在这里就表示把业务层 的此项通信工作 交给了BpBinder。
二、现在一步步分析交给binder之后,binder是如何工作的:分析binder通信层的工作
从BpBinder.cpp入手
这个文件中主要玩儿的就是这个transact()函数,追踪这个函数之后是这个函数中的IPCThreadState()工作线程对象的transact()工作。
IPCThreadState()::self() -> transact()(在同一个类中,成员函数之间可是相互调用)IPCThreadState()::self() 会创建new出来一个IPCThreadState对象。(IPCThreadState对象会把它自己放到TLS。)
这个对象中有两项要使用的:成员变量mIn,mOut,mIn是用来接收binder设备中的数据,mOut是用来传输数据给binder设备。第二个就是这个transact()函数的工作。
IPCThreadState()::transact()的工作步骤:
第一步:使用writeTransactionData(BC_TRANSACTION,flags,handle,code,data,NULL)完成把数据发出去的作用。
BC_TRANSACTION:这个参数必须解释下:表示向Binder驱动设备发送要求,定义如下
BC_TRANSACTION = _IOW_BAD('c', 0, struct binder_transaction_data),"C"表示向驱动发请求,“0”是对应的目的端handle值,接着是需要发送的数据。
这里会使用一个用于和binder驱动设备沟通的数据结构:struct binder_transaction_data,这个结构体类型的变量的成员变量中,
:
:
binder_transaction_data tr;
tr.target.handle = handle; //!!这个handle的值传给target,用这个来标示目标端,在这里,0是binder系统中表示ServiceManager,这里它就是我们要的目的端
tr.code = code;
tr.flags = binderFlags;
:
:
第二步:就是等待回复,status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)这个函数开始工作,
函数中的重要点是switch()语句中的executeCommand()完成了接收回复的工作。在程序中以BR_FAILED_REPLY,“RB”这样的形式表示完成接收回复。
主要的都有了现在要知道的就是和binder驱动设备交互的是谁,答案是:status_t IPCThreadState::talkWithDriver(bool doReceive)这个函数在工作的时候是
binder_write_read bwr用来和binder设备交互数据结构。
到此算是基本上找到头了!可以暂时结束一下这里的追踪工作。
一个Bp####中的参数必须有BpBinder,因为这才是本质用来工作的。
三、关于startThreadPool和joinThreadPool的工作:
这两者是和Binder驱动设备打交道的,startThreadPool创建新的IPCProcessState(),这个是可以用来不断工作的,同时通过joinThreadPool来读取binder设备,
判断是否有请求存在。
这里的一个问题是,主线程和工作线程都是可以调用startThreadPool和joinThreadPool工作的,就是一个多线程操作了。