Android binder 机制驱动核心源码详解_binder_thread_read

前言

应用程序中执行 getService() 需与 ServiceManager 通过 binder 跨进程通信,此过程中会贯穿 Framework、Natve 层以及 Linux 内核驱动。

binder 驱动的整体分层如上图,下面先来宏观的了解下 getService() 在整个 Android 系统中的调用栈,ServiceManager 本身的获取:

与 ServiceManager 进行 IPC 通信:

「本文将主要分析此过程中 binder 驱动具体承担了哪些工作」,也就是上图中 IPCThreadState 与 binder 驱动的 ioctl 调用。

binder 驱动中做的工作可以总结为以下几步:

  • 准备数据,根据命令分发给具体的方法去处理
  • 找到目标进程的相关信息
  • 将数据一次拷贝到目标进程所映射的物理内存块
  • 记录待处理的任务,唤醒目标线程
  • 调用线程进入休眠
  • 目标进程直接拿到数据进行处理,处理完后唤醒调用线程
  • 调用线程返回处理结果

在源码中实际会执行到的函数主要包括:

  • binder_ioctl()
  • binder_get_thread()
  • binder_ioctl_write_read()
  • binder_thread_write()
  • binder_transaction()
  • binder_thread_read()

下面按照这些 binder 驱动中的函数,以工作步骤为脉络,深入分析驱动中的源码执行逻辑,彻底搞定 binder 驱动!

1.binder_ioctl()

在 IPCThreadState 中通过系统调用 ioctl 陷入系统内核,调用到 binder_ioctl() 方法:

ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)

binder_ioctl() 方法中会根据 BINDER_WRITE_READ、BINDER_SET_MAX_THREADS 等不同 cmd 转调到不同的方法去执行,这里我们只关注 BINDER_WRITE_READ,代码如下:

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
    int ret;
    //拿到调用进程在 binder_open() 中记录的 binder_proc
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    binder_lock(__func__);
    //获取调用线程 binder_thread
    thread = binder_get_thread(proc);
    switch (cmd) {
    case BINDER_WRITE_READ:
      //处理 binder 数据读写,binder IPC 通信的核心逻辑
     ret = binder_ioctl_write_read(filp, cmd, arg, thread);
     if (ret)
      goto err;
     break;
    ...
}

之前文章介绍过 binder_open() 方法, binder_open() 方法主要做了两个工作
1、创建及初始化每个进程独有一份的、用来存放 binder 相关数据的 binder_proc 结构体
2、将 binder_proc 记录起来,方便后续使用。

正是通过 file 的 private_data 来记录的:

static int binder_open(struct inode *nodp, struct file *filp){
    ...
    filp->private_data = proc;
    ...
}

拿到调用进程后,进一步通过 binder_get_thread() 方法拿到调用线程,然后就交给 binder_ioctl_write_read() 方法去执行具体的 binder 数据读写了。

可见 binder_ioctl() 方法本身的逻辑非常简单,将数据 arg 透传了出去。
下面分别来看 binder_get_thread()、binder_ioctl_write_read() 这两个方法。

2.binder_get_thread()

static struct binder_thread *binder_get_thread(
                            struct binder_proc *proc){
    struct binder_thread *thread = NULL;
    struct rb_node *parent = NULL;
    //从 proc 中获取红黑树根节点
    struct rb_node **p = &proc->threads.rb_node; 
    //查找 pid 等于当前线程 id 的thread,该红黑树以 pid 大小为序存放
    while (*p) {
        parent = *p;
        thread = rb_entry(paren
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值