【Binder 机制】分析 Android 内核源码中的 Binder 驱动源码 binder.c ( googlesource 中的 Android 内核源码 | 内核源码下载 )(二)

二、分析 Binder 驱动源码 binder.c



1、binder_ioctl


在 Android Native 层中的 service_manager.c 中的 main 函数中 , 调用了 binder_become_context_manager(bs) , 将自己注册成 Binder 进程的上下文 , 其中调用的 ioctl 方法是内核中的方法 , 这是 IO Control 的简称 ;


int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}


上面调用的 ioctl 方法 , 就是下面的内核中的 Binder 驱动源码 binder.c 中的 static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 方法 ;


Native 层传入的 cmd 参数是 BINDER_SET_CONTEXT_MGR , 因此这里的 switch 分支走 case BINDER_SET_CONTEXT_MGR: 分支 , 执行 binder_ioctl_set_ctx_mgr(filp, NULL) 方法 ;


case BINDER_SET_CONTEXT_MGR:
  ret = binder_ioctl_set_ctx_mgr(filp, NULL);
  if (ret)
    goto err;
  break;


binder.c 相关代码如下 :


static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret;
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    /*pr_info("binder_ioctl: %d:%d %x %lx\n",
    proc->pid, current->pid, cmd, arg);*/
    binder_selftest_alloc(&proc->alloc);
    trace_binder_ioctl(cmd, arg);
    ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    if (ret)
  goto err_unlocked;
    thread = binder_get_thread(proc);
    if (thread == NULL) {
  ret = -ENOMEM;
  goto err;
    }
    switch (cmd) {
    case BINDER_SET_CONTEXT_MGR:
  ret = binder_ioctl_set_ctx_mgr(filp, NULL);
  if (ret)
    goto err;
  break;
    default:
  ret = -EINVAL;
  goto err;
    }
    ret = 0;
err:
    if (thread)
  thread->looper_need_return = false;
    wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    if (ret && ret != -EINTR)
  pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
    trace_binder_ioctl_done(ret);
    return ret;
}


完整代码参考 https://android.googlesource.com/kernel/common/+/refs/heads/android-mainline/drivers/android/binder.c



2、binder_ioctl_set_ctx_mgr


在 binder_ioctl 方法中调用了 binder_ioctl_set_ctx_mgr 方法 ,


static int binder_ioctl_set_ctx_mgr(struct file *filp,
        struct flat_binder_object *fbo)
{
    int ret = 0;
    // 获取 binder_proc 结构体, 该结构体用于存放 IPC 跨进程请求相关信息 
    // mmap 一次拷贝机制也与该结构体相关 
    struct binder_proc *proc = filp->private_data;
    struct binder_context *context = proc->context;
    // 该 binder_node 相当于 Binder 的实体
    struct binder_node *new_node;
    kuid_t curr_euid = current_euid();
    mutex_lock(&context->context_mgr_node_lock);
    if (context->binder_context_mgr_node) {
  pr_err("BINDER_SET_CONTEXT_MGR already set\n");
  ret = -EBUSY;
  goto out;
    }
    ret = security_binder_set_context_mgr(proc->tsk);
    if (ret < 0)
  goto out;
    if (uid_valid(context->binder_context_mgr_uid)) {
  if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
    pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
          from_kuid(&init_user_ns, curr_euid),
          from_kuid(&init_user_ns,
      context->binder_context_mgr_uid));
    ret = -EPERM;
    goto out;
  }
    } else {
  context->binder_context_mgr_uid = curr_euid;
    }
    // 创建 Binder 实体 
    new_node = binder_new_node(proc, fbo);
    if (!new_node) {
  ret = -ENOMEM;
  goto out;
    }
    // 设置 Binder 实体 , 强引用和弱引用次数 + 1
    binder_node_lock(new_node);
    new_node->local_weak_refs++;
    new_node->local_strong_refs++;
    new_node->has_strong_ref = 1;
    new_node->has_weak_ref = 1;
    context->binder_context_mgr_node = new_node;
    binder_node_unlock(new_node);
    binder_put_node(new_node);
out:
    mutex_unlock(&context->context_mgr_node_lock);
    return ret;
}


完整代码参考 https://android.googlesource.com/kernel/common/+/refs/heads/android-mainline/drivers/android/binder.c


上一篇:记一次线上问题 → 对 MySQL 的 ON UPDATE CURRENT_TIMESTAMP 的片面认知


下一篇:MongDB查询性能分析——explain 结果详解