天天看点

Android Binder进程间通信机制

1 Binder机制简介

为了系统的安全与稳定,Linux系统是存在进程隔离的:两个不同的进程,如应用App进程和ActivityManagerService服务所在的system_server系统进程,是无法直接通过内存地址访问到对方内部的函数或者变量的。所以两个进程如果需要相互访问就涉及到一个跨进程通信的概念即IPC(Inter-process communication,进程间通讯)。本质上是借助于不同进程的内核空间都是共享的原理,两个不同的进程都去访问内核空间,从而达到“间接”访问对方的目的。Binder就是Android系统中大量使用的IPC机制,无论是应用程序对系统服务的请求(例如应用调用系统核心服务AMS的startActivity接口去实现应用启动),还是应用程序自身提供对外服务,都需要使用到Binder。因此,Binder机制在Android系统中的地位非常重要,可以说,理解Binder是理解Android系统的前提。本文将基于最新的Android 11代码,全面分析Binder机制的全貌。

其实在Unix/Linux系统中,存在很多传统的IPC机制。如管道、消息队列、共享内存、Socket、信号量等。但是Android系统虽然是基于Linux系统但是却很少会使用这些这些传统的IPC机制,而是大部分场景下都是使用Binder。主要原因是,相对于传统的IPC机制,Binder有如下三点优势:

  1. 性能上的优势:管道,消息队列,Socket的通讯都需要两次数据拷贝,而Binder由于使用了内存映射所以只需要一次拷贝。要知道,对于系统底层的IPC形式,少一次数据拷贝,对整体性能的影响是非常之大的。
  2. 稳定性上的优势:Binder本身是C/S架构的,客户端(Client)有什么需求就丢给服务端(Server)去完成,架构清晰、职责明确又相互独立,自然稳定性更好。共享内存虽然无需拷贝,但是控制负责,难以使用。从稳定性的角度讲,Binder机制是优于内存共享的。
  3. 安全性上的优势:传统IPC形式,无法得到对方的身份标识(UID/PID),而在使用Binder IPC时,这些身份标示是跟随调用过程而自动传递的。Server端很容易就可以知道Client端的身份,非常便于做安全检查,这一点对移动操作系统非常重要。

2 Binder整体架构

借用一张经典的架构图来描述binder的整体架构全貌,如下所示:

Android Binder进程间通信机制

从图中可以看出。这个Binder机制从架构上大致可以分为三层:

  1. 驱动层,我们知道Android系统是基于Linux内核的,Binder驱动层则位于Linux内核中。Binder 驱动会将自己注册为一个misc device,并向上层提供一个dev/binder节点(此Binder节点并不会对应真实的硬件设备)。Binder驱动运行在内核态,提供了最底层的数据传递,对象标识,线程管理,调用过程控制等功能,是Binder实现跨进程通信的核心。
  2. Framework C++层,以驱动层为基础,Binder机制C++的封装实现。
  3. Framework Java层,Binder机制的Java层的封装实现,采用JNI调用复用C++层的实现。

Binder通信架构是典型的C/S架构,由Client、Server、ServiceManager、Binder Driver四大组件组成。Client、Server、ServiceManager、Binder Driver这几个组件在通信过程中扮演的角色就如同互联网中服务器(Server)、客户端(Client)、DNS域名服务器(ServiceManager)以及路由器(Binder Driver)之间的关系。其相互配合完成一次Binder通信的大概过程如下:

  1. 首先在系统开机启动时,一个进程通过Binder驱动将自己注册成ServiceManager,其地址固定为0;
  2. Server通过驱动向ServiceManager中注册Binder(Server中的Binder实体),表明可以对外提供服务。驱动为这个Binder创建位于内核中的实体节点以及ServiceManager对实体的引用,将名字以及新建的引用打包传给ServiceManager,ServiceManger将其填入查找表;
  3. Client通过名字,在Binder驱动的帮助下从ServiceManager中获取到对Binder实体的引用,通过这个引用就能实现和Server进程的通信。

整个过程如下图所示:

Android Binder进程间通信机制

3 Binder驱动与协议

这部分源码位置在Linux内核中:

/kernel/drivers/android/binder.c

/kernel/include/uapi/linux/android/binder.h

3.1 Binder驱动设备初始化

Binder驱动设备在初始化时主要完成如下几件事情:

  1. 通过misc_register()将自己注册为misc device类型的驱动设备;
  2. 填写file_operations函数指针结构体以标识用户空间在使用Binder驱动时所支持的文件操作;
  3. 指定Binder设备的名称是“binder”,这样用户空间便可以通过对/dev/binder文件进行操作来使用Binder。如下代码所示:
/*kernel/drivers/android/binder.c*/
static int __init init_binder_device(const char *name)
{
  int ret;
  struct binder_device *binder_device;
  binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
  if (!binder_device)
    return -ENOMEM;
  binder_device->miscdev.fops = &binder_fops;// 1.Binder驱动支持的文件操作
  binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;//动态分配次设备号
  binder_device->miscdev.name = name;//2.驱动名称设置,一般就是“binder”
  binder_device->context.binder_context_mgr_uid = INVALID_UID;
  binder_device->context.name = name;
  mutex_init(&binder_device->context.context_mgr_node_lock);
  ret = misc_register(&binder_device->miscdev);// 3.注册Binder驱动
  if (ret < 0) {
    kfree(binder_device);
    return ret;
  }
  hlist_add_head(&binder_device->hlist, &binder_devices);
  return ret;
}

