乐趣区

Binder驱动之设备初始化

Binder 是 Android 使用的进程间通信工具。Android 本身是一个复杂的操作系统,运行着众多的应用和服务,它们之间的通信就显得尤为重要。应用程序在使用 Binder 进行进程间通信时,实现方法非常简单,只需要编写 AIDL 文件,系统在编译时就会生成 IPC 通信代码。这种简单的方式也使得应用开发者可以不用了解 Binder 底层的传输机制。但对于系统开发人员,熟知 Binder 的原理是必要的,在分析解决问题时多数情况都会和 Binder 纠缠在一起。本文讲解使用 Binder 的第一步,打开和初始化一个 Binder 设备。

打开 Binder 设备

Binder 驱动在初始化时注册为一个字符设备“/dev/binder”,并实现了 poll、ioctl、mmap 等接口。应用层对 binder 的控制都是通过 ioctl 完成的,而 IPC 通信的内容就是通过 ioctl 的命令“BINDER_WRITE_READ”中传输的。

Android 中大多数的 Binder 通信都是通过 ProcessState 来初始化 Binder 设备的。

frameworks/native/libs/binder/ProcessState.cpp

#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
......

ProcessState::ProcessState()
    : mDriverFD(open_driver()) // 打开 binder 设备
    , mVMStart(MAP_FAILED)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{if (mDriverFD >= 0) {
        // XXX Ideally, there should be a specific define for whether we
        // have mmap (or whether we could possibly have the kernel module
        // availabla).
#if !defined(HAVE_WIN32_IPC)
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        // 映射 binder 地址空间
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); 
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1; 
        }
#else
        mDriverFD = -1; 
#endif
    }   

    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

可以看到,ProcessState 构造过程中先打开 Binder 设备获得设备描述符,然后通过 mmap 映射了 (1M – 8K) 大小的地址空间用于数据传输。先看一下 open_driver()。

frameworks/native/libs/binder/ProcessState.cpp

static int open_driver()                                                                                                                                                                                    
{int fd = open("/dev/binder", O_RDWR);
    if (fd >= 0) {fcntl(fd, F_SETFD, FD_CLOEXEC);
        int vers = 0;
        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 does not match user space protocol!");
            close(fd);
            fd = -1;
        }
        size_t maxThreads = 15;
        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'/dev/binder'failed: %s\n", strerror(errno));
    }
    return fd;
}

这里打开设备“/dev/binder”,然后验证版本信息。之后通过 BINDER_SET_MAX_THREADS 设置一个进程中最大的 Binder 线程数,在驱动中设置给 proc->max_threads。代码中设置的值为 15,但驱动中的计数是从 0 开始的,所以实际上 Binder 最大线程数是 16。接下来看下驱动的 open 函数,比较简单,就是创建 Binder 进程结构体并初始化。

drivers/staging/android/binder.c

static int binder_open(struct inode *nodp, struct file *filp)
{
    struct binder_proc *proc; // Binder 进程结构体
    ......
    proc = kzalloc(sizeof(*proc), GFP_KERNEL);
    if (proc == NULL)
        return -ENOMEM;
    get_task_struct(current);
    proc->tsk = current;
    INIT_LIST_HEAD(&proc->todo);
    init_waitqueue_head(&proc->wait);
    proc->default_priority = task_nice(current); // 缺省优先级

    binder_lock(__func__);

    binder_stats_created(BINDER_STAT_PROC); // 记录 binder 状态
    hlist_add_head(&proc->proc_node, &binder_procs);
    proc->pid = current->group_leader->pid;
    INIT_LIST_HEAD(&proc->delivered_death);
    filp->private_data = proc; // 设备私有数据设置为 binder 进程结构体

    binder_unlock(__func__);
    ......
}

Bind_proc 用于管理 Binder 进程,一个进程只会有一个 binder_proc,记录了 Binder 传输的所有信息。下面看一下 binder_proc 的定义。

drivers/staging/android/binder.c

