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 VENDORSERVICEMANAGERALOGW("failed to open binder driver %s\n", driver);while (true) {sleep(UINT_MAX);}#elseALOGE("failed to open binder driver %s\n", driver);#endifreturn -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 VENDORSERVICEMANAGERcb.func_log = selinux_vendor_log_callback;#elsecb.func_log = selinux_log_callback;#endifselinux_set_callback(SELINUX_CB_LOG, cb);#ifdef VENDORSERVICEMANAGERsehandle = selinux_android_vendor_service_context_handle();#elsesehandle = selinux_android_service_context_handle();#endifselinux_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 methodif (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。
参考: 彻底理解Android Binder通信架构 - Gityuan博客 | 袁辉辉的技术博客