Binder通信是一个比较大的架构,从内核跟native源码角度分析的文章很多,今天准备写一下大概原理,适合跟我一样的新手看。
C/S架构
Binder通信整体架构是我们很熟悉的客户端+服务端模式,客户端进程得到一个BpBinder,也就是binder的代理对象,通过代理对象向内核缓冲区读写数据。服务端得到一个BBinder,也就是binder的本地对象,通过本地对象向内核缓冲区读写数据,这样就实现了跨进程通信。
下面画了一张图:
Binder原理.jpg
内存映射
我们理解一般的跨进程通信需要两次数据拷贝,而Binder只需要一次,这是为什么呢?
在Linux系统中,每个进程之间是独立的,各自拥有自己的内存空间,分为用户空间和内核空间。
如果需要实现通信,就需要把进程A的数据拷贝到内核空间,然后再从内核空间拷贝到进程B。
而binder建立了一个映射关系,把内核缓冲区的数据映射到进程A和进程B,它们的物理地址是一样的,从而省去了一次数据拷贝的过程。
下面画了一张图
IPC数据拷贝.jpg
Binder服务的注册与获取
Binder通信还有一个比较特殊的地方,就是所有的服务都需要通过ServiceManager向Binder驱动注册。
ServiceManager本身也是一个Binder服务,它的本地实现代码都在service_manager.c文件中,同时向外提供了ISeriviceManager接口,开发者可以通过IServiceManager接口获取到一个BpServiceManager对象,通过它来addService或者getService。
下面画了一张图,写了ServiceManager启动,注册跟获取服务的过程:
ServiceManager.jpg
ServiceManager启动过程
我们看下ServiceManager的main方法,初始化的过程做了以下几件事:
1.打开binder驱动,并调用mmap()方法分配内存映射空间:binder_open();
2.通知binder驱动使其成为守护进程:binder_become_context_manager();
3.验证selinux权限,判断进程是否有权注册或查看指定服务;
4.进入循环状态,等待Client端的请求:binder_loop()。
/frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
bs = binder_open(driver, 128*1024);//1
if (!bs) {
#ifdef VENDORSERVICEMANAGER
ALOGW("failed to open binder driver %s\n", driver);
while (true) {
sleep(UINT_MAX);
}
#else
ALOGE("failed to open binder driver %s\n", driver);
#endif
return -1;
}
if (binder_become_context_manager(bs)) {//2
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
#ifdef VENDORSERVICEMANAGER
cb.func_log = selinux_vendor_log_callback;
#else
cb.func_log = selinux_log_callback;
#endif
selinux_set_callback(SELINUX_CB_LOG, cb);
//3
#ifdef VENDORSERVICEMANAGER
sehandle = selinux_android_vendor_service_context_handle();
#else
sehandle = selinux_android_service_context_handle();
#endif
selinux_status_open(true);
if (sehandle == NULL) {
ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
abort();
}
if (getcon(&service_manager_context) != 0) {
ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
abort();
}
binder_loop(bs, svcmgr_handler);//4
return 0;
}
获取ServiceManager的代理对象BpServiceManager
接着开发者可以通过IServiceManager接口,获取到ServiceManager的代理对象。
/frameworks/native/libs/binder/IServiceManager.cpp
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == nullptr) {//1
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(nullptr));//2
if (gDefaultServiceManager == nullptr)
sleep(1);//3
}
}
return gDefaultServiceManager;
}
这里是一个单例模式,如果gDefaultServiceManager存在就直接返回,否则创建新的gDefaultServiceManager,它就是BpServiceManager。
注释1 处用了一个while循环,保证gDefaultServiceManager创建成功;
注释2 处获取了三个重要的对象:
(1)通过self函数获取一个ProcessState对象;
(2)通过getContextObject获取了一个BpBinder对象;
(3)通过interface_cast获取了一个BpServiceManager对象;
注释3 处如果创建不成功,sleep1秒后再次尝试创建。
向Binder驱动注册服务
通过上面拿到的BpServiceManager,我们可以向Binder驱动注册自己的服务了。这里通过Parcel将数据序列化之后写入内存。
/frameworks/native/libs/binder/IServiceManager.cpp
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated, int dumpsysPriority) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
data.writeInt32(dumpsysPriority);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
客户端操作是通过BpBinder代理对象,而实际通信操作都是在IPCThreadState类中完成的。
/frameworks/native/libs/binder/BpBinder.cpp
// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
通过ServiceManager获取服务
获取服务的过程类似上面,也是通过代理对象获取的,这里就不介绍源码了,画了一下上层java接口的流程。
Binder java.jpg
服务端异常死亡处理
可以通过实现IBinder.DeathRecipient接口,来监听服务端死亡通知。
private class BinderDeathRecipient implements DeathRecipient {
@Override
public void onBinderDied() {
//
}
}
然后将获取到的IBinder对象,通过IBinder.linkToDeath()方法链接到DeathRecipient。
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected ComponentName=" + name);
mReporterBinder = service;
try {
sercie.linkToDeath(new BinderDeathRecipient(), 0);
} catch (RemoteException e) {
//
}
}
参考:
Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析
彻底理解Android Binder通信架构
Binder系列—开篇
Android深入浅出之Binder机制
Binder死亡通知机制之linkToDeath
Android多进程之Binder的意外死亡及权限校验














网友评论