binder数据结构分析

1 binder进程的表述

1.1 ProcessState

binder进程在C++层表述为ProcessState类


ProcessState类构造函数是私有成员,binder进程只能通过静态成员函数sp<processstate>    self()获取ProcessState类。


典型的单例设计模式,一个进程只会创建一个ProcessState对象。很容易理解吧,应用程序对应唯一的进程对象,下次再调用静态成员函数sp<processstate>    self()就直接返回ProcessState对象了。

再来看看ProcessState构造函数


open_driver()打开binder驱动把句柄保存到成员mDriverFD中,mmap映射内核空间地址并把地址保存到成员mVMStart 。

1.2 binder_proc

binder进程在binder驱动中表述为binder_proc结构体,用户空间进程调用open("/dev/binder", O_RDWR)打开驱动的时候,驱动会为该进程在内核空间创建一个binder_proc结构体,并把该结构体链入全局hlist表binder_procs。


1.2.1 open_driver()

open("/dev/binder", O_RDWR)然后调用到binder驱动的binder_open函数


每当应用层实例化processstate对象的时候binder驱动都会为构建一个binder_proc 结构体,并把binder_proc 结构体添加到binder驱动全局hlist表中binder_procs


2 binder线程的表述

2.1 IPCThreadState

binder线程在C++层表述为IPCThreadState类


像ProcessState类一样。IPCThreadState类构造函数是私有成员,binder线程只能通过静态成员函数static  IPCThreadState*     self();获取其IPCThreadState类。


再来看看IPCThreadState构造函数



2.2 binder_thread

binder线程在binder驱动表述为binder_thread


2.3 IPCThreadState与binder_thread联系

当进程在用户空间调用ioctl进入binder驱动的时候,都会经过thread = binder_get_thread(proc); 


binder_get_thread会根据线程id判断是否已经为用户空间调用ioctl的线程在内核空间创建binder_thread结构体,有则直接返回,没有则创建并插入红黑树中。


3 binder实体、binder引用的表述

在binder初始化篇已经介绍了binder实体在引用层表述为BBinder,而binder引用表述为BpBinder。

3.1 binder_node

binder实体在binder驱动表述为binder_node


在server进程注册了多少个服务,就会在用户空间中实例化多少个BBinder对象,内核空间以BBinder对象在用户空间的地址创建binder_node,并以地址为index链入binder_proc的nodes。


3.2 binder_ref

binder引用在binder驱动表述为binder_ref


client获取服务,实质先在binder驱动根据binder_node信息创建一个binder_ref,然后返回handle值给应用层再创建BpBinder类。


binder_proc中的refs_by_node和refs_by_desc红黑树作用是一样的,binder_ref都会链入两个红黑树,只是index不一样。

这样binder实体和binder引用就关联上了。

3.3 flat_binder_object

binder实体和引用在各进程间传输,都被封装成flat_binder_object结构体


用union表示要么传输的是一个binder实体,要么就是binder引用,能通过type判断出来,若传输的是实体,*binder就是该进程用户空间BBinder的地址,若传输的是引用,handle就是该进程对实体引用的编号。


4 binder内存管理

4.1 映射内存

ProcessState构造函数在内核空间映射了一段内存

mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

然后会调用binder驱动中的binder_mmap函数。


再来看看binder_update_page_range函数


binder内存管理把用户空间内存地址和内核空间内存地址映射到同一个物理地址,并且只映射一页,后续空间不够才会继续映射其它页。这样分配的用户空间和内核空间地址就能共享同一段物理地址,内核空间传递特定数据给用户空间的时候不需要对这段数据copy_to_user,只要把数据复制到这段内存,并把该段数据在内核空间内存中的地址传递给用户空间,在用户空间访问传递的地址加上proc->user_buffer_offset的值就能访问到这些数据。

4.2 binder_buffer 

驱动为目标进程分配映射的内存都会用binder_buffer结构体来描述这段内存


4.3 分配内存


为目标进程分配一段内存,并返回对该段内存描述结构体binder_buffer 。

4.4 释放内存


目标进程处理完这些数据后,会及时发BC_FREE_BUFFER命令给驱动释放刚才分配的内存。


5 其它重要结构体

5.1 binder_write_read


binder用户空间与内核空间交互是用到ioctl(fd, cmd, arg),其中cmd=BINDER_WRITE_READ命令最为重要,参数是固定的binder_write_read 结构体。数据分为写部分和读部分,如果write_size不等于0就把数据写入binder驱动,并将会调用驱动中的binder_thread_write函数。如果read_size等于0驱动执行完binder_thread_write函数就会返回的应用层,如果read_size不等于0就会阻塞在驱动中的binder_thread_read函数,直到有消息处理才会唤醒,并把读到的数据拷贝到read_buffer的地址中,read_consumed为读到的长度。

5.2 binder_transaction_data


binder_write_read.write_buffer和binder_write_read.read_buffer也是采用cmd+arg模式。当涉及到两个进程通信,就需要用到binder_transaction_data 结构体,这时候写进程的binder_write_read.write_buffer地址内容就是(cmd = BC_TRANSACTION) + (arg = binder_transaction_data 结构体),binder_transaction_data 其实只是传输数据的消息头,数据有有效负荷还是在binder_transaction_data.data.ptr.buffer地址中,所以内核空间和用户空间中只传递消息头。binder_transaction_data .targe域非常重要,该成员指明发送目的进程消息发送方是client,目的进程是server,所以binder_transaction_data .targe.handle要填上binder实体的引用号(handle)。当数据到达server进程,仍然是用这个消息头描述接收的数据,server进程在binder_write_read.read_buffer取出消息头驱动已经把binder_transaction_data .targe.ptr改为binder实体的地址,同时也把cmd修改为BR_TRANSACTION 。server就能通过ptr的值来调用不同的服务。

5.3 binder_transaction


binder_transaction结构体只存在于binder驱动中,发送方在内核空间通过copy_from_user收到用户空间要传递的消息头 binder_transaction_data, 并整理成一个事务binder_transaction,然后通过binder_transaction.work域添加到目标进程或者线程的todo链表,这样目标进程内核空间就会收到这个事务,最终把事务再组织成消息头通过copy_to_user发到用户空间。binder的内存映射目的为了让消息头有效负载的数据不用再次copy_to_user一次,所以发送方内核空间会为目标进程分配一段映射过的内存并记录到这个事务中。何时才会完成这个事务呢?这个事务是记录了收发双方的线程进程相关信息,和内存的分配信息。当然是接收方处理完信息头的有效负载就会发送命令到驱动释放内存,这个事务如果需要回复,就会通过事务记录的信息去回复发送进程,最终在todo链表把这个事务删掉。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值