const struct file_operations binder_fops = {
  .owner = THIS_MODULE,
  .poll = binder_poll,
  .unlocked_ioctl = binder_ioctl,// binder_ioctl
  .compat_ioctl = binder_ioctl,
  .mmap = binder_mmap,// binder_mmap
  .open = binder_open,// binder_open
  .flush = binder_flush,
  .release = binder_release,
};
      

由此可见,Binder驱动为上层应用提供了6个接口——其中使用最多的就是binder_ioctl、binder_mmap和binder_open。这是因为:需要使用Binder的进程,几乎总是先通过binder_open打开Binder设备,然后通过binder_mmap进行内存映射,最后再通过binder_ioctl来进行实际的操作。Client对于Server端的请求,以及Server对于Client请求结果的返回,都是通过ioctl完成的。

3.2 打开Binder驱动——binder open

上层用户空间的进程在访问Binder驱动时,首先需要通过open(“dev/binder”)打开Binder驱动设备,这个操作最终对应的实现是在binder_open()中。如下所示:

/*kernel/drivers/android/binder.c*/
static int binder_open(struct inode *nodp, struct file *filp)
{
  struct binder_proc *proc;
  struct binder_device *binder_dev;
  binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
         current->group_leader->pid, current->pid);
  proc = kzalloc(sizeof(*proc), GFP_KERNEL);//1.创建进程对应的binder_proc对象
  if (proc == NULL)
           return -ENOMEM;
  spin_lock_init(&proc->inner_lock);
  spin_lock_init(&proc->outer_lock);
  get_task_struct(current->group_leader);
  proc->tsk = current->group_leader;
  INIT_LIST_HEAD(&proc->todo);
  proc->default_priority = task_nice(current);
  /* binderfs stashes devices in i_private */
  if (is_binderfs_device(nodp))
    binder_dev = nodp->i_private;
  else
    binder_dev = container_of(filp->private_data,
            struct binder_device, miscdev);
  proc->context = &binder_dev->context;
  binder_alloc_init(&proc->alloc);
  binder_stats_created(BINDER_STAT_PROC);
  proc->pid = current->group_leader->pid;
        // 2.初始化binder_proc
  INIT_LIST_HEAD(&proc->delivered_death);
  INIT_LIST_HEAD(&proc->waiting_threads);
  filp->private_data = proc;
  mutex_lock(&binder_procs_lock);// 获取锁
  hlist_add_head(&proc->proc_node, &binder_procs);// 3.添加到全局列表binder_procs中
  mutex_unlock(&binder_procs_lock);
  if (binder_debugfs_dir_entry_proc) {
    char strbuf[11];
    snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
    /*
     * proc debug entries are shared between contexts, so
     * this will fail if the process tries to open the driver
     * again with a different context. The priting code will
     * anyway print all contexts that a given PID has, so this
     * is not a problem.
     */
    proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
      binder_debugfs_dir_entry_proc,
      (void *)(unsigned long)proc->pid,
      &proc_fops);
  }
  return 0;
}
      

在Binder驱动中,通过binder_procs集合记录了所有使用Binder的进程。每个初次打开Binder设备的进程都会创建一个binder_proc结构体对象,用来描述使用Binder的进程,然后被添加到这个列表中的。

3.3 内存映射——binder_mmap

在打开Binder设备之后,上层进程就要通过mmap进行内存映射。mmap的作用有如下两个:

  • 申请一块内存空间,用来接收Binder通信过程中的数据
  • 对这块内存进行地址映射,以便将来访问

mmap在内核对应的就是binder_mmap()函数:在这个函数中,会申请一块物理内存,然后将用户空间和内核空间虚拟地址同时对应到这块物理内存上。在这之后,当有Client要发送数据给Server的时候,只需一次copy_from_user动作,将Client发送过来的数据拷贝到Server端的内核空间指定的内存地址即可(从而实现前文说的Binder通信机制只需要一次内存拷贝的效果),由于这个内存地址在服务端已经同时映射到用户空间,因此无需再做一次复制,Server即可直接访问,整个过程如下图所示:

Android Binder进程间通信机制

这幅图的说明如下:

  1. Server在启动之后,调用对/dev/binder设备调用mmap;
  2. 内核中的binder_mmap函数进行对应的处理:申请一块物理内存,然后在用户空间和内核空间同时进行映射;
  3. Client通过BINDER_WRITE_READ命令发送请求,这个请求将先到驱动中,同时需要将数据从Client进程的用户空间拷贝到内核空间;
  4. 驱动通过BR_TRANSACTION通知Server有人发出请求,Server进行处理。由于这块内存也在用户空间进行了映射,因此Server进程的代码可以直接访问。

3.4 Binder驱动控制协议——binder_ioctl

binder_ioctl()实现了上层应用进程与Binder驱动之间的交互命令,可以说承载了Binder驱动的大部分业务,也是我们学习的重中之重。下面表格中列出binder_ioctl支持的命令:

命令 说明
BINDER_WRITE_READ 读写操作,可以用此命令向Binder读取或写入数据
BINDER_SET_MAX_THREADS 设置支持的最大线程数。因为客户端可以并发向服务器端发送请求,如果Binder驱动发现当前线程数已经超过设定值,就会告知Binder Server停止启动新的线程
BINDER_SET_CONTEXT_MGR Service Manager专用,将自己设置为“Binder大管家”。系统中只能有一个SM存在
BINDER_THREAD_EXIT 通知Binder线程退出。每个线程退出时都应该告知Binder驱动、才能释放相关资源;否则会造成内存泄漏
BINDER_VERSION 获取Binder版本号

