Android Binder进程间通讯原理分析

Binder IPC原理

        Android系统是基于Linux内核开发的。Linux开发提供了丰富的进程间通讯机制,例如管道、信号、消息队列、共享内存、插口(Socket) 。而Binder是一套新的通讯工具。

Binder通信采用了c/s架构,所以我们包含了 Client,Server,ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务。  

Android Binder进程间通讯原理分析_第1张图片

注意:图片来源于网络

        从进程进度来看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 defaultServiceManager()
  {
      if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
  
      {
          AutoMutex _l(gDefaultServiceManagerLock);
          while (gDefaultServiceManager == nullptr) {
              gDefaultServiceManager = interface_cast(
                  ProcessState::self()->getContextObject(nullptr));
              if (gDefaultServiceManager == nullptr)
                  sleep(1);
          }
      }
  
      return gDefaultServiceManager;
  }

这个过程中做了3个工作,ProcessState::self() 获取了ProcessState对象单利,每个进程只有一个ProcessState对象。 getContextObject()获取率BpBinder对象,handle=0的BpBinder对象。 

interface_cast()用于获取BpServiceManager对象 。 

注册服务

注册服务时候由defaultServiceManager()返回BpServcieManager同时创建了ProcessState对象和BpBinder对象 。 实际就是BpServcieManager调用addService() 

 virtual status_t addService(const String16& name, const sp& 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()  函数

大致通讯流程如下 : 

Android Binder进程间通讯原理分析_第2张图片

获取服务

请求服务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 getService(const String16& name) const
    {
        unsigned n;
        for (n = 0; n < 5; n++){
            sp svc = checkService(name); 
            if (svc != NULL) return svc;
            sleep(1);
        }
        return NULL;
    }

通过BpServiceManager来获取服务:检索服务是否存在,当服务存在则返回相应的服务,当服务不存在则休眠1s再继续检索服务如果每次都无法获取服务,循环5次,每次循环休眠1s。

参考: 彻底理解Android Binder通信架构 - Gityuan博客 | 袁辉辉的技术博客

你可能感兴趣的:(Android开发,binder,linux,运维)