Binder系列6—获取服务(getService)
一、 获取服务
在Native层的服务注册,我们选择以media为例来展开讲解,先来看看media的类关系图。
1.1 类图
图解:
蓝色: 代表获取MediaPlayerService服务相关的类;
绿色: 代表Binder架构中与Binder驱动通信过程中的最为核心的两个类;
紫色: 代表注册服务和获取服务的公共接口/父类;
二. 获取Media服务
2.1 getMediaPlayerService
[-> framework/av/media/libmedia/IMediaDeathNotifier.cpp]
其中defaultServiceManager()过程在上一篇文章获取ServiceManager已讲过,返回BpServiceManager。
在请求获取名为”media.player”的服务过程中,采用不断循环获取的方法。由于MediaPlayerService服务可能还没向ServiceManager注册完成或者尚未启动完成等情况,故则binder返回为NULL,休眠0.5s后继续请求,直到获取服务为止。
2.2 BpSM.getService
[-> IServiceManager.cpp ::BpServiceManager]
通过BpServiceManager来获取MediaPlayer服务:检索服务是否存在,当服务存在则返回相应的服务,当服务不存在则休眠1s再继续检索服务。该循环进行5次。为什么是循环5次呢,这估计跟Android的ANR时间为5s相关。如果每次都无法获取服务,循环5次,每次循环休眠1s,忽略checkService()的时间,差不多就是5s的时间
2.3 BpSM.checkService
[-> IServiceManager.cpp ::BpServiceManager]
检索指定服务是否存在, 其中remote()为BpBinder。
2.4 BpBinder::transact
[-> BpBinder.cpp]
Binder代理类调用transact()方法,真正工作还是交给IPCThreadState来进行transact工作,
2.4.1 IPCThreadState::self
[-> IPCThreadState.cpp]
TLS是指Thread local storage(线程本地储存空间),每个线程都拥有自己的TLS,并且是私有空间,线程之间不会共享。通过pthread_getspecific/pthread_setspecific函数可以获取/设置这些空间中的内容。从线程本地存储空间中获得保存在其中的IPCThreadState对象。
2.4.2 IPCThreadState初始化
[-> IPCThreadState.cpp]
每个线程都有一个IPCThreadState,每个IPCThreadState中都有一个mIn、一个mOut。成员变量mProcess保存了ProcessState变量(每个进程只有一个)。
mIn 用来接收来自Binder设备的数据,默认大小为256字节;
mOut用来存储发往Binder设备的数据,默认大小为256字节。
2.5 IPC::transact
[-> IPCThreadState.cpp]
2.6 IPC.writeTransactionData
[-> IPCThreadState.cpp]
其中handle的值用来标识目的端,注册服务过程的目的端为service manager,此处handle=0所对应的是binder_context_mgr_node对象,正是service manager所对应的binder实体对象。binder_transaction_data结构体是binder驱动通信的数据结构,该过程最终是把Binder请求码BC_TRANSACTION和binder_transaction_data结构体写入到mOut。
2.7 IPC.waitForResponse
[-> IPCThreadState.cpp]
2.8 IPC.talkWithDriver
[-> IPCThreadState.cpp]
binder_write_read结构体用来与Binder设备交换数据的结构, 通过ioctl与mDriverFD通信,是真正与Binder驱动进行数据读写交互的过程。 先向service manager进程发送查询服务的请求(BR_TRANSACTION),见Binder系列3—启动ServiceManager。当service manager进程收到该命令后,会执行do_find_service() 查询服务所对应的handle,然后再binder_send_reply()应答 发起者,发送BC_REPLY协议,然后调用binder_transaction(),再向服务请求者的Todo队列 插入事务。
接下来,再看看binder_transaction过程。
2.8.1 binder_transaction
这个过程非常重要,分两种情况来说:
当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;
当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
2.8.2 binder_thread_read
2.9 readStrongBinder
[-> Parcel.cpp]
2.9.1 unflatten_binder
[-> Parcel.cpp]
2.9.2 getStrongProxyForHandle
[-> ProcessState.cpp]
readStrongBinder的功能是flat_binder_object解析并创建BpBinder对象.
2.9.3 lookupHandleLocked
根据handle值来查找对应的handle_entry.
二. 总结
请求服务(getService)过程,就是向servicemanager进程查询指定服务,当执行binder_transaction()时,会区分请求服务所属进程情况。
当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;
最终readStrongBinder(),返回的是BpBinder对象;
当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
最终readStrongBinder(),返回的是BBinder对象的真实子类;