其中BINDER_WRITE_READ这个命令是重点,又分为若干子命令,如下表所示:

BC_TRANSACTION Binder事务,即:Client对于Server的请求
BC_REPLY 事务的应答,即:Server对于Client的回复
BC_ENTER_LOOPER 通知驱动主线程ready
BC_REGISTER_LOOPER 通知驱动子线程ready
BR_REPLY 通知进程收到Binder请求的回复(Client)
BR_TRANSACTION_COMPLETE 驱动对于接受请求的确认回复
BR_TRANSACTION 通知进程收到一次Binder请求(Server端)
BR_DEAD_BINDER 发送死亡通知
BR_SPAWN_LOOPER 通知Binder进程创建一个新的线程

其中BC_TRANSACTION和BC_REPLAY是最关键的两个命令,Binder机制中Client与Server交互基本靠它们完成。

单独看上面的协议可能很难理解,这里我们以一次Binder请求过程来详细看一下Binder协议是如何通信的,就比较好理解了。

Android Binder进程间通信机制
  • Binder是C/S架构的,通信过程牵涉到:Client,Server以及Binder驱动三个角色
  • Client对于Server的请求以及Server对于Client回复都需要通过Binder驱动来中转数据
  • BC_XXX命令是进程发送给驱动的命令
  • BR_XXX命令是驱动发送给进程的命令
  • 整个通信过程由Binder驱动控制

4 Binder Framework C++层

Binder Framework的C++部分:主要功能是实现向下与Binder驱动的对接交互,并封装复杂的内部实现,对外提供使用接口。头文件定义位于:/frameworks/native/include/binder/,实现位于这个路径:/frameworks/native/libs/binder/ 。Binder库最终会编译成一个动态链接库libbinder.so,供其他进程链接使用。为了便于说明,下文中我们将Binder Framework 的C++部分称为libbinder。

4.1 主要类结构

先用一张类图描述libbinder中的主要类结构之间的关系:

Android Binder进程间通信机制

对照上面这张libbinder的设计类图,我们来理一下各个核心类的功能与职责:

  • 基类
  1. IBinder:Binder对象的基类,这个类描述了所有在Binder上传递的对象,它既是Binder服务端对象BBinder的父类,也是Binder客户端对象BpBinder的父类;主要定义的方法有:a.transact ———进行一次Binder操作;b.queryLocalInterface——尝试获取本地Binder对象;c.getInterfaceDescriptor ——获取Binder的服务接口唯一的描述;d.isBinderAlive——查询Binder服务是否还活着等;
  2. IInterface:Binder服务接口的基类,Binder服务通常需要同时提供客户端接口和服务端接口。每个Binder服务都是为了某个功能而实现的,因此其本身会定义一套接口集来描述自己提供的所有功能。而Binder服务既有自身实现服务的类,也要有给客户端进程调用的类。为了便于开发,这两中类里面的服务接口应当是一致的。因此为了实现方便,本地实现类和远程接口类需要有一个公共的描述服务接口的基类(即上图中的IXXXService)来继承。而这个基类通常是IInterface的子类。
  • 客户端类
  1. BpBinder :BpBinder的实例代表了客户端Binder,这个类的对象将被客户端调用。这个类最重要就是提供了transact方法,这个方法会将客户端调用的参数封装好通过IPCThreadState逻辑封装后发送给Binder驱动。
  2. BpInterface:客户端接口的基类,远程接口是供客户端调用的接口集。BpInterface是个模板类,它们在继承自INTERFACE的基础上还继承了BpRefBase,通过这个类的remote方法可以获取到指向服务实现方的句柄。
  • 服务端类
  1. BBinder:BBinder的实例代表了服务端Binder,它描述了服务的提供方,所有Binder服务的实现者都要继承这个类(的子类),在继承类中,最重要的就是实现onTransact方法,因为这个方法是所有请求的入口。因此,这个方法是和BpBinder中的transact方法对应的,这个方法同样也有一个uint32_t code参数(统一在IBinder中定义),在这个方法的实现中,由服务提供者通过code对请求的接口进行区分,然后调用具体实现服务的方法。
  2. BnInterface:服务端接口的基类,是需要服务端服务中真正实现的接口集。BnInterface是个模板类,它们在继承自INTERFACE(Binder服务接口的基类,继承自IInterface)的基础上还继承了BBinder,由此可以通过复写onTransact方法来提供实现。
  • 与驱动通信的类
  1. ProcessState : 代表使用Binder的进程。在讲解Binder驱动的时候我们就提到:任何使用Binder机制的进程都必须要对/dev/binder设备进行open以及mmap之后才能使用,这部分逻辑是所有使用Binder机制进程共同的。对于这种共同逻辑的封装便是Framework层的职责之一。libbinder中,ProcessState类封装了这个逻辑,从而负责进程Binder的初始化。
  2. IPCThreadState :代表了进程中使用Binder的线程,这个类中封装了与Binder驱动通信的具体实现逻辑。

在客户端接口的实现类中,每个接口在组装好参数之后,都会调用remote()->transact来发送请求,而这里其实就是调用的BpBinder的transact方法,这样请求便通过Binder到达了服务实现方的onTransact中。这个过程如下图所示:

Android Binder进程间通信机制

4.2 进程的Binder初始化(ProcessState)

之前讲解Binder驱动的时候讲过,需要使用Binder的进程,需要先通过binder_open打开Binder设备,然后通过binder_mmap进行内存映射。由于这部分逻辑是所有使用Binder的进程共有的,所以libbinder中使用ProcessState类统一封装了这个逻辑,具体代码如下:

