这篇博客主要看一下binder的一些实现,以及自己写一个实例:
Binder中service组件和client组件分别使用模板类BnInterface和BpInterface来描述,前者为Binder的本地对象,后者为代理对象。
// ----------------------------------------------------------------------
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();
};
模板参数INTERFACE是一个由进程自定义的的接口,Bninterface和BpInterface都需要实现该接口,自己必须实现Bninterface和BpInterface这两个类
下面是自己实现的一个.h文件
class IExampleService : public IInterface
{
public:
DECLARE_META_INTERFACE(ExampleSercie);
virtual int get () = 0;
virtual void set (int value) = 0;
}
class BnExampleService : public BnInterface<IExampleService>//这边的模板其实对应上面的定义,就是继承这个接口类而已
{
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
}
对应实现一个.cpp文件,Bp和Bn的实现在一个文件中,但是实际上是在两个进程中,两个类都要实现IExampleService中的方法
enum {
EXAMPLE_GET = IBinder::FIRST_CALL_TRANSACTION,
EXAMPLE_SET,
};
class BpExampleService : public BpInterface<IExampleService>
{
public:
virtual int get()
{
Parcel data, reply;
data.writeInterfaceToken(IExampleService::getInterfaceDescriptor());
remote()->transact(EXAMPLE_GET, data, &reply);
return reply.readInt();
}
virtual void set(int value)
{
Parcel data, reply;
data.writeInterfaceToken(IExampleService::getInterfaceDescriptor());
data.writeInt(value);
remote()->transact(EXAMPLE_SET, data, &reply);
return;
}
};
IMPLEMENT_META_INTERFACE(ExampleService, "ExampleDescriptor");
status_t BnExampleService::onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags)
{
switch(code) {
case EXAMPLE_GET:
CHECK_INTERFACE(IExampleService, data, &reply);
reply->writeInt(get());
break;
case EXAMPLE_SET:
CHECK_INTERFACE(IExampleService, data, &reply);
set(data->readInt());
break;
default:
return BBinder::onTransact(code,data,reply,flags);
}
return NO_ERROR;
}
最后实现service,ExampleService需要继承BnExampleService,并实现虚函数,添加一个instantiate函数将当前service加入到servicemanager中。
class ExampleService : pulic BnExampleService
{
public:
ExampleService ():mValue(0);
public int get() {return mValue};
public void set (int value) { mValue = value;}
public static void instantiate() {
defaultServiceManager()->addService(String16("example"), new ExampleService());
}
private:
int mValue;
}
Bninterface类继承了BBinder,定义如下:
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);
......
};
当有一个Binder代理对象(客户端)通过binder驱动程序向一个binder本地对象(server端)发出一个进程间通信请求时,Binder驱动程序就会调用该Binder本地对象的成员函数tracsact来处理该请求。onTransact由子类实现,负责分发与业务相关的进程间通信请求,我们的例子中在BnExampleService实现了该函数,负责处理进程间发送过来的请求。
class BpRefBase : public virtual RefBase
{
protected:
BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
........
inline IBinder* remote() { return mRemote; }
inline IBinder* remote() const { return mRemote; }
private:
........
IBinder* const mRemote;
......
};
mRemote指向一个BpBinder对象,可以通过remote函数来获取
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函数获取,它是binder驱动程序中一个client的binder引用对象,client组件通过这个句柄和binder对象引用对象建立对应关系。
BpBinder类的transact用来向运行在server进程中的service组件发送进程间通信请求,通过binder驱动实现。transact会把mHandle,以及通信数据发送给binder驱动,这样驱动可以根据这个句柄值找到对应的binder引用对象,然后找到binder实体对象,最后把通信数据发给对应的service组件。
无论是BBinder,BpBinder同事通过IPCThreadState类和binder驱动交互的。
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线程,内部都有一个IPCThreaState对象,可以通过self获取,transact函数和binder驱动交互,在transact函数内部调用talkwithDriver来实现,它一方面负责向binder驱动发送通信请求,一方面接受binder驱动通信请求。
IPCThreadState类有一个mProcess,指向ProcessState对象。对于每个使用binder的进程,内部都有一个ProcessState对象,负责初始化Binder设备,即打开设备文件/dev/binder,以及将设备文件/dev/binder映射到进程的地址空间。由于ProcessState对象在进程唯一,binder线程池中每一线程都可以通过它与驱动程序连接。
class ProcessState : public virtual RefBase
{
public:
static sp<ProcessState> self();
....
private:
int mDriverFD;
void* mVMStart;
....
};
进程中可以通过self函数获取ProcessState 对象,第一次调用创建一个对象,并且打开设备文件/dev/binder, 然后调用函数mmap将它映射到进程的地址空间,即请求binder驱动为进程分配内核缓冲区。得到的内核缓冲区的用户地址保存在mVMStart中。
前面实例中有两个宏还没有分析
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp<I##INTERFACE> asInterface( \
const android::sp<android::IBinder>& obj); \
virtual const android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##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() { }
其中就是实现自己的IExample一些固定接口,这边主要看下asInterface这个函数,IBinder中有两个接口,localBinder,remoteBinder,localBinder指的是Binder实体对象,remoteBInder指的是引用对象。
对于服务进程,localBinder有意义,remoteBinder没有意义。在客户端就相反,remoteBinder有意义。因此在asInterface中,querLocalInterface返回为空代表是在客户端,因此需要new Bp##INTERFACE对象。即BpBinder没有重载querLocalInterface这函数,返回为null
下面我们实现service进程的主函数。
int main()
{
ExampleService::instantiate();//将service加入到serviceManager中
processState::self()->startThreadPool();//开启了一个线程读取binder请求
IPCThreadState::self()->joinThreadPool();//主线程joinThreadPool读取binder请求,因此有两个binder线程。
return 0;
}
最后我们看看客户端如何通过binder跨进程通信,调用接口。
int main()
{
sp<IBinder> binder = defaultServiceManager()->getService(string16("example"));
if (binder == null)
{
LOGE("failed");
return -1;
}
sp<IExampleService> service = IExampleService::asInterface(binder);//将IBinder转换成
int value = service->get();
printf("%d", value);
}
binder c++的分析完了,后面分析下java的binder原理。