您的位置:首页 > 移动开发 > Android开发

Android Binder

2015-07-09 18:09 633 查看

Binder进程间通信库

Android系统在应用程序框架层将各种Binder驱动程序操作封装成了一个Binder库,这样进程就可以方便调用Binder库提供的接口来进行进程间通信。在Binder库中,Service组件和Client组件分别使用模板类BnInterface和BpInterface来描述,其中,前者称为Binder本地对象(Binder Native),后者称为Binder代理对象(Binder proxy)。Binder库中的Binder本地对象和代理对象分别对应于Binder驱动程序中的Binder实体对象和Binder引用对象。下面我们主要介绍这两个模板类的实现。

模板类BnInterface和BpInterface的定义如下所示:

template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface>  queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;

protected:
virtual IBinder* onAsBinder();
}

template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp<IBinder>& remote);

protected:
virtual IBinder* onAsBinder();
}


模板参数INTERFAE是一个由进程自定义的Service组件接口,模板类BnInterface和BpInterface都需要实现该接口。在使用Binder库开发Service组件和Client组件时,除了要定义Service组件接口之外,还必须要实现一个Binder本地对象类和一个Binder代理对象类,它们分别继承于模板类BnInterface和BpInterface。

BnInterface

模板类BnInterface继承了BBinder类,后者为Binder本地对象提供了抽象的进程间通信接口,它的定义如下所示:

class BBinder : public IBinder
{
public:
// ......
virtual status_t transact(uint32_t code, const Parcel& data, Parcel *reply, uint32_t flags = 0);
// ......
protected:
// ......
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
}


BBinder类有两个重要的成员函数transact和onTransact。当一个Binder代理对象通过Binder驱动程序向一个Binder本地对象发出一个进程间通信请求时,Binder驱动程序就会调用该Binder本地对象的成员函数transact来处理该请求。成员函数onTransact是由BBinder的子类,即Binder本地对象类来实现的,它负责分发与业务相关的进程间通信请求。事实上,与业务相关的进程间通信请求是由Binder本地对象类的子类,即Service组件类来负责处理的。

BBinder类又继承了IBinder类,而后者又继承了RefBase类。由Android智能指针的知识可知,继承了RefBase类的子类的对象均可以通过强指针和弱指针来维护它们的生命周期,换句话说,就是Binder本地对象是通过引用计数技术来维护生命周期的。

BpInterface

模板类BpInterface继承自BpRefBase类,后者为Binder代理对象提供了抽象的进程间通信接口,它的定义如下所示:

class BpRefBase : public virtual BpRefBase
{
protected:
BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
inline IBinder* remote() {return mRemote;}
inline IBinder* remote() const {return mRemote;}
private:
IBinder* const mRemote;
}


BpRefBase类又继承了RefBase类,因此,它的子类对象,即Binder代理对象也可以通过强指针和弱指针来维护生命周期。

BpRefBase类有一个重要的成员变量mRemote,它指向一个BpBinder对象,可以通过成员函数remote来获取。BpBinder类实现了BpRefBase类的进程间通信接口,它的定义如下所示。

class BpBinder : public IBinder
{
public:
BpBinder(int32_t handle);
inline int32_t handle() const { return mHandle; }
virtual status_t transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
private:
const int32_t mHandle;
}


BpBinder类的成员变量mHandle是一个整数,它表示一个Client组件的句柄值,可以通过成员函数handle来获取。每一个Client组件在Binder驱动程序中都对应有一个Binder引用对象,而每一个Binder引用对象都有一个句柄值,其中,Client组件就是通过这个句柄值来和Binder驱动程序中的Binder引用对象建立对应关系的。

BpBinder类的成员函数transact用来向运行在Server进程中的Service组件发送进程间通信请求,这是通过Binder驱动程序间接实现的。BpBinder类的成员函数transact会把BpBinder类的成员变量mHandle,以及进程间通信数据发送给Binder驱动程序,这样Binder驱动程序就能根据这个句柄值来找到对应的Binder引用对象,继而找到对应的Binder实体对象,最后就可以将进程间通信数据发送给对应的Service组件了。

IPCThreadState

无论是BBinder类,还是BpBinder类,它们都是通过IPC-ThreadState类来和Binder驱动程序交互的。IPCThreadState类的定义如下所示:

class IPCThreadState
{
public:
static IPCThreadState* self();
// ...
status_t transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
// ...
private:
status_t talkWithDriver(bool doReceive=true);
// ...
const sp<ProcessState> mProcess;
// ...
}


每一个使用了Binder进程间通信机制的进程都有一个Binder线程池,用来处理进程间通信请求。对于每一个Binder线程来说,它的内部都有一个IPCThreadState对象,我们可以通过IPCThreadState类的静态成员函数self来获取,并且调用它的成员函数transanct来和Binder驱动程序进行交互。在IPCThreadState类的成员函数transanct内部,与Binder驱动程序的交互操作又是通过调用成员函数talkWithDriver来实现的,它一方面负责向Binder驱动程序发送进程间通信请求,另一方面又负责接收来自Binder驱动程序的进程间通信请求。

IPCThreadState类有一个成员变量mProcess,它指向一个ProcessState对象。对于每一个使用了Binder进程间通信机制的进程来说,它的内部都有一个ProcessState对象,它负责初始化Binder设备,即打开设备文件/dev/binder,以及将设备文件/dev/binder映射到进程的地址空间。由于这个ProcessState对象在进程范围内都是唯一的,因此,Binder线程池中的每一个线程都可以通过它来和Binder驱动程序建立连接。

class ProcessState : public virtual RefBase
{
public:
static sp<ProcessState> self();
// ...
private:
// ...
int mDriverFD;
void* mVMStart;
}


进程中的ProcessState对象可以通过ProcessState类的静态成员函数self来获取。第一次调用ProcessState类的静态成员函数self时,Binder库就会为进程创建一个ProcessState对象,并且调用函数open来打开设备文件/dev/binder,接着又调用函数mmap将它映射到进程的地址空间,即请求Binder驱动程序为进程分配内核缓冲区。设备文件/dev/binder映射到进程的地址空间后,得到的内核缓冲区的用户地址就保存在其成员变量mVMStart中。

至此,Binder库的基础知识就介绍完毕了。我们通过如下两个UML图来描述Service组件和Client组件的实现原理。





IXXXXX表示Service组件和Client组件都需要实现的服务接口。BnXXXXX和BpXXXXX分别表示Service组件和Client组件要继承的Binder本地对象类和Binder代理对象类。XXXXX表示一个具体的Service组件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  binder android