/*framework/native/libs/binder/ProcessState.cpp*/
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) // 1M - 8k

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))// 1.调用open_driver打开binder驱动设备
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mBinderContextCheckFunc(nullptr)
    , mBinderContextUserData(nullptr)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
    , mCallRestriction(CallRestriction::NONE)
{

// TODO(b/139016109): enforce in build system
#if defined(__ANDROID_APEX__)
    LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
#endif

    if (mDriverFD >= 0) {
        // 2.mmap执行内存映射动作
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
            close(mDriverFD);
            mDriverFD = -1;
            mDriverName.clear();
        }
    }
}
      

这是ProcessState构造函数,Binder的初始化工作都是在这个函数中完成的。在这个函数中,初始化mDriverFD的时候调用了open_driver方法打开binder设备,然后又在函数体中,通过mmap进行内存映射。这里需要注意的是mmap函数的参数中有个BINDER_VM_SIZE,这个就是指定在内核上开辟的内存空间的大小,也是一次Binder通信传递的最大数据量,目前默认定义大小是1016个字节(1M-8K)。这个其实也就解释了我们平常开发过程中遇到的一个问题,就是通过Intent传递过大的对象时会报TransactionTooLargeException异常的原因。open_driver动作具体代码如下:

/*framework/native/libs/binder/ProcessState.cpp*/
#define DEFAULT_MAX_BINDER_THREADS 15

static int open_driver(const char *driver)
{
    int fd = open(driver, O_RDWR | O_CLOEXEC);// 1.通过open系统调用打开了dev/binder设备
    if (fd >= 0) {
        int vers = 0;
        // 2.通过ioctl获取Binder实现的版本号,并检查是否匹配
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result == -1) {
            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
          ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
                vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
            close(fd);
            fd = -1;
        }
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        // 3.通过ioctl设置进程支持的最大Binder线程数
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
    }
    return fd;
}
      

open_driver函数中除了实现通过open系统调用打开了dev/binder设备外。还会通过ioctl调用的BINDER_SET_MAX_THREADS命令设置进程支持的最大Binder线程数,目前定义的一般进程默认最大Binder线程数是15。这个也解释了我们在开发过程中遇到一类性能问题:就是进程的Binder线程耗尽,此时进程中已经开启了15个Binder线程用于处理binder请求且都处于工作或阻塞状态,此时如果有新的binder请求时就无法继续处理了,从而导致阻塞卡主;

4.3 与Binder驱动的通信(IPCThreadState)

IPCThreadState是一个单例类,进程中的每个Binder线程存在一个实例,负责了与驱动通信的细节处理。这个类中的关键几个方法说明如下:

Android Binder进程间通信机制

以其中最主要的是transact方法为例,该方法会完成一次Binder数据传输动作,代码如下:

/*framework/native/libs/binder/IPCThreadState.cpp*/
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    ...
    // 1.通过writeTransactionData完成数据组装写入
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
    ...
    // 2.判断是否为TF_ONE_WAY异步单向请求,如果是线程不需要阻塞等待返回值,直接返回即可
    if ((flags & TF_ONE_WAY) == 0) {
        ...
        // 3.通过waitForResponse将数据传输到驱动并等待返回结果
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        ...
    } else {
        err = waitForResponse(nullptr, nullptr);
    }

    return err;
}
      

从代码可以看出,通过Binder驱动完成一次Binder数据传输的主要流程是:

  1. 先通过writeTransactionData函数完成传输数据binder_transaction_data的组装填充;
  2. 通过waitForResponse函数真正完成传输数据写入驱动并等待返回数据,具体实现会调用talkWithDriver函数,通过ioctl命令BINDER_WRITE_READ与Binder驱动通信,完成数据的传输写入,并读取返回数据。

详细代码如下:

/*framework/native/libs/binder/IPCThreadState.cpp*/
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    // 组装binder_transaction_data
    binder_transaction_data tr;

    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }

    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;

    while (1) {
        // 调用talkWithDriver真正完成传输数据写入驱动并等待返回数据
        if ((err=talkWithDriver()) < NO_ERROR) break;
    }
}

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(__ANDROID__)
        // 通过ioctl命令BINDER_WRITE_READ与Binder驱动通信
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
        ...
    } while (err == -EINTR);
    ...
}
      

4.4 C++ Binder服务实现举例

上面的理论知识可能比较枯燥和抽象,下面以Android系统中的一个系统Binder服务为例,结合上面的理论具体分析一下。 我们以实现系统图像合成显示的核心进程服务SurfaceFlinger为例,来分析C++的Binder服务如何实现。下图是SurfaceFlinger C++ Binder服务实现类图:

Android Binder进程间通信机制

ISurfaceComposer定义了SurfaceFlinger对外提供的功能接口,其子类都继承了这些接口。

  • BpSurfaceComposer是提供给客户端调用的远程接口,先通过remote方法获取到指向服务实现方的句柄,然后通过transact方法发送具体请求。
  • BnSurfaceComposer中只有一个onTransact方法,该方法根据请求的code来对接每个请求,并直接调用SurfaceFlinger中对应的方法。
  • SurfaceFlinger是服务接口功能真正的实现。

4.4.1 服务端实现

