关于Binder的设计思想与Driver层实现细节可以看这个:Android Binder设计与实现 - 设计篇。这里只记录下Native层对Binder的使用。
Binder被实现为一个字符设备,应用程序通过ioctl调用与Binder驱动程序进行通信。首先看实现一个ServiceDemo涉及到的类结构关系。
RefBase是Android实现指针管理的类,牵扯到引用计数的都继承自这个类,然后通过sp,wp实现强引用计数与弱引用计数的管理。
Binder使用Client-Server的通信方式,要实现一个Server,需要先定义一套接口,Client与Server同时实现这套接口,Server端完成实际的功能,Client端只是对Server端功能调用的封装,由于这套接口需要跨进程调用,需要对所有接口一一编号,Server端根据接口编号决定调用什么函数。在上图中对接口的定义就是IServiceDemo。
要实现进程间通信,首先需要定义通信的协议,然后向应用程序提供通信的接口,Binder Driver定义了通信协议,IBinder,BpBinder,BBinder承担了通信接口的工作,IBinder定义了通信的接口,BpBinder是Client访问服务端的代理对象,负责打开Binder设备并与Binder设备通信,BBinder作为服务端与Binder设备通信的接口。Client通过BpBinder连接Binder Driver,然后Binder Driver通过BBinder与Server通信,从而完成进程间通信。
IServiceDemo定义了Client与Server通信的接口,需要Client与Server同时实现,我们已经知道,Client通过BpBinder与Server的BBinder进行通信,那么Client端怎么得到BpBinder,Server端怎么得到BBinder呢?从上图可以看到,IServiceDemo继承自IInterface,其实IInterface就定义了一个方法asBinder,返回一个IBinder对象的指针,应该是通过这个方法获得BpBinder与BBinder对象了。看asBinder实现可以知道,asBinder直接调用了onAsBinder,onAsBinder是一个虚方法,所以是调用子类的具体实现。我们发现,IInterface有两个子类BpInterface与BnInterface,在这两个类中都实现了onAsBinder,在BpInterface中,onAsBinder返回了remote(),remote()其实是返回一个BpBinder对象,后面会看到。在BnInterface中,onAsBinder直接返回this指针,而BnInterface继承自BBinder,所以BnInterface的onAsBinder返回了一个BBinder对象,BpBinder与BBinder都有了,Client就可以与Server通信了。
前面说到remote()返回一个BpBinder对象,那么这个对象是如何返回的呢?从上图看到,BnInterface是继承自BBinder的,但是BpInterface并没有继承自BpBinder,但是我们发现,BpInterface的构造函数接收一个IBinder类型的参数,我们看一下BpInterface的构造函数:
template<typename INTERFACE> inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote) : BpRefBase(remote) { }
BpInterface继承自BpRefBase,在BpInterface的初始化列表中调用了父类BpRefBase的构造函数,将IBinder remote传了过去。再看BpRefBase的构造函数:
BpRefBase::BpRefBase(const sp<IBinder>& o) : mRemote(o.get()), mRefs(NULL), mState(0) { extendObjectLifetime(OBJECT_LIFETIME_WEAK); if (mRemote) { mRemote->incStrong(this); // Removed on first IncStrong(). mRefs = mRemote->createWeak(this); // Held for our entire lifetime. } }
直接将BpInterface传过来的IBinder remote保存到了成员mRemote中,而remote()函数就直接返回了这个mRemote对象。
通过BpInterface的构造函数保存了BpBinder对象,那么BpInterface的构造函数是什么时候调用的,而作为构造函数参数传递进去的BpBinder又是什么时候构造的?以ServiceManager为例,实名Binder需要通过addService向ServiceManager注册,这也是进程间通信,那么我们就需要获得ServiceManager的BpBinder,即BpInterface的子类BpServiceManager对象,来看一下BpServiceManager的获取方法:
sp<IServiceManager> defaultServiceManager() { if (gDefaultServiceManager != NULL) return gDefaultServiceManager; { AutoMutex _l(gDefaultServiceManagerLock); if (gDefaultServiceManager == NULL) { gDefaultServiceManager = interface_cast<IServiceManager>( ProcessState::self()->getContextObject(NULL)); } } return gDefaultServiceManager; }
单例模式,看以上代码的红色部分,ProcessState代表进程对象,每个进程只有一个,在ProcessState::self()中通过单例模式返回每个进程的ProcessState的唯一实例,在ProcessState的函数函数中通过open调用打开了Binder设备,并通过mmap建立了内存映射。open引起binder driver中的binder_open被调用,binder_open中新建binder_proc节点,初始化todo队列与wait队列,并将binder_proc节点保存在binder_open第二个参数struct file *flip的flip->private_data中及binder_procs中。
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller) { return getStrongProxyForHandle(0); } sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) { sp<IBinder> result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); if (e != NULL) { // We need to create a new BpBinder if there isn't currently one, OR we // are unable to acquire a weak reference on this current one. See comment // in getWeakProxyForHandle() for more info about this. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { b = new BpBinder(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; } else { // This little bit of nastyness is to allow us to add a primary // reference to the remote proxy when this team doesn't have one // but another team is sending the handle to us. result.force_set(b); e->refs->decWeak(this); } } return result; }
handle是0,lookupHandleLocked的返回结果会是NULL,所以会执行红色部分新建一个BpBinder,defaultServiceManager中红色部分可以简化为:
gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));
BpBinder有了,我们在前面也知道了BpBinder会做为参数传递给BpInterface的构造函数,那么BpInterface的构造函数是什么时候调用的?从以上代码看,应该是interface_cast了,将参数BpBinder转化为了BpInterface的子类BpServiceManager,再来看interface_cast的实现。
template<typename INTERFACE> inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj) { return INTERFACE::asInterface(obj); }
INTERFACE即为IServiceManager,继承自IInterface的类都会声明DELCARE_META_INTERFACE与IMPLEMENT_META_INTERFACE,看一下IMPLEMENT_META_INTERFACE的实现:
#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() { }
在IMPLEMENT_META_INTERFACE宏中实现了asInterface,上述红色代码中,obj即传进来的BpBinder(0),最上面的图的注释中说了BpBinder的queryLocalInterface返回NULL,所以会执行蓝色代码,INTERFACE是Servicemanager,所以会新建一个BpServiceManager对象。BpServiceManager对象有了,对过其asBinder方法返回的BpBinder对象就可以与Server进行通信了。
Client有了代理对像BpInterface,那么怎么通过这个代理对象与Server进行通信呢?标准方法是下面这样:
remote()->transact(SET_MASTER_VOLUME, data/*parcel*/, &reply/*parcel*/);
前面已经说了,Client通过BpBinder经由Binder驱动、BBinder与Server端通信,从这里看确实是这样,remote()返回BpBinder对象,调用BpBinder的transact来与Server通信,transact是定义在IBinder中的,BpBinder与BBinder都实现了这个方法。
在BpBinder::transact的实现中,直接调用了IPCThreadState::transact,前面说过ProcessState代表进程对象,每个进程有一个,在ProcessState的构造函数会打与Binder设备并进行mmap,而这里的IPCThreadState就表示线程对象,使用LTS(Local Thread Storage)每个线程有一个IPCThreadState对象,Binder通信是线程与线程的通信,这里我们能通过IPCThreadState::transact与Server端进行通信。
IPCThreasState::transact方法首先调用writeTransactionDate将请求数据封装进binder_transaction_data结构并写入Parcel mOut中。然后调用waitForResponse。
waitForResponse会调用talkWithDriver,talkWithDriver通过ioctl(driverFD,BINDER_WIRTE_READ,&binder_write_read)与Binder驱动进行通信,当Server处理完请求后talkWithDriver成功返回,然后waitForResponse中读取Binder Driver返回的指令并执行相应的动作。
在Server中,binder thread会调用taklWithDriver等待Client请求,当有请求到来时talkWithDriver返回,读取command,调用executeCommand处理请求。在executeCommand中调用BBinder的transact处理请求,BBinder::transact会调用虚方法onTransact来完成具体功能,具体实现就是BnServiceManager::onTransact或BnServiceDemo::onTransact等等。一般会有一个类继承自BnXXXXX完成具体功能,在BnXXXXX的onTransact中会调用完成相应功能的接口,由于是虚方法,就会调用到具体实现类。
注册上下文管理者--ServiceManager
通过 ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); 一个进程可以注册成为上下文件管理者,在ServiceManager就是执行这条ioctl请求。
ioctl调用会执行Binder Driver的binder_ioctl函数,binder_ioctl根据第二个参数cmd执行相应的同作,看下BINDER_SET_CONTEXT_MGR对应的处理:
case BINDER_SET_CONTEXT_MGR: if (binder_context_mgr_node != NULL) { printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; goto err; } if (binder_context_mgr_uid != -1) { if (binder_context_mgr_uid != current->cred->euid) { printk(KERN_ERR "binder: BINDER_SET_" "CONTEXT_MGR bad uid %d != %d\n", current->cred->euid, binder_context_mgr_uid); ret = -EPERM; goto err; } } else binder_context_mgr_uid = current->cred->euid; binder_context_mgr_node = binder_new_node(proc, NULL, NULL); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; } binder_context_mgr_node->local_weak_refs++; binder_context_mgr_node->local_strong_refs++; binder_context_mgr_node->has_strong_ref = 1; binder_context_mgr_node->has_weak_ref = 1; break;
很简单,就是通过binder_new_node获取到一个binder_node保存到全局变量binder_context_mgr_node中,同时保存了UID,只能有一个context_manager。