android binder机制---Binder驱动

4 Binder驱动

binder机制到底是如何从代理对象找到其对应的binder实体呢?其实,在binder驱动层,还有个与之相对的结构,

叫做binder_proc。示意图如下,

 

Binder驱动是Android专用的,但底层的驱动架构与Linux驱动一样。binder驱动在以misc设备进行注册,作为虚拟

字符设备,没有直接操作硬件,只是对设备内存的处理。主要是驱动设备的打开 (binder_open),数据操作(binder_ioctl)。

用户态的程序调用Kernel层驱动是需要陷入内核态,进行系统调用(syscall),比如打开Binder驱动方法的调用链为: 

open-> __open() -> binder_open()。 open()为用户空间的方法,__open()便是系统调用中相应的处理方法,通过查找,

对应调用到内核binder驱动的binder_open()方法,至于其他的从用户态陷入内核态的流程也基本一致。

 

简单说,当用户空间调用open()方法,最终会调用binder驱动的binder_open()方法; ioctl()方法也是同理,在BInder

系列的后续文章从用户态进入内核态,都依赖于系统调用过程。

Kernel/drivers/staging/android/ 路径下的binder.c的binder_open方法如下,

 
  1. static int binder_open(struct inode *nodp, struct file *filp)

  2. {

  3. struct binder_proc *proc;

  4.  
  5. proc = kzalloc(sizeof(*proc), GFP_KERNEL); // 为binder_proc结构体在分配kernel内存空间

  6. if (proc == NULL)

  7. return -ENOMEM;

  8. get_task_struct(current);

  9. proc->tsk = current; //将当前线程的task保存到binder进程的tsk

  10. INIT_LIST_HEAD(&proc->todo); //初始化todo列表

  11. init_waitqueue_head(&proc->wait); //初始化wait队列

  12. proc->default_priority = task_nice(current); //将当前进程的nice值转换为进程优先级

  13.  
  14. binder_lock(__func__); //同步锁,因为binder支持多线程访问

  15. binder_stats_created(BINDER_STAT_PROC); //BINDER_PROC对象创建数加1

  16. hlist_add_head(&proc->proc_node, &binder_procs); //将proc_node节点添加到binder_procs为表头的队列

  17. proc->pid = current->group_leader->pid;

  18. INIT_LIST_HEAD(&proc->delivered_death);

  19. filp->private_data = proc; //file文件指针的private_data变量指向binder_proc数据

  20. binder_unlock(__func__); //释放同步锁

  21.  
  22. return 0;

  23. }

创建binder_proc对象,并把当前进程等信息保存到binder_proc对象,该对象管理IPC所需的各种信息并拥有其他

结构体的根结构体;再把binder_proc对象保存到文件指针filp,以及把binder_proc加入到全局链表binder_procs。

Binder驱动中通过static HLIST_HEAD(binder_procs);,创建了全局的哈希链表binder_procs,用于保存所有的

binder_proc队列,每个进程新创建的binder_proc对象都会加入binder_procs链表中。

binder_proc结构体重要的部分如下,

 
  1. struct binder_proc

  2. {

  3. struct hlist_node proc_node;

  4. struct rb_root threads;

  5. struct rb_root nodes;

  6. struct rb_root refs_by_desc;

  7. struct rb_root refs_by_node;

  8. int pid;

  9. . . . .

  10. };

其中的那4个rb_root域,“rb”的意思是“red black”,可见binder_proc里搞出了4个红黑树。

其中,nodes树用于记录binder实体,refs_by_desc树和refs_by_node树则用于记录binder代理。之所以会有两个

代理树,是为了便于快速查找,我们暂时只关心其中之一就可以了。threads树用于记录执行传输动作的线程信息。

  在一个进程中,有多少“被其他进程进行跨进程调用的”binder实体,就会在该进程对应的nodes树中生成多少个红

黑树节点。另一方面,一个进程要访问多少其他进程的binder实体,则必须在其refs_by_desc树中拥有对应的引用

节点。

这4棵树的节点类型是不同的,threads树的节点类型为binder_thread,nodes树的节点类型为binder_node,

refs_by_desc树和refs_by_node树的节点类型相同,为binder_ref。这些节点内部都会包含rb_node子结构,该结构