主要包括BnSurfaceComposer和SurfaceFlinger两个类,SurfaceFlinger是BnSurfaceComposer的子类,因此在BnSurfaceComposer中调用自身的virtual方法其实都是在子类SurfaceFlinger类中实现的。BnSurfaceComposer类要做的就是复写onTransact方法,这个方法的职责是:根据请求的code区分具体调用的是那个接口,然后按顺序从Parcel中读出打包好的参数,接着调用留待子类实现的虚函数。我们看一下BnSurfaceComposer::onTransact中的代码片段:

/*framework/native/libs/gui/ISurfaceComposer.cpp*/
status_t BnSurfaceComposer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
       ...
       case CREATE_DISPLAY: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            String8 displayName = data.readString8();
            bool secure = bool(data.readInt32());
            sp<IBinder> display(createDisplay(displayName, secure));
            reply->writeStrongBinder(display);
            return NO_ERROR;
        }
        ...
    }
}
      

这段代码中我们看到了实现中是如何根据code区分接口,并通过Parcel读出调用参数,然后调用具体服务方的。而SurfaceFlinger这个类中的createDisplay方法才是真正实现创建显示设备的逻辑,详细代码如下:

/*framework/native/services/surfaceflinger/SurfaceFlinger.cpp*/
sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) {
    class DisplayToken : public BBinder {
        sp<SurfaceFlinger> flinger;
        virtual ~DisplayToken() {
             // no more references, this display must be terminated
             Mutex::Autolock _l(flinger->mStateLock);
             flinger->mCurrentState.displays.removeItem(this);
             flinger->setTransactionFlags(eDisplayTransactionNeeded);
         }
     public:
        explicit DisplayToken(const sp<SurfaceFlinger>& flinger)
            : flinger(flinger) {
        }
    };

    sp<BBinder> token = new DisplayToken(this);

    Mutex::Autolock _l(mStateLock);
    // Display ID is assigned when virtual display is allocated by HWC.
    DisplayDeviceState state;
    state.isSecure = secure;
    state.displayName = displayName;
    mCurrentState.displays.add(token, state);
    mInterceptor->saveDisplayCreation(state);
    return token;
}
      

4.4.2 注册服务

服务实现完成之后,并不是立即就能让别人使用的。而是需要先通过Binder驱动向ServiceManager中注册服务,表明可以对外提供服务。下面我们看看SurfaceFlinger服务注册发布的具体代码实现:

/*frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp*/
int main(int, char**) {
    ...
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);

    // 1.启动Binder线程池
    // start the thread pool
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();

    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
    set_sched_policy(0, SP_FOREGROUND);

    // initialize before clients can connect
    flinger->init();

    // 2.通过IServiceManager::addService在ServiceManager中注册服务,此处服务的名称为“SurfaceFlinger”
    // publish surface flinger
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);

    // run surface flinger in this thread
    flinger->run();
    return 0;
}
      

由此可见,发布Binder服务需要先启动Binder线程池,然后通过IServiceManager::addService在ServiceManager中进行服务的注册。

4.4.3 客户端实现

BpSurfaceComposer需要实现ISurfaceComposer中的所有接口。我们以上文提到的createDisplay接口为例,来看看BpSurfaceComposer::createDisplay方法代码是如何实现的:

/*frameworks/native/libs/gui/ISurfaceComposer.cpp*/
    virtual sp<IBinder> createDisplay(const String8& displayName, bool secure)
    {
        Parcel data, reply;
        // 1.填写服务接口的唯一描述信息descriptor
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        // 2.通过Parcel写入发送参数
        data.writeString8(displayName);
        data.writeInt32(secure ? 1 : 0);
        // 3\. 调用remote()->transact将请求发送出去
        remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
        return reply.readStrongBinder();
    }
      

这段代码很简单,逻辑就是:通过Parcel写入调用参数进行打包,然后调用remote()->transact将请求发送出去。

4.4.4 获取服务

客户端在使用服务端的服务之前,需要先根据服务的名称向ServiceManager中查询获取到访问服务的句柄,才能通过BpSurfaceComposer::remote()函数拿到远端服务的代理后调用transact方法完成一次Binder数据发送。详细代码如下:

/*framworks/native/libs/gui/SurfaceComposerClient.cpp*/
void ComposerService::connectLocked() {
    // 1\. 需要查找的远端Binder服务名称为"SurfaceFlinger"
    const String16 name("SurfaceFlinger");
    // 2 .调用IServiceManager::getService封装接口获取远端服务代理并封装到BpSurfaceComposer中
    while (getService(name, &mComposerService) != NO_ERROR) {
        usleep(250000);
    }
    ...
}

/*frameworks/native/include/binder/IServiceManager.h*/
template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{   // 1\. 获取到ServiceManager的代理以访问ServiceManager
    const sp<IServiceManager> sm = defaultServiceManager();
    if (sm != nullptr) {
        // 2\. 通过getService获取具体的服务句柄,并使用interface_cast转换获取到BpSurfaceComposer对象
        *outService = interface_cast<INTERFACE>(sm->getService(name));
        if ((*outService) != nullptr) return NO_ERROR;
    }
    return NAME_NOT_FOUND;
}

/*frameworks/native/libs/binder/IServiceManager.cpp*/
sp<IServiceManager> defaultServiceManager()
{
    std::call_once(gSmOnce, []() {
        sp<AidlServiceManager> sm = nullptr;
        while (sm == nullptr) {
            //ProcessState::getContextObject(nullptr)获取到ServiceManager的访问句柄
            sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
            ...
            }
        }
    });
    return gDefaultServiceManager;
}

