Android进程间Binder机制服务端及客户端C++实现分析
(2012-02-06 22:12)
接触过android的人都知道Binder服务调用是android系统的基础。它担负是跨进程或进程内调用和数据传递的任务。理解它是理解android众多services的基础。binder服务的层次图如下: 从图中看出,一个binder服务基本分为3层:第一层业务层,它是服务的主体;第二层是粘合层,它把服务的主体和下层的binder层粘合在一起,在这一层上,可以进行transact()调用;第三层是binder层,它负责与binder驱动交互,完成跨进程数据传递。下面从服务端实现说起: Binder服务的C++实现分析 BnXXXService是由模板类BnInterface生成的,BnInterface扮演粘合剂的角色,它把服务主体接口(IXXXService)和服务载体(BBinder)粘和在一起。它定义在frameworks/base/include/binder/IInterface.h:
一个新的服务实体类BnXXXService一般用下面的方式定义:
模板展开后,相当于:
这样BnXXXService同时继承于IXXXService和BBinder。IXXXService是服务的接口,具体的服务函数在BnXXXService中实现。必须重载BnXXXService::onTransact(),在其中对不同的请求code,调用不同的函数。BBinder是服务的载体。当客户端发起服务请求,binder驱动找出相应服务的binder对象,这个binder对象就是BBinder,返回给IPCThreadState,IPCThreadState调用BBinder::transact(),如下面1028行代码所示:
1028行调用BBinder::tranact()。BBinder::tranact()是:
107行调用的onTransact(),其实就是BnXXXService::onTransact()。这样就可以在BnXXXService::onTransact()中通过switch语句完成各种各样的服务。有关类的关系如图: 由此看出:BnXXXService包含两部分:一是IXXXService,服务的主体的接口;另一部分是BBinder,它是服务的载体,它和binder驱动共同工作,保证客户的请求最终是对一个binder对象(BBinder类)的调用。从binder驱动的角度,每一个服务就是一个BBinder类,binder驱动负责找出服务对应的BBinder类。然后把这个BBinder类返回给IPCThreadState,IPCThreadState调用BBinder的transact()。BBinder的transact()又会调用onTransact()。BBinder::onTransact()是虚函数,所以实际实际是调用BnXXXService::onTransact(),这样就可在BnXXXService::onTransact()中完成具体的服务函数的调用。
BnXXXService可以用下面的方法以名字“xxx.xxx.serviceName”向ServiceManager注册:
Binder客户端C++实现分析 如果说BnInterface是服务端服务主体和载体的粘和剂,那么BpInterface就是客户端代理和binder载体的粘合剂。它的定义:
与服务端类似,客服端一般也用下面的方式得到客户端的服务代理:
如代码所示:先通过defaultServiceManager()得到IServiceManager的客户代理,然后这个IServiceManager对象查询"IXXXService.name"服务,ServiceManager::getService()返回对应服务的IBinder。最后,interface_cast把这个IBinder转换成服务的客户端代理类BpXXXService。interface_cast的定义如下,
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ const android::String16 I##INTERFACE::descriptor(NAME); \ const android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } \ android::sp<I##INTERFACE> I##INTERFACE::asInterface( \ const android::sp<android::IBinder>& obj) \ { \ android::sp<I##INTERFACE> intr; \ if (obj != NULL) { \ intr = static_cast<I##INTERFACE*>( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == NULL) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \ } \ I##INTERFACE::I##INTERFACE() { } \ I##INTERFACE::~I##INTERFACE() { } \ 关键在:如果obj是BBinder,obj->queryLocalInterface()返回接口本身;如果是BpBinder,则返回NULL。利用这个特性,当queryLocalInterface()返回NULL时,程序构造一个BpXXXService。这就是interface_cast(const sp<IBinder>& obj)返回的客户端代理类BpXXXService。 这里有个细节,binder驱动实际上返回的是服务的句柄(handle),而getService返回的是IBinder。这中间发生了什么?看看getService(),getSerivice()调用checkService():
CHECK_SERVICE_TRANSACTION的结果放在reply,binder驱动返回的服务句柄放在reply中,它应该在Parcel::readStrongBinder()中被转换成sp<IBinder>。看看Parcel::readStrongBinder()
Parcel::readStrongBinder()调unflatten_binder()。在unflatten_binder()里,由于binder驱动返回的是handle,所以ProcessState::getStrongProxyForHandle()被调用。
如果应用是第一次请求服务,那lookupHandleLocked(handle)应该返回Null 。这样ProcessState::getStrongProxyForHandle()构造一个以handle为参数构造BpBinder。这个BpBinder就是getService()得到IBinder。这样这个至关重要的handle被保存在BpBinder里。这个BpBinder也是interface_cast(const sp<IBinder>& obj)中输入参数的IBinder。 客户端涉及的类关系图:
到此为止,我们大致勾画出binder调用的过程,服务端用BnInterface模板,把具体服务的接口和BBinder结合起来生成一个服务类。然后把这个服务类向ServiceManager注册,注册简单地说就是把一个服务的名字和它对应的BBinder的句柄(handle)在ServiceManager中关联起来。以后有人需要这个服务,可以用名字得到它的句柄,用这个句柄,binder驱动就可以找到具体的BBinder服务类了。
客户端用BpInterface模板,把具体服务的接口和BpBinder结合起来生成一个客户端代理类。客户端代理类的实质就是一个服务句柄,这个句柄从binder驱动中返回给应用层,应用层再用Parcel::readStrongBinder()把它转换成sp<IXXXService>,并把它保存在BpBinder。 |
|