struct binder_proc {
    struct hlist_node proc_node;  // 该 binder 进程的节点,挂载到 binder_procs 链表中
    struct rb_root threads; // binder 线程 ID 红黑树
    struct rb_root nodes; // binder 实体对象红黑树
    struct rb_root refs_by_desc; // binder 引用对象红黑树,以 handle 为 key
    struct rb_root refs_by_node; // binder 引用对象红黑树,以 node 为 key
    int pid; // 进程 ID
    struct vm_area_struct *vma;  // 该进程的虚拟地址空间指针
    struct mm_struct *vma_vm_mm; // 该进程的内存结构体
    struct task_struct *tsk; // 该进程的 task 结构体
    struct files_struct *files; // 该进程的 file 结构体
    struct hlist_node deferred_work_node; // 延迟工作队列节点,挂载到 binder_deferred_list 链表中
    int deferred_work; // 延迟工作的类型
    void *buffer; // 映射的内核空间地址
    ptrdiff_t user_buffer_offset; // 映射的内核空间与用户空间的偏移

    struct list_head buffers; // 全部 buffer 链表
    struct rb_root free_buffers; // 空闲 buffer 红黑树
    struct rb_root allocated_buffers; // 已分配的 buffer 红黑树
    size_t free_async_space; // 剩余异步传输空间大小

    struct page **pages; // 物理内存页
    size_t buffer_size; // 映射的 buffer 大小
    uint32_t buffer_free; // 剩余可用 buffer 大小
    struct list_head todo; // 进程工作链表
    wait_queue_head_t wait; // 等待队列
    struct binder_stats stats; // binder 统计信息
    struct list_head delivered_death; // 已经发布的死亡通知链表
    int max_threads; // 最大线程数
    int requested_threads; // 请求的线程数
    int requested_threads_started; // 请求的线程已经启动的数量
    int ready_threads; // 已经准备好的线程数
    long default_priority; // 默认优先级
    struct dentry *debugfs_entry; // debugf 入口指针
};

内存空间映射

创建 binder_proc,完成初始化后,应用层会调用 mmap()来映射地址空间。

drivers/staging/android/binder.c

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
    int ret;
    struct vm_struct *area;
    struct binder_proc *proc = filp->private_data;
    const char *failure_string;
    struct binder_buffer *buffer;

    if (proc->tsk != current)
        return -EINVAL;

    // 映射空间不能大于 4M
    if ((vma->vm_end - vma->vm_start) > SZ_4M)
        vma->vm_end = vma->vm_start + SZ_4M;
......
// fork 的子进程无法复制映射空间,并且不允许修改写属性
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
......
// 获取内核虚拟地址空间
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
......
proc->buffer = area->addr;
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
mutex_unlock(&binder_mmap_lock);
......
// 创建物理页结构体
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
......
proc->buffer_size = vma->vm_end - vma->vm_start;

vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
// 分配一个物理页,并映射到虚拟地址空间
    if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {
......
// 创建 buffers 链表,插入第一个 free buffer
    buffer = proc->buffer;
    INIT_LIST_HEAD(&proc->buffers);
    list_add(&buffer->entry, &proc->buffers);
    buffer->free = 1;
binder_insert_free_buffer(proc, buffer);
// 异步传输可用空间大小设置为映射大小的一半
    proc->free_async_space = proc->buffer_size / 2;
    barrier();
    proc->files = get_files_struct(current);
    proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
......
}

Binder_mmap()主要完成了内核虚拟地址空间分配,地址空间映射,binder_proc 中内存相关参数的初始化等工作。真正的物理页分配时通过 binder_update_page_range()进行的,这里只分配了一个物理页放入 free_buffers 树中。之后的 Binder 传输过程中会根据需要分配和回收 buffer。

drivers/staging/android/binder.c

static int binder_update_page_range(struct binder_proc *proc, int allocate,
                    void *start, void *end,
                    struct vm_area_struct *vma)
{
    void *page_addr;
    unsigned long user_page_addr;
    struct vm_struct tmp_area;
    struct page **page;
struct mm_struct *mm;
......
// 只有 mmap 时 vma 不为 NULL,其他情况都会根据 proc 来获取内存相关数据
    if (vma)
        mm = NULL;
else
    // 获取内存描述符,并增加用户计数,防止 mm_struct 被释放
        mm = get_task_mm(proc->tsk);