/*frameworks/native/libs/binder/ProcessState.cpp*/
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{    
    // 此处的参数“0”代表查找的是ServiceManager服务,这个是个特殊的地址,用于标识ServiceManager
    sp<IBinder> context = getStrongProxyForHandle(0);
    ...
    return context;
}
      

通过interface_cast这个方法来获取服务的接口对象,由这个方法本身根据是否是在同一个进程,来自动确定返回一个本地Binder还是远程Binder。interface_cast是一个模板方法,其源码如下:

/*frameworks/native/libs/binder/include/binder/IInterface.h*/
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
      

对于ISurfaceComposer来说,其实就是ISurfaceComposer::asInterface(obj),其定义如下:

/*frameworks/native/libs/binder/include/binder/IInterface.h*/
    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != nullptr) {                                           \
            //1.先使用queryLocalInterface尝试获取本地同一进程中的Binder对象
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            //2.失败则创建并返回远端Binder对象,封装成BpSurfaceComposer
            if (intr == nullptr) {                                      \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }   
      

由于都是模板定义,所以在理解的时候,将“##”替换成SurfaceComposer即可。

5 ServiceManager——Binder服务“大管家”

ServerManager(简称SM)的功能可以类比互联网中的DNS服务器,“IP地址”为0。每一个Binder服务都需要有一个唯一的名称,由SM来管理这些服务的注册和查找。另外,和DNS服务器本身也是服务器一样,SM也是一个标准的Binder Server,且Binder驱动中,也会通过特定handle = 0这个位置来访问ServiceManager。因此,分析SM我们可以完整的看到一个上层应用如何通过Binder驱动来构建一个Binder Server的过程。下面我们分析SM模块的的具体实现。

5.1 ServiceManager进程的启动

SM作为Binder服务的“大管家”,必须要保证在系统所有Binder服务启动之前就已经启动并处于正常工作状态。所以SM是在开机时由init程序解析init.rc加载时直接启动。如下所示:

/*framework/native/cmds/servicemanager/servicemanager.rc*/
service servicemanager /system/bin/servicemanager// 1.servicemanager是一个独立可执行文件
    class core animation
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote// 2.servicemanager重启后会导致zygote重启
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger// 3.servicemanager重启后会导致surfaceflinger重启
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    onrestart restart keystore
    onrestart restart gatekeeperd
    onrestart restart thermalservice
    writepid /dev/cpuset/system-background/tasks
    shutdown critical
      

由上可见,servicemanager是一个独立可执行文件,由C++编写,是一个独立运行的native进程,在系统开机时有init进程直接拉起。源码路径如下:

/framework/native/cmds/servicemanager/*

其main函数主要逻辑如下:

/*framework/native/cmds/servicemanager/main.cpp*/
int main(int argc, char** argv) {
    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }

    const char* driver = argc == 2 ? argv[1] : "/dev/binder";
    //1.通过initWithDriver会完成打开/dev/binder下的binder驱动设备和mmap内存映射动作
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);
    ps->setThreadPoolMaxThreadCount(0);
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
    //2.创建ServiceManager对象,并通过addService接口将自己注册为名为“manager”的Binder Server
    sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());
    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
        LOG(ERROR) << "Could not self register servicemanager";
    }

    IPCThreadState::self()->setTheContextObject(manager);
    ps->becomeContextManager(nullptr, nullptr);// 3.通知binder驱动将自己注册为binder服务大管家

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);

    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);

    while(true) {
        looper->pollAll(-1);// 4.循环等待其它模块请求服务
    }

    // should not be reached
    return EXIT_FAILURE;
}
      

主要做了如下四件事情:

  1. 通过调用ProcessState的initWithDriver静态接口,这其中会创建SM进程的ProcessState对象并完成进程的Binder初始化:先调用open_driver动作打开Binder驱动,然后调用mmap动作通知Binder驱动完成binder_mmap物理内存分配和虚拟内存映射的操作;
  2. 创建ServiceManager对象,并通过addService接口将SM自身注册为名为“manager”的Binder Server服务,也进一步说明SM自身本质上也是一个C++写的Binder Server服务进程;
  3. 调用ProcessState的becomeContextManager接口,通过binder_ioctl协议命令BINDER_SET_CONTEXT_MGR通知Binder设备驱动,将SM注册为binder服务“大管家”;
  4. 进入循环等待Binder Client进程的客户端进程访问请求。

5.2 ServiceManager进程Binder服务接口

我们看看ServiceManager.h接口文件的代码定义:

/*framework/native/cmds/servicemanager/ServiceManager.h*/
class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
public:
    ServiceManager(std::unique_ptr<Access>&& access);
    ~ServiceManager();
    ...
    // getService will try to start any services it cannot find
    // 1.根据名称查询Binder Server服务
    binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override;
    binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override;
     // 2.注册Binder Server服务
    binder::Status addService(const std::string& name, const sp<IBinder>& binder,
                              bool allowIsolated, int32_t dumpPriority) override;
    // 3.遍历列出所有已注册的Binder Server服务
    binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override;
    ...

};
      

根据上一节对Binder framework C++层的分析我们可以看到:ServiceManager继承自BnServiceManager,是一个Binder Server服务端实现。对客户端提供getService查询Service服务、addService注册Service服务以及listServices遍历所有已注册服务等核心功能接口。 其内部具体的实现是通过一个全局的名为mNameToService的ServiceMap类型(本质上还是一个map类型的集合)的变量记录维护着服务名称和具体的服务代理之间映射关系;以addService注册服务的实现代码为例:

