binder 情景分析 - service 的注册(上)
本篇为 service 注册的第一篇,主要讲述一些原理性的东西。service 注册部分只讲到获取 IServiceManager
对象。
RPC 原理简述
在开始之前,我们先来了解一下基本的原理。
不同进程之间进行通信时,本质上还是只能够交换一下数据。方法、函数的调用是能够跨进程的。为了实现跨进程的函数调用,我们在原有 client 和 service 的基础上,增加两个对象——proxy 和 stub。客户端调用的,其实是 proxy 的函数。proxy 通过某些 IPC 通道,告知 stub。stub 读取 proxy 发生的数据,得知需要调用的函数后,再回调 service 对应的函数。
这样,从 client 和 service 的角度看,就好像是 client 调了 service 的函数。
基本的服务注册流程
从应用的角度,服务的注册其实非常简单:
1 | sp<IServiceManager> manager = defaultServiceManager(); |
这样,就成功注册了一个叫 serv_name
的服务。下面,我们就详细了解一下,在两个简单的调用背后,到底发生了什么。
注:以下 framework 源码使用 oreo-release 分支,kernel 部分使用 common 的 android-4.9-o-release 分支。部分代码为了可读性,在不影响结果的情况下作了删改。
获取 context manager 的 IBinder
我们先来看看 defaultServiceManager()
函数:
1 | // frameworks/native/libs/binder/IServiceManager.cpp |
这里关键的一句,便是:
1 | gDefaultServiceManager = interface_cast<IServiceManager>( |
getContextObject(NULL)
返回的,便是指向 context manager
的 sp<IBinder>
:
1 | // frameworks/native/libs/binder/ProcessState.cpp |
这里的 handle
类似于文件描述符,通过这个 handle,binder 驱动就可以找到对应的 struct binder_node
,而 binder_node
则关联着对应的服务。而 handle = 0
特指 context manager。
lookupHandleLocked()
会先查找本地的缓存。如果已经为对应的 handle
生成过 BpBinder
,则直接返回。即便没有,lookupHandleLocked()
也会创建一个 handle_entry
,但是 e->binder
为空。接下来 new BpBinder(handle)
,并把新生成的对象放到缓存中。
各个类之间的关系
BpBinder
实际上是 IBinder
的类。在本篇中会涉及到的类之间的继承关系如下:
前面我们获取的 BpBinder
其实是 IBinder
的子类。以 BpXXX
方式命名的,都是运行在客户端的代理。
IBinder
和 IInterface
之间的转换关系下:
IInterface
在下面一节开始说明。
获取 IServiceManager
代理对象
1 | gDefaultServiceManager = interface_cast<IServiceManager>( |
再次回到一开始的这里,现在我们知道,ProcessState::self()->getContextObject(NULL)
会返回一个指向 BpBinder
的 sp<IBinder>
。
下面是 interface_cast
:
1 | // frameworks/native/libs/binder/include/binder/IInterface.h |
展开模板后是这样:
1 | inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj) |
而 IServiceManager::asInterface()
是用宏生成的:
1 | // frameworks/native/libs/binder/IServiceManager.cpp |
展开后,IServiceManager::asInterface()
是这样的:
1 | sp<IServiceManager> IServiceManager::asInterface(const sp<::android::IBinder>& obj) |
从上面的类关系,我们知道,BpBinder
继承了 IBinder
。同时,它也继承了 queryLocalInterface
的实现:
1 | // frameworks/native/libs/binder/Binder.cpp |
上面的代码最终会执行 intr = new BpServiceManager(obj);
,返回的是一个 BpServiceManager
对象。
到这里,我们就完成了服务注册的第一步——获取一个 IServiceManager
,还知道了它实际上是一个 BpServiceManager
。
1 | // frameworks/native/libs/binder/IServiceManager.cpp |
在 BpServiceManager
的构造函数里,它只是简单地将 BpBinder
传递给了父类 BpInterface
。BpInterface
有继续传给父类,最终到了 BpRefBase
,存在了成员变量 mRemote
里。
通过 remote()
函数,我们就可以重新拿到底层的 BpBinder
对象。
现在,我们终于完成了第一部分——获取一个 IServiceManager
对象。下一篇,我们再继续第二部分——服务的注册。