学习binder机制的简要笔记

来源:互联网 发布:中专升大专网络教育 编辑:程序博客网 时间:2024/06/16 10:56
如标题所言,只是做为学习后的思想总结,仅标识出个人关注的要点。

一、关注的函数
wake_up_interruptible               proc/thread(9)
wake_up_interruptible_all           proc(1)

wait_event_interruptible            thread(1)
wait_event_interruptible_exclusive  proc(1)

binder_update_page_range
binder_mmap(1)
binder_alloc_buf(1)
binder_free_buf(1) --- binder_delete_free_buffer(1)

二、关注的知识点
接收方用户空间内存只读,驱动按最佳匹配算法分配内存,大小1MB减8KB字节。初始映射4KB的物理内存页
binder_proc::buffer: 内核虚拟地址首地址,大小为128KB或1MB减8KB字节,实际使用时将拆分成多个buffer内存块并映射物理地址
binder_proc::buffers: list_head表的头,按地址连续性将buffer内存块链接到一起
binder_proc::free_buffers: rbtree,空闲的buffer内存块,可能已映射,可能未映射
binder_proc::allocated_buffers: rbtree,分配的buffer内存块,已映射
binder_proc::pages: 存储物理页表对应page结构的地址的指针数组,数组结点数为虚拟地址buffer完全映射时对应的页表数,即(vma_end-vma_start)/PAGE_SIZE
binder_proc::buffer_size: buffer内存块总大小,即vma_end-vma_start

mmap分配的内存除了映射进了接收方进程里,还映射进了内核空间。所以驱动调用copy_from_user将数据从发送方用户空间拷贝进内核空间也相当于拷贝进了接收方的用户空间

进程有一个全局数据接收队列(todo),线程有私有数据接收队列(todo)。Client发给Server的请求数据包都提交到Server进程的全局todo队列,同步请求的返回数据包都发送到发起请求的线程的私有todo队列中。需要结合等待队列头(wait)通过调度完成这些工作

线程优先级调整,nice;线程池(数量有限,应用动态调整,驱动跟踪)结合等待队列处理并发请求;pid是代表线程,tgid是代表线程组(可以理解为进程)

事务binder_transaction携带的数据是由binder_buffer存储的,binder_buffer从binder_proc::buffers分配内存,并做为list_head表entry的结点串联到一起,内存块的地址也是首尾相连,虚拟地址连续的,系统对binder内存的管理,也就是对binder_buffer结构体的管理和操作。binder_buffer::data记录内存开始地址,binder_buffer::data_size存放此次事务对应的数据大小,binder_buffer::offsets_size表示数据中包含的binder对象的数目。

binder_update_page_range为进程的内核空间和进程的用户空间针对同一块物理内存建立映射。当映射的物理内存不够用时,由binder_alloc_buf动态的建立需要的的物理内存的映射。binder_free_buf完成内存的释放工作。事务binder_transaction需要使用到内存则会调用binder_alloc_buf从目标进程内存空间分配。

线程池在用户空间创建和销毁,在内核空间管理和控制。服务所在进程启动时会创建两个线程,一个是主线程,一个是binder线程。前者数量固定为一,后者可调整。

关于IPCThreadState成员mPendingStrongDerefs的作用是用于处理已经死亡的BBinder对象(应该是使用了clear接口产生)。

Binder通信中的两端,看类名可以看出其角色定义大概。如果是BpXXX则是客户端,如果是BnXXX则是服务端,这里的客户端和服务端是针对谁主动发起调用来看的,这也是为什么官方的说法中Bp是指“Binder proxy”、Bn是指“Binder native”,而没有提及客户/服务端的原因。对于正向调用和反向通知,客户端和服务端的定义是有反转的,即:只要是调用了抽象接口的实例BpXXX则认为此时是做为客户端,调用BnXXX则认为是做为服务端,要实现全双工则通信两端其实是分别有一组BpXXX和BnXXX的,这样才能达到正向调用和反向通知的目的。对于有些简单的用法,如果不需要反向通知,就只需要在通信两端分别实现一组中的BpXXX或BnXXX。

以Camera子系统为例,以计算机网络模型类比,Camera和CameraService非抽象接口类就是通信两端的终端和服务器角色;ICamera和ICameraClient抽象接口类是通信两端的通信接口(例如socket),由于需要双向通信,ICamera完成正向调用,ICameraClient完成反向通知,它们在通信两端的实例化可以认为是通信接口的初始化。

在Binder机制中有一个很重要的术语,就是命名和匿名Binder对象。在Camera子系统中,命名的Binder对象是ICameraService("media.camera"),Proxy端需要通过名称来和它通信,在和它通信过程中让它创建匿名的Binder对象ICamera并返回,同时也将自己的匿名Binder对象ICameraClient传递给它。完成这个工作后Service就空闲并等待下一次连接,之后的工作就是由两个匿名Binder对象完成双向通信了。当然,对于单向通信,最简单的做法就是让Proxy和Service端承担通信平台和通信接口的工作,这样的话事务都是在Service中实现,通信也都是在命名Binder对象中完成。这种情况有点类似在线游戏,登录服务器和游戏服务器是分开架设还是合二为一。

进程间的边界是通过驱动和抽象接口分隔的,这也是面向接口编程原则的具体体现。因为binder机制是通过驱动传递数据和找到对应类实例的接口的,抽象接口实际上是做为key值记录的,这样在跨进程过程中才能根据key对应到实例并调用。如:
进程BpXXX:object1(addr1)=>interface1
驱动:     interface1=>interface2
进程BnXXX: interface2=>object2(addr2)

BpXXX将object1转换为interface1并传递到驱动;驱动根据interface1找到interface2,并通知BnXXX;BnXXX根据interface2转换为object2,并进行接口调用。如果BpXXX和BnXXX在一个进程,那addr1和addr2在同一地址空间,BpXXX和BnXXX就直接互访了。

关于BpXXX和BnXXX分别对应的实例化对象,仅有一个是在一端显式实例化,并传递相关的cookie到另一端隐式实例化的,具体的实现细节不再涉及。

三、相关引用
=====必看=====

Android Bander设计与实现 - 设计篇
http://blog.csdn.net/universus/article/details/6211589

binder驱动-------之数据结构篇1
http://blog.csdn.net/xiaojsj111/article/details/27361651

Kernel 及 binder mmap实现
http://blog.csdn.net/myarrow/article/details/7207628

Binder通信过程中的用户空间线程池的管理
http://blog.csdn.net/fuyajun01/article/details/27710535

android的binder驱动1
http://blog.chinaunix.net/uid-25830576-id-322261.html

Android Binder设计与实现 - 实现篇(1)
http://www.cnblogs.com/albert1017/p/3849585.html

=====选看=====

红茶一杯话Binder
http://my.oschina.net/youranhongcha/blog/152233

Android Binder机制(超级详尽)
http://blog.csdn.net/coding_glacier/article/details/7520199

Android Binder分析一:ServiceMananger的启动
http://blog.csdn.net/lilian0118/article/details/23747107

Binder机制1---Binder原理介绍
http://blog.csdn.net/bathinbreeze/article/details/8989105

Android的IPC机制Binder的各个部分
http://daimajishu.iteye.com/blog/1080773/




0 0
原创粉丝点击