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对象的真实子类;

推荐阅读更多精彩内容