    if (mm) {down_write(&mm->mmap_sem);
        vma = proc->vma;
        if (vma && mm != proc->vma_vm_mm) {
            pr_err("%d: vma mm and task mm mismatch\n",
                proc->pid);
            vma = NULL;
        }
}

    // 回收内存时 allocate 为 0
    if (allocate == 0)
        goto free_range;
......
    // 循环分配物理页,每次分配一页
    for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
        int ret;
        struct page **page_array_ptr;
        page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];

        BUG_ON(*page);
        // 分配一个物理页,保存地址到 proc 中
        *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
        ......
        tmp_area.addr = page_addr;
        tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */;
        page_array_ptr = page;
        // 建立页表与物理页的映射
        ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr);
        ......
        user_page_addr =
            (uintptr_t)page_addr + proc->user_buffer_offset;
        // 插入物理页到用户虚拟地址空间
        ret = vm_insert_page(vma, user_page_addr, page[0]);
        ......
}
    if (mm) {up_write(&mm->mmap_sem);
        // 减少内存描述符的用户计数
        mmput(mm);
    }
return 0;

free_range:
    for (page_addr = end - PAGE_SIZE; page_addr >= start;
         page_addr -= PAGE_SIZE) {page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
        if (vma)
            // 解除用户虚拟地址空间与物理页的映射
            zap_page_range(vma, (uintptr_t)page_addr +
                proc->user_buffer_offset, PAGE_SIZE, NULL);
err_vm_insert_page_failed:
        // 解除物理页与内核页表的映射
        unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
err_map_kernel_failed:
        // 释放物理页
        __free_page(*page);
        *page = NULL;
err_alloc_page_failed:
        ;
    }
........
}

ProcessState 构造函数执行完,也就完成了对 Binder 设备的初始化和内存空间映射。应用层获得了 Binder 设备的描述符 mDriverFD,之后通过 ioctl 操作就可以进行 IPC 传输。

第一个 Binder 线程

之前分析到,一个 Binder 进程最多可以有 16 个 Binder 线程,每个 Binder 线程都可以独立进行 Binder 传输。第一个 Binder 线程一般在创建 ProcessState 对象后,通过 ProcessState::startThreadPool()来创建。

frameworks/native/libs/binder/ProcessState.cpp

