Android Binder进程间通讯原理分析
Android系统是基于Linux内核开发的。Linux开发提供了丰富的进程间通讯机制,例如管道、信号、消息队列、共享内存、插口(Socket)。而Binder是一套新的通讯工具。Binder通信采用了c/s架构,所以我们包含了 Client,Server,ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务。注意:图片来源于网络从进程进度来看
Binder IPC原理
Android系统是基于Linux内核开发的。Linux开发提供了丰富的进程间通讯机制,例如管道、信号、消息队列、共享内存、插口(Socket) 。而Binder是一套新的通讯工具。
Binder通信采用了c/s架构,所以我们包含了 Client,Server,ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务。
注意:图片来源于网络
从进程进度来看IPC机制, 每个Android的进程只能运行在质疑进程所拥有的虚拟地址空间。对于一个虚拟地址空间包含了用户空间和内核空间。 (内核空间大小可以通过参数配置调整)对于用户空间不同进程之间彼此之间不能共享的,而内核空间时可以共享的。Client进程向Server进程通信,切切是利用了进程间可共享内核空间来完成底层通信的工作,Client端与Server端进程采用iotcl等方法跟内核空间驱动进行交互。
如何启动Service Manager
可以看出无论是注册服务还是获取服务的过程都需要ServiceManager,是整个Binder通信机制的大管家, 是Android进程间通信机制Binder的守护进程,那么它是如何被启动㩐?
ServiceManager是由init进程通过解析init.rc文件而创建的,对应得可执行程序是 system/bin/servicemanageer , 源文件是 /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);
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)) {
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);
#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);
return 0;
}
通过源码我们看到 binder_open(128*1024) ,通过mmap实现对驱动128k大小的内存映射,所以我们经常看到binder传输过大数据会导致异常。
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return NULL;
}
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open %s (%s)\n",
driver, strerror(errno));
goto fail_open;
}
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
fprintf(stderr,
"binder: kernel driver version (%d) differs from user space version (%d)\n",
vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
goto fail_open;
}
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
fprintf(stderr,"binder: cannot map device (%s)\n",
strerror(errno));
goto fail_map;
}
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return NULL;
}
binder_open函数源码上我们可以看到有几个关键函数,ioctl 和 mmap 。
打开binder驱动后,注册成为binder服务的管家:binder_become_context_manager()
int binder_become_context_manager(struct binder_state *bs)
{
struct flat_binder_object obj;
memset(&obj, 0, sizeof(obj));
obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
// fallback to original method
if (result != 0) {
android_errorWriteLog(0x534e4554, "121035042");
result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
return result;
}
最后进入looper_binder无限循环,处理client端发来的请求。
如何获取Service Manager
当进程注册服务或者获取服务的过程之前都需要调用defaultServiceManager()方法来获取gDefaultServiceManager对象。
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == nullptr) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(nullptr));
if (gDefaultServiceManager == nullptr)
sleep(1);
}
}
return gDefaultServiceManager;
}
这个过程中做了3个工作,ProcessState::self() 获取了ProcessState对象单利,每个进程只有一个ProcessState对象。 getContextObject()获取率BpBinder对象,handle=0的BpBinder对象。
interface_cast<IServiceManager>()用于获取BpServiceManager对象 。
注册服务
注册服务时候由defaultServiceManager()返回BpServcieManager同时创建了ProcessState对象和BpBinder对象 。 实际就是BpServcieManager调用addService()
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;
}
Parcel:writeStrongBinder() 函数
大致通讯流程如下 :
获取服务
请求服务getService()过程,就是向ServiceManager进程查询指定服务,当执行binder_transaction函数会区分请求服务所属进程情况。
1. 请求服务进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node ; 最终通过readStrongBinder()返回BpBinder对象。
2. 请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且虚拟改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER . 。 最终通过readStrongBinder()返回BBinder对象的真实之类。
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
sleep(1);
}
return NULL;
}
通过BpServiceManager来获取服务:检索服务是否存在,当服务存在则返回相应的服务,当服务不存在则休眠1s再继续检索服务如果每次都无法获取服务,循环5次,每次循环休眠1s。
更多推荐
所有评论(0)