/*framework/native/cmds/servicemanager/ServiceManager.cpp*/
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
    ...
    auto entry = mNameToService.emplace(name, Service {
        .binder = binder,
        .allowIsolated = allowIsolated,
        .dumpPriority = dumpPriority,
        .debugPid = ctx.debugPid,
    });
    ...
    return Status::ok();
}
      

5.3 libbinder中对访问ServiceManager接口的封装

源码路径:

frameworks/native/include/binder/IServiceManager.h frameworks/native/libs/binder/IServiceManager.cpp

这块逻辑相当于是Binder framework C++层的libbinder库作为Binder客户端对ServiceManager进程所提供的Binder服务端接口访问的封装。

IServiceManager的C++接口定义如下:

/*frameworks/native/include/binder/IServiceManager.h*/
class IServiceManager : public IInterface
{
public:
    ...
    // 1.根据名称查询Binder Server服务
    /**
     * Retrieve an existing service, blocking for a few seconds
     * if it doesn't yet exist.
     */
    virtual sp<IBinder>         getService( const String16& name) const = 0;

    /**
     * Retrieve an existing service, non-blocking.
     */
    virtual sp<IBinder>         checkService( const String16& name) const = 0;
     // 2.注册Binder Server服务
    /**
     * Register a service.
     */
    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                bool allowIsolated = false,
                                int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
    // 3.遍历列出所有已注册的Binder Server服务
    /**
     * Return list of all existing services.
     */
    // NOLINTNEXTLINE(google-default-arguments)
    virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;

    /**
     * Efficiently wait for a service.
     *
     * Returns nullptr only for permission problem or fatal error.
     */
    virtual sp<IBinder> waitForService(const String16& name) = 0;
    ...
};
      

普通的Binder服务我们需要通过ServiceManager来获取接口才能调用,那么ServiceManager的接口又该如何获得呢?在libbinder中,提供了一个defaultServiceManager方法来获取ServiceManager的代理,并且这个方法不需要传入参数。原因我们在驱动篇中也已经讲过了:Binder的实现中,为ServiceManager留了一个特殊的位置,不需要像普通服务那样通过标识去查找。defaultServiceManager代码如下:

/*frameworks/native/libs/binder/IServiceManager.cpp*/
sp<IServiceManager> defaultServiceManager()
{
    std::call_once(gSmOnce, []() {
        sp<AidlServiceManager> sm = nullptr;
        while (sm == nullptr) {
            sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
            if (sm == nullptr) {
                ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());
                sleep(1);
            }
        }

        gDefaultServiceManager = new ServiceManagerShim(sm);
    });

    return gDefaultServiceManager;
}
      

6 Binder Framework Java层

6.1 主要结构

Android应用使用Java语言开发,Binder Framework框架自然也是提供了相关Java接口。前面我们已经分析了Binder Framework C++层的完整实现。因此Java层完全不用重复实现,而是通过虚拟机提供的JNI机制,直接调用而复用C++层的实现。下面借用一张图描述Binder Framework Java层到C++层的调用关系。

Android Binder进程间通信机制

6.2 JNI衔接调用

JNI全称是Java Native Interface,这个是由Java虚拟机提供的机制。这个机制使得native代码可以和Java代码互相通讯。简单来说就是:我们可以在C/C++端调用Java代码,也可以在Java端调用C/C++代码。实际上,在Android中很多的服务或者机制都是在C/C++层实现的,想要将这些实现复用到Java层,就必须通过JNI进行衔接。其实这里面就是解决两个方向的调用问题:

  1. Java端的代码是如何调用的libbinder中的C++方法的? 以BinderProxy.java中的transact方法为例,其功能是实现Java层的Binder客户端使用服务端的远端代理完成一次Binder数据发送传输,简化代码实现如下:
/*frameworks/base/core/java/android/os/BinderProxy.java*/
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        ..
        try {
            return transactNative(code, data, reply, flags);
        } finally {
            ...
        }
    }

     /**
     * Native implementation of transact() for proxies
     */
    public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
      

可以看到方法transactNative是用native关键字修饰的,并且没有方法实现体,这些方法其实都是在C++中实现的。在android_util_Binder.cpp文件中的下面这段代码,定义了Java方法与C++方法的对应关系,并定义了真正的实现,简化代码实现如下:

/*frameworks/base/core/jni/android_util_Binder.cpp*/
// 集合中定义了Java方法与C++方法的对应关系
static const JNINativeMethod gBinderProxyMethods[] = {
     /* name, signature, funcPtr */
     ...
    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
     ...
};

// 真正的方法实现
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    ...
    // 1.获取BpBinder对象
    IBinder* target = getBPNativeData(env, obj)->mObject.get();
    ...
    // 2.调用libbinder中的BpBinder的transact接口实现真正的Binder传输
    status_t err = target->transact(code, *data, reply, flags);
    ...
    return JNI_FALSE;
}
      
  1. libbinder如何能够通知调用到Java层呢? 下面以libbinder中的BBinder::onTransact如何调用到Java中的Binder::onTransact为例进行分析:这段逻辑是在android_util_Binder.cpp中JavaBBinder::onTransact(JavaBBinder是BBinder子类)中借用虚拟机提供的CallBooleanMethod接口实现native方法调用Java Object上的方法实现。简化代码实现如下:
/*frameworks/base/core/jni/android_util_Binder.cpp*/
// JavaBBinder是BBinder的子类
class JavaBBinder : public BBinder
{
protected:
    ...
    status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
    {
        ...
        // 1\. CallBooleanMethod这个方法是由虚拟机提供的实现native方法来调用一个Java Object上的方法。这一行代码其实是在调用mObject上offset为mExecTransact的方法,
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
        ...
    }
    ...
};

