overview
Binder是Android系统进程间通信方式之一。
相比传统的IPC通信,binder的优点是:
- 只需要一次内存拷贝
- 安全可靠(在内核中添加UID等)
- Android系统中广泛使用Client-Server的通信方式,Binder提供了这一机制。
binder通信中的四个角色:Client,Server,ServiceManager,binder驱动。

Binder驱动:提供进程间通信方式的机制,上图中所有跨进程的通信都需要通过Binder驱动
ServiceManager:服务管理者,所有的服务都需要首先注册到ServiceManager中才可以被其他进程访问到,作为一个特殊的系统服务,在系统启动时启动服务。
Server:服务的提供者,首先需要将服务注册到ServiceManger中,后续处理Client的请求。
Client:服务的使用者,首先需要向ServiceManager请求服务句柄,后续通过这个句柄请求服务。
编写一个Binder通信实例
功能:Server提供一个变量的访问接口,Client需要通过这个接口实现跨进程的访问。
virtual int32_t getVal() = 0;
virtual void setVal(int32_t val) = 0;
|
为了方便Binder的使用,系统为我们提供一套接口,我们只需要实现对应的接口即可使用Binder通信。这个接口使用了代理模式,如下所示。
BnInterface和BpInterface都继承了模板接口类INTERFACE,这个模板接口类就是Service提供的接口。这里Bn表示本地服务接口,Bp表示远程代理接口。
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); //Bn端重写这一接口,根据descriptor返回一个IInterface接口,Bp端使用默认实现,返回NULL
virtual const String16& getInterfaceDescriptor() const;
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
explicit BpInterface(const sp<IBinder>& remote);
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
}; |
INTERFACE需要继承Binder通信库提供的接口IInterface,所以我们的接口定义如下
class IFregService: public IInterface
{
public:
DECLARE_META_INTERFACE(FregService); //通过宏定义声明的默认接口
virtual int32_t getVal() = 0;
virtual void setVal(int32_t val) = 0;
};
|
Bn端的Service需要实现BnInterface接口,Bp端的Client需要实现BpInterface接口。
Bn端的实现如下所示:
class BnFregService: public BnInterface<IFregService> //继承实现BnInterface接口
{
public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};
IMPLEMENT_META_INTERFACE(FregService, "shy.luo.IFregService");
status_t BnFregService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code)
{
case GET_VAL:
{
CHECK_INTERFACE(IFregService, data, reply);
int32_t val = getVal();
reply->writeInt32(val);
return NO_ERROR;
}
case SET_VAL:
{
CHECK_INTERFACE(IFregService, data, reply);
int32_t val = data.readInt32();
setVal(val);
return NO_ERROR;
}
default:
{
return BBinder::onTransact(code, data, reply, flags);
}
}
} |
onTransact()是一个继承自BBinder的接口,进程收到服务请求后,最终会通过这个接口处理。其中:
code:输入,表示双方约定的协议代码,GET_VAL表示请求服务端的get_val()接口,SET_VAL表示请求服务端的set_val()接口。
data:输入,保存了接口需要的参数等。
reply:输出,接口的输出值保存在这个类中。
flags:暂时没有用
onTransact会根据收到的服务请求调用本地不同的接口,并将返回值填入reply中,之后binder库会完成与驱动通信的所有事件。
CHECK_INTERFACE会判断请求是不是对应的代理对象发送过来的(通过代理对象的写的数据头),如果不是,就不会继续往下执行。
这里的BnFregService仍然是一个纯虚类,需要继续实现服务接口:
class FregServer : public BnFregService
{
public:
static void instantiate()
{
defaultServiceManager()->addService(String16(FREG_SERVICE), new FregServer());
}
int32_t getVal()
{
return m_val;
}
void setVal(int32_t val)
{
m_val = val;
}
private:
int32_t m_val = 1;
}; |
Bn端提供了访问类成员m_val的接口,Bp端的调用最终访问的就是这个接口。
并且Bn端提供了一个注册服务的静态方法,将实例化的本地类FregServer通过服务名FREG_SERVICE注册到service manager中。
服务端的main函数实现:
int main(int argc, char** argv)
{
FregServer::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
} |
首先将FregServer类实例化,并注册到service Manager中,然后启动binder线程池开始监听client发送过来的请求,所有的这些请求最终都会被转发到onTransact()方法中处理。
Bp端的实现如下所示:
class BpFregService: public BpInterface<IFregService>
{
public:
BpFregService(const sp<IBinder>& impl)
: BpInterface<IFregService>(impl)
{
}
public:
int32_t getVal()
{
Parcel data;
data.writeInterfaceToken(IFregService::getInterfaceDescriptor());
Parcel reply;
remote()->transact(GET_VAL, data, &reply);
int32_t val = reply.readInt32();
return val;
}
void setVal(int32_t val)
{
Parcel data;
data.writeInterfaceToken(IFregService::getInterfaceDescriptor());
data.writeInt32(val);
Parcel reply;
remote()->transact(SET_VAL, data, &reply);
} };
|
Bp端重写了我们定义的接口,以getVal()为例,
writeInterfaceToken将通信头写入到输入数据data中,remote()返回的是一个BpBinder,所以这里调用了BpBinder的transact方法,将通信请求发送到服务端,再从返回结果reply中读出服务端的返回数据。
这个跨进程通信的过程通过封装,对于用户来说是通过代理接口就可以直接返回本地接口的处理结果。
Client端的main函数:
int main()
{
sp<IBinder> binder = defaultServiceManager()->getService(String16(FREG_SERVICE));
if(binder == NULL) {
ALOGE("Failed to get freg service: %s.\n", FREG_SERVICE);
return -1;
}
sp<IFregService> service = IFregService::asInterface(binder);
if(service == NULL) {
ALOGE("Failed to get freg service interface.\n");
return -1;
}
printf("Read original value from FregService:\n");
int32_t val = service->getVal();
printf(" %d.\n", val);
printf("Add value 1 to FregService.\n");
val += 1;
service->setVal(val);
printf("Read the value from FregService again:\n");
val = service->getVal();
printf(" %d.\n", val);
return 0;
} |
首先通过服务名,使用ServiceManager的getService(