美文网首页Binder机制详解程序员
Binder系列6—获取服务(getService)

Binder系列6—获取服务(getService)

作者: 十年开发程序员 | 来源:发表于2018-04-03 18:13 被阅读46次

    一、 获取服务

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

    相关文章

      网友评论

        本文标题:Binder系列6—获取服务(getService)

        本文链接:https://www.haomeiwen.com/subject/bgychftx.html