class PoolThread : public Thread
{
public:
    PoolThread(bool isMain)                                                                                                                                                                                 
        : mIsMain(isMain)
    { }

protected:
    virtual bool threadLoop()
{
    // 通过 startThreadPool 创建时,mIsMain 是 true,为主线程
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};
......
void ProcessState::startThreadPool()
{AutoMutex _l(mLock);
// 第一个线程必须通过 startThreadPool 来创建
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }   
}
......
void ProcessState::spawnPooledThread(bool isMain)                                                                                                                                                           
{if (mThreadPoolStarted) {
    // 构造 binder 名字:Binder_XX
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}

最终真正的 Binder 线程创建是通过 IPCThreadState::joinThreadPool()来实现的。

frameworks/native/libs/binder/IPCThreadState.cpp

void IPCThreadState::joinThreadPool(bool isMain)
{
......
// 主线程使用命令 BC_ENTER_LOOPER,以后再创建线程都通过 BC_REGISTER_LOOPER
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
......
// 设置线程为前台 group,保证 Binder 传输初始化
    set_sched_policy(mMyThreadId, SP_FOREGROUND);
     
    status_t result;
do { 
    // 清理命令队列
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        // 获取一个命令并执行
        result = getAndExecuteCommand();
        ......
        // 非主线程时,如果线程不在需要将退出。主线程将一直存活
        if(result == TIMED_OUT && !isMain) {break;}    
    } while (result != -ECONNREFUSED && result != -EBADF);
...... 
// 线程退出命令   
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

joinThreadPool()发送命令 BC_ENTER_LOOPER 创建第一个 Binder 线程。之后进入循环,通过 getAndExecuteCommand()获取命令并执行。简单看下是如何与驱动交互的。

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd; 

    // 与 Binder 驱动进行交互
result = talkWithDriver();
    if (result >= NO_ERROR) {size_t IN = mIn.dataAvail();
......
// 执行命令
        result = executeCommand(cmd);
        ......
        // 执行命令时可能将线程设置为后台 group,再次设置为前台 group
        set_sched_policy(mMyThreadId, SP_FOREGROUND);
} 

    return result;
}
......
status_t IPCThreadState::talkWithDriver(bool doReceive)                                                                                                                                                     
{
......
// 写数据为 mOut
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();

// This is what we'll read.
// 读数据为 mIn
    if (doReceive && needRead) {bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();} else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
......
   // 使用 BINDER_WRITE_READ 对驱动进行读写
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
......
} 

应用对 Binder 驱动的读写是通过 ioctl 的 BINDER_WRITE_READ 命令完成的,读写数据为 mIn 和 mOut。mIn 和 mOut 为 Parcel 实例,Binder 的数据都需要经过 Parcel 将数据序列化后才传输的,应用接收的数据再经过反序列化读出。我们先关心线程的创建,看一下驱动中对 BC_ENTER_LOOPER 的处理。

drivers/staging/android/binder.c

static int binder_thread_write(struct binder_proc *proc,
            struct binder_thread *thread,
            binder_uintptr_t binder_buffer, size_t size,
            binder_size_t *consumed)
{
......
        case BC_ENTER_LOOPER:
            ......
            // 设置 thread looper 状态
            thread->looper |= BINDER_LOOPER_STATE_ENTERED;
            break;
......
}
......
static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
    struct binder_thread *thread = NULL;
    struct rb_node *parent = NULL;
    struct rb_node **p = &proc->threads.rb_node;

    // 在 proc threads 树上查找线程
    while (*p) {
        parent = *p;
        thread = rb_entry(parent, struct binder_thread, rb_node);

        if (current->pid < thread->pid)
            p = &(*p)->rb_left;
        else if (current->pid > thread->pid)
            p = &(*p)->rb_right;
        else
            break;
}
// 如果 threads 树上没有找到线程则创建一个线程,并插入到树中
    if (*p == NULL) {thread = kzalloc(sizeof(*thread), GFP_KERNEL);
        if (thread == NULL)
            return NULL;
        binder_stats_created(BINDER_STAT_THREAD);
        thread->proc = proc;
        thread->pid = current->pid;
        init_waitqueue_head(&thread->wait);
        INIT_LIST_HEAD(&thread->todo);
        rb_link_node(&thread->rb_node, parent, p);
        rb_insert_color(&thread->rb_node, &proc->threads);
        thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
        thread->return_error = BR_OK;
        thread->return_error2 = BR_OK;
    }
    return thread;
}
......
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
......
// 在 binder 进程中获取当前线程的 binder 线程
thread = binder_get_thread(proc);
......
    switch (cmd) {
case BINDER_WRITE_READ: {if (bwr.write_size > 0) {
            // 写数据
            ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
        ......
        if (bwr.read_size > 0) {
            // 读数据
            ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
        ......
        if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
            ret = -EFAULT;
            goto err;
        }
        break;BC_ENTER_LOOPER
    }
......
}

整理一下第一个 Binder 线程创建的流程,

  • 应用在创建 ProcessState 实例后调用 startThreadPool()创建了一个线程 Binder_1。
  • Binder_1 运行时调用 IPCThreadState::joinThreadPool()跟驱动交互,发送命令 BC_ENTER_LOOPER。
    驱动在读写数据时先创建一个 Binder 线程,加入到 proc->threads 树上。这是该红黑树上应该只有一个节点,其 pid 为 Binder_1 的 pid。
  • 驱动执行命令 BC_ENTER_LOOPER,设置 Binder 线程 looper 状态为 BINDER_LOOPER_STATE_ENTERED。
  • 驱动调用 binder_thread_read()等待数据写入。

后续 Binder 线程的创建

进程中的第一个 Binder 线程创建后,再创建 Binder 线程有两种方式。

  • 直接调用 IPCThreadState::joinThreadPool():一些 Native Service 使用这个方式,像 MediaServer,DrmServer。
  • 通过 ProcessState::spawnPooledThread(false):处理 BR_SPAWN_LOOPER 命令时执行。

大部分后续 Binder 线程的创建都是通过 BR_SPAWN_LOOPER 命令来完成的。这个命令是由 Binder 驱动发出的。当 Binder 驱动检查到 Binder 线程不足时,就会发送 BR_SPAWN_LOOPER 给应用层,用来创建 Binder 线程。

drivers/staging/android/binder.c

static int binder_thread_read(struct binder_proc *proc,
                  struct binder_thread *thread,
                  binder_uintptr_t binder_buffer, size_t size,
                  binder_size_t *consumed, int non_block)
{
......
// 是否从 proc 中获取工作项
    wait_for_proc_work = thread->transaction_stack == NULL &&
                list_empty(&thread->todo);
......
// 设置状态为 Binder 线程正在等待处理
thread->looper |= BINDER_LOOPER_STATE_WAITING;
// 如果处理 proc 工作,则让 ready_threads 加 1
    if (wait_for_proc_work)
        proc->ready_threads++;

    binder_unlock(__func__);
......
// 线程进入休眠,等待数据到来
if (wait_for_proc_work) {
......
            ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    } else {
        ......
            ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}

    binder_lock(__func__);

// 如果处理 proc 工作,则让 ready_threads 减 1,表面 Binder 线程开始处理数据

    if (wait_for_proc_work)
        proc->ready_threads--;
    // 移除 Binder 线程等待处理状态
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
......
// 如果没有剩余的可用 Binder 线程,并且没有达到最大线程数,则发送 BR_SPAWN_LOOPER
    if (proc->requested_threads + proc->ready_threads == 0 &&
        proc->requested_threads_started < proc->max_threads &&
        (thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
         BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
         /*spawn a new thread if we leave this out */) {
        proc->requested_threads++;
        binder_debug(BINDER_DEBUG_THREADS,
                 "%d:%d BR_SPAWN_LOOPER\n",
                 proc->pid, thread->pid);
        if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
            return -EFAULT;
        binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
    }
    return 0;
}

当进程中没有剩余可用的 Binder 线程时,驱动就会发送 BR_SPAWN_LOOPER 命令,应用层接收到该命令则执行 spawnPooledThread(false)。这个函数在上面分析过,会向驱动发送 BC_REGISTER_LOOPER 命令。

drivers/staging/android/binder.c

static int binder_thread_write(struct binder_proc *proc,
            struct binder_thread *thread,
            binder_uintptr_t binder_buffer, size_t size,
            binder_size_t *consumed)
{
    ......
        case BC_REGISTER_LOOPER:
            ......
            } else {
                // 更新 proc 中线程状态计数
                proc->requested_threads--;
                proc->requested_threads_started++;
            }
            // 设置 thread looper 状态
            thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
            break;
......
}

可以看到,proc 中线程相关的计数有三个,

  • ready_threads:这个计数会在处理 proc 工作项时更新,表明有多少 Binder 线程正在等待处理命令。
  • requested_threads:驱动申请创建 Binder 线程时将该计数 +1,应用层完成线程创建后向驱动注册时发送 BC_REGISTER_LOOPER 会将计数 -1。所以 Binder 线程创建流程结束后该计数应该为 0。
  • requested_threads_started:表明已经启动了多少 Binder 线程。但是 Binder 主线程时通过 BC_ENTER_LOOPER 建立的,不更新该计数。所以最大的 Binder 线程数是(max_threads + 1)。

Binder 线程创建流程

根据上面分析,可以知道 Binder 线程有两种创建方式,

  • Binder 主线程:在 Binder 进程初始化时创建了一个线程,并发送 BC_ENTER_LOOPER 给 Binder 驱动,注册为主线程。主线程在一个 Binder 进程中只有一个,且不能销毁。
  • Binder 辅线程:在 Binder 进程没有空余 Binder 线程时,由 Binder 驱动发送 BR_SPAWN_LOOPER 创建。应用层创建一个线程通过 BC_REGISTER_LOOPE 进行注册。Binder 辅线程可以有多个,在不需要时可以销毁。

上图是对 Binder 线程创建流程的简单整理。可以看到如果 Binder 主线程接收到消息就会再创建一个 Binder 线程,之后如果接收消息时没有空余线程才会创建。所以在一些 Native Service 中,会在初始化时就调用 joinThreadPool()创建一个辅线程,这样 Service 在开始运行时就会有两个 Binder 线程,因为它们很明确一定会使用跨进程通信。

退出移动版