专门负责连接节点的工作,和前文的hlist_node有点儿异曲同工,这也是linux上一个常用的小技巧。我们以nodes树

为例,其示意图如下:

 

rb_node和rb_root的定义如下:

 
  1. struct rb_node

  2. {

  3. unsigned long rb_parent_color;

  4. #define RB_RED 0

  5. #define RB_BLACK 1

  6. struct rb_node *rb_right;

  7. struct rb_node *rb_left;

  8. } __attribute__((aligned(sizeof(long))));

  9. /* The alignment might seem pointless, but allegedly CRIS needs it */

  10.  
  11. struct rb_root

  12. {

  13. struct rb_node *rb_node;

  14. };

binder_node的定义如下:

 
  1. struct binder_node

  2. {

  3. int debug_id;

  4. struct binder_work work;

  5. union {

  6. struct rb_node rb_node;

  7. struct hlist_node dead_node;

  8. };

  9. struct binder_proc *proc;

  10. struct hlist_head refs;

  11. int internal_strong_refs;

  12. int local_weak_refs;

  13. int local_strong_refs;

  14. void __user *ptr; // 注意这个域!

  15. void __user *cookie; // 注意这个域!

  16. unsigned has_strong_ref:1;

  17. unsigned pending_strong_ref:1;

  18. unsigned has_weak_ref:1;

  19. unsigned pending_weak_ref:1;

  20. unsigned has_async_transaction:1;

  21. unsigned accept_fds:1;

  22. unsigned min_priority:8;

  23. struct list_head async_todo;

  24. };

nodes树是用于记录binder实体的,所以nodes树中的每个binder_node节点,必须能够记录下相应binder实体的

信息。因此请大家注意binder_node的ptr域和cookie域。

另一方面,refs_by_desc树和refs_by_node树的每个binder_ref节点则和上层的一个BpBinder对应,而且更重要

的是,它必须具有和“目标binder实体的binder_node”进行关联的信息。binder_ref的定义如下:

 
  1. struct binder_ref

  2. {

  3. int debug_id;

  4. struct rb_node rb_node_desc;

  5. struct rb_node rb_node_node;

  6. struct hlist_node node_entry;

  7. struct binder_proc *proc;

  8. struct binder_node *node; // 注意这个node域

  9. uint32_t desc;

  10. int strong;

  11. int weak;

  12. struct binder_ref_death *death;

  13. };

请注意那个node域,它负责和binder_node关联。另外,binder_ref中有两个类型为rb_node的域:rb_node_desc

域和rb_node_node域,它们分别用于连接refs_by_desc树和refs_by_node。也就是说虽然binder_proc中有两棵

引用树,但这两棵树用到的具体binder_ref节点其实是复用的。

上图只表示了从进程1向进程2发起跨进程传输的意思,其实反过来也是可以的,即进程2也可以通过自己的“引用

树”节点找到进程1的“实体树”节点,并进行跨进程传输。大家可以自己补充上图。

OK,现在我们可以更深入地说明binder句柄的作用了,比如进程1的BpBinder在发起跨进程调用时,向binder驱动

传入了自己记录的句柄值,binder驱动就会在“进程1对应的binder_proc结构”的引用树中查找和句柄值相符的

binder_ref节点,一旦找到binder_ref节点,就可以通过该节点的node域找到对应的binder_node节点,这个目标

binder_node当然是从属于进程2的binder_proc啦,不过不要紧,因为binder_ref和binder_node都处于binder驱

动的地址空间中,所以是可以用指针直接指向的。目标binder_node节点的cookie域,记录的其实是进程2中BBinder

的地址,binder驱动只需把这个值反映给应用层,应用层就可以直接拿到BBinder了。这就是Binder完成精确打击的

大体过程。

5,小结

1,Java层的系统服务所在进程和native的系统服务所在进程都会在进程启动时打开binder驱动。

2,一个进程中仅有一个ProcessState对象,相当于全局变量,但是有多个IPCThreadState对象。

3,打开binder驱动之后,每个进程都会将进程信息写入binder_proc结构中。

4, servicemanager进程首先通知Binder驱动程序它是守护进程,然后进入循环等待请求的到来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值