const char* const kBinderPathName = "android/os/Binder";

static int int_register_android_os_Binder(JNIEnv* env)
{
    ...
    jclass clazz = FindClassOrDie(env, kBinderPathName);
    // 2\. 找到android/os/Binder.java中的execTransact方法
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    ...
    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}

/*frameworks/base/core/java/android/os/Binder.java*/
 // Entry point from android_util_Binder.cpp's onTransact
    @UnsupportedAppUsage
    private boolean execTransact(int code, long dataObj, long replyObj,
            int flags) {
        ...
        try {
            return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
        }
    }

    private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
            int callingUid) {
        ...
        try {
            ...
            if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) {
                ...
            } else {
                // 调用到java层的onTransact实现
                res = onTransact(code, data, reply, flags);
            }
        } catch (RemoteException|RuntimeException e) {
           ...
        } finally {
           ...
        }
        ...
    }
      

6.3 Java Binder服务实现举例

和C++层一样,这里我们还是通过一个具体的实例来看一下Java层的Binder服务是如何实现的。 以系统框架system_server进程的核心服务ActivityManager为例,下面是其实现的类图结构:

Android Binder进程间通信机制

IActivityManager接口定义了ActivityManager对外提供的功能接口,其子类都继承了这些接口。

  • IActivityManager.Stub.Proxy是提供给客户端调用的远程接口,获取到指向服务实现方的句柄BinderProxy,然后通过transact方法发送具体请求。
  • IActivityManager.Stub是服务端的实现,其中只有一个onTransact方法,该方法根据请求的code来对接每个请求,并直接调用ActivityManagerService中对应的方法。
  • ActivityManagerService是服务端接口功能真正的实现。

可以看到,这种组织架构和4.4.4小结中Binder C++层SurfaceFlinger服务基本是一样的。对于Android应用程序的开发者来说,系统对这些类进行了封装,所以我们不会直接接触到上图中的几个类,而是使用android.app.ActivityManager中的接口。那ActivityManager中的接口与上图的实现是什么关系呢。我们选取其中的一个方法来看一下:

/*frameworks/base/core/java/android/app/ActivityManager.java*/
  public List<RunningAppProcessInfo> getRunningAppProcesses() {
        try {
            return getService().getRunningAppProcesses();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
      

这个方法的实现调用了getService()中的方法,因此我们在来看一下getService()返回到到底是什么。

/*frameworks/base/core/java/android/app/ActivityManager.java*/
    @UnsupportedAppUsage
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    @UnsupportedAppUsage
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    // 1.通过访问ServiceManager按照服务名“activity”查询获取到远端服务的代理IBinder对象
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    // 2.调用asInterface将获取到的远端服务代理IBinder对象转换封装成客户端IActivityManager接口对象
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
      

这里其实是先通过IBinder b = ServiceManager.getService(“activity”); 向 ServiceManager查询获取到ActivityManager的远端服务代理Binder对象(该AMS系统核心服务在系统开机过程中提前在ServiceManager Binder“大管家”进程中注册,且服务名为“activity”);接着我们再来看一下asInterface(b)的实现:

/*gen/android/app/IActivityManager.java*/
public static android.app.IActivityManager asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof android.app.IActivityManager))) {
        return ((android.app.IActivityManager)iin);
      }
      return new android.app.IActivityManager.Stub.Proxy(obj);
    }
      

首先通过queryLocalInterface确定有没有本地Binder,如果有的话直接返回,否则创建一个android.app.IActivityManager.Stub.Proxy客户端代理对象。

6.4 AIDL机制

Android应用开发者对AIDL机制应该不会陌生,AIDL全称是Android Interface Definition Language,它是Android SDK提供的一种机制。借助这个机制,应用可以提供跨进程的服务供其他应用使用。aidl文件使用Java语言的语法来定义,每个.aidl文件只能包含一个interface,并且要包含interface的所有方法声明。。 下面是一个aidl文件的示例:

// IMyAidlInterface.aidl
package com.example.myapplication;
// Declare any non-default types here with import statements
interface IMyAidlInterface {

    void add(int a, long b);

    void sum(in int[] numbers);
}
      

这个文件中包含了两个接口add和sum。对于包含.aidl文件的工程,Android IDE在编译项目的时候,会为aidl文件生成对应的Java文件。针对上面这个aidl文件编译后生成的java文件中包含的结构如下图所示:

Android Binder进程间通信机制

在这个生成的Java文件中,包括了:

  1. 公共接口定义:一个名称为IMyAildInterface的interface,该interface继承自android.os.IInterface并且包含了我们在aidl文件中声明的接口方法add和sum。
  2. Binder服务端实现封装:IMyAildInterface中包含了一个名称为Stub的静态内部类,这个类是一个抽象类,它继承自android.os.Binder并且实现了IMyAildInterface接口。这个类中包含了一个onTransact方法。
  3. Binder客户端实现封装:Stub内部又包含了一个名称为Proxy的静态内部类,Proxy类同样实现了IMyAildInterface接口,内部通过持有android.os.IBinder类型的mRemote远程服务代理对象,调用其transact方法实现Binder访问。

从这个过程也可以看出,AIDL是典型的代理设计模式的思想体现,本质上是对Java层Binder逻辑在编译时自动简化封装,省去应用开发者去写公共且繁琐的实现代理模式相关代码。

7 总结