`

Android Binder设计(二)

 
阅读更多
这其中最常用的命令是BINDER_WRITE_READ。该命令的参数包括两部分数据:一部分是向Binder写入的数据,一部分是要从 Binder读出的数据,驱动程序先处理写部分再处理读部分。这样安排的好处是应用程序可以很灵活地处理命令的同步或异步。例如若要发送异步命令可以只填 入写部分而将read_size置成0;若要只从Binder获得数据可以将写部分置空即write_size置成0;若要发送请求并同步等待返回数据可 以将两部分都置上。

4.1 BINDER_WRITE_READ 之写操作
Binder写操作的数据时格式同样也是(命令+数据)。这时候命令和数据都存放在binder_write_read 结构write_buffer域指向的内存空间里,多条命令可以连续存放。数据紧接着存放在命令后面,格式根据命令不同而不同。下表列举了Binder写 操作支持的命令:

Binder写操作命令字

cmd 含义 arg
BC_TRANSACTION
BC_REPLY
BC_TRANSACTION用于写入请求数据;BC_REPLY用于写入回复数据。其后面紧接着一个 binder_transaction_data结构体表明要写入的数据。 struct binder_transaction_data
BC_ACQUIRE_RESULT
BC_ATTEMPT_ACQUIRE
暂未实现
BC_FREE_BUFFER 释放一块映射的内存。Binder接收方通过mmap()映射一块较大的内存空间,Binder驱动基于这片内存采用最佳匹配算法实现接收数据缓存 的动态分配和释放,满足并发请求对接收缓存区的需求。应用程序处理完这片数据后必须尽快使用该命令释放缓存区,否则会因为缓存区耗尽而无法接收新数据。 指向需要释放的缓存区的指针;该指针位于收到的Binder数据包中
BC_INCREFS
BC_ACQUIRE
BC_RELEASE
BC_DECREFS
这组命令增加或减少Binder的引用计数,用以实现强指针或弱指针的功能。 32位Binder引用号
BC_INCREFS_DONE
BC_ACQUIRE_DONE
第一次增加Binder实体引用计数时,驱动向Binder实体所在的进程发送BR_INCREFS, BR_ACQUIRE消息;Binder实体所在的进程处理完毕回馈BC_INCREFS_DONE,BC_ACQUIRE_DONE void *ptr:Binder实体在用户空间中的指针 void *cookie:与该实体相关的附加数据
BC_REGISTER_LOOPER
BC_ENTER_LOOPER
BC_EXIT_LOOPER
这组命令同BINDER_SET_MAX_THREADS一道实现Binder驱动对接收方线程池管理。BC_REGISTER_LOOPER通知 驱动线程池中一个线程已经创建了;BC_ENTER_LOOPER通知驱动该线程已经进入主循环,可以接收数据;BC_EXIT_LOOPER通知驱动该 线程退出主循环,不再接收数据。
BC_REQUEST_DEATH_NOTIFICATION 获得Binder引用的进程通过该命令要求驱动在Binder实体销毁得到通知。虽说强指针可以确保只要有引用就不会销毁实体,但这毕竟是个跨进程 的引用,谁也无法保证实体由于所在的Server关闭Binder驱动或异常退出而消失,引用者能做的是要求Server在此刻给出通知。 uint32 *ptr; 需要得到死亡通知的Binder引用 void **cookie: 与死亡通知相关的信息,驱动会在发出死亡通知时返回给发出请求的进程。
BC_DEAD_BINDER_DONE 收到实体死亡通知书的进程在删除引用后用本命令告知驱动。 void **cookie


在这些命令中,最常用的是BC_TRANSACTION/BC_REPLY命令对,Binder数据通过这对命令发送给接收方。这对命令所承载的数 据包由结构体struct binder_transaction_data定义。Binder交互有同步和异步之分,利用binder_transaction_data中 flag域区分。如果flag域的TF_ONE_WAY位为1则为异步交互,即Client端发送完请求交互即结束, Server端不再返回BC_REPLY数据包;否则Server会返回BC_REPLY数据包,Client端必须等待接收完该数据包方才完成一次交 互。

4.2 BINDER_WRITE_READ :从Binder读出数据
从Binder里读出的数据格式和向Binder中写入的数据格式一样,采用(消息ID+数据)形式,并且多条消息可以连续存放。下表列举了从 Binder读出的命令字及其相应的参数:

Binder读操作消息ID

消息 含义 参数
BR_ERROR 发生内部错误(如内存分配失败)
BR_OK
BR_NOOP
操作完成
BR_SPAWN_LOOPER 该消息用于接收方线程池管理。当驱动发现接收方所有线程都处于忙碌状态且线程池里的线程总数没有超过BINDER_SET_MAX_THREADS 设置的最大线程数时,向接收方发送该命令要求创建更多线程以备接收数据。
BR_TRANSACTION
BR_REPLY
这两条消息分别对应发送方的BC_TRANSACTION和BC_REPLY,表示当前接收的数据是请求或是回复。 binder_transaction_data
BR_ACQUIRE_RESULT
BR_ATTEMPT_ACQUIRE
BR_FINISHED
尚未实现
BR_DEAD_REPLY 交互过程中如果发现对方进程或线程已经死亡则返回该消息
BR_TRANSACTION_COMPLETE 发送方通过BC_TRANSACTION或BC_REPLY发送完一个数据包后,都能收到该消息做为成功发送的反馈。这和BR_REPLY不一样, 是驱动告知发送方已经发送成功,而不是接收方返回请求数据。所以不管同步还是异步交互接收方都能获得本消息。
BR_INCREFS
BR_ACQUIRE
BR_RELEASE
BR_DECREFS
这一组消息用于管理强/弱指针的引用计数。只有提供Binder实体的进程才能收到这组消息。 void *ptr:Binder实体在用户空间中的指针 void *cookie:与该实体相关的附加数据
BR_DEAD_BINDER
BR_CLEAR_DEATH_NOTIFICATION_DONE
向获得Binder引用的进程发送Binder实体死亡通知书;收到死亡通知书的进程接下来会返回BC_DEAD_BINDER_DONE做确认。 void **cookie:在使用BC_REQUEST_DEATH_NOTIFICATION注册死亡通知时的附加参数。
BR_FAILED_REPLY 如果发送非法引用号则返回该消息


和写数据一样,其中最重要的消息是BR_TRANSACTION 或BR_REPLY,表明收到了一个格式为binder_transaction_data的请求数据包(BR_TRANSACTION)或返回数据包 (BR_REPLY)。

4.3 struct binder_transaction_data :收发数据包结构
该结构是Binder接收/发送数据包的标准格式,每个成员定义如下:
Binder收发数据包结构:binder_transaction_data

成员 含义
union { size_t handle;void *ptr;} target; 对于发送数据包的一方,该成员指明发送目的地。由于目的是在远端,所以这里填入的是对Binder实体的引用,存放在target.handle 中。如前述,Binder的引用在代码中也叫句柄(handle)。 当数据包到达接收方时,驱动已将该成员修改成Binder实体,即指向Binder对象内存的指针,使用target.ptr来获得。该指针是接收 方在将Binder实体传输给其它进程时提交给驱动的,驱动程序能够自动将发送方填入的引用转换成接收方Binder对象的指针,故接收方可以直接将其当 做对象指针来使用(通常是将其reinterpret_cast成相应类)。
void *cookie; 发送方忽略该成员;接收方收到数据包时,该成员存放的是创建Binder实体时由该接收方自定义的任意数值,做为与Binder指针相关的额外信息 存放在驱动中。驱动基本上不关心该成员。
unsigned int code; 该成员存放收发双方约定的命令码,驱动完全不关心该成员的内容。通常是Server端定义的公共接口函数的编号。
unsigned int flags; 与交互相关的标志位,其中最重要的是TF_ONE_WAY位。如果该位置上表明这次交互是异步的,接收方不会返回任何数据。驱动利用该位来决定是否 构建与返回有关的数据结构。另外一位TF_ACCEPT_FDS是出于安全考虑,如果发起请求的一方不希望在收到的回复中接收文件形式的Binder可以 将该位置上。因为收到一个文件形式的Binder会自动为接收方打开一个文件,使用该位可以防止打开文件过多。
pid_t sender_pid; uid_t sender_euid; 该成员存放发送方的进程ID和用户ID,由驱动负责填入,接收方可以读取该成员获知发送方的身份。
size_t data_size; 该成员表示data.buffer指向的缓冲区存放的数据长度。发送数据时由发送方填入,表示即将发送的数据长度;在接收方用来告知接收到数据的长 度。
size_t offsets_size; 驱动一般情况下不关心data.buffer里存放什么数据,但如果有Binder在其中传输则需要将其相对data.buffer的偏移位置指出 来让驱动知道。有可能存在多个Binder同时在数据中传递,所以须用数组表示所有偏移位置。本成员表示该数组的大小。
union { struct {const void *buffer;const void *offsets;} ptr;uint8_t buf[8];} data; data.bufer存放要发送或接收到的数据;data.offsets指向Binder偏移位置数组,该数组可以位于data.buffer 中,也可以在另外的内存空间中,并无限制。buf[8]是为了无论保证32位还是64位平台,成员data的大小都是8个字节。


这里有必要再强调一下offsets_size和data.offsets两个成员,这是Binder通信有别于其它IPC的地方。如前 述,Binder采用面向对象的设计思想,一个Binder实体可以发送给其它进程从而建立许多跨进程的引用;另外这些引用也可以在进程之间传递,就象 java里将一个引用赋给另一个引用一样。为Binder在不同进程中建立引用必须有驱动的参与,由驱动在内核创建并注册相关的数据结构后接收方才能使用 该引用。而且这些引用可以是强类型,需要驱动为其维护引用计数。然而这些跨进程传递的Binder混杂在引用程序发送的数据包里,数据格式完全由用户定 义,如果不把它们一一标记出来告知驱动,驱动将无法从数据中将它们提取出来。于是就使用数组data.offsets存放用户数据中每个Binder相对 data.buffer的偏移量,用offsets_size表示这个数组的大小。驱动在发送数据包时会根据data.offsets和 offset_size将散落于data.buffer中的Binder找出来并一一为它们创建相关的数据结构。在数据包中传输的Binder是类型为 struct flat_binder_object的结构体。

对于接收方来说,该结构只相当于一个定长的消息头,真正的用户数据存放在data.buffer所指向的缓存区中。如果发送方在数据中内嵌了一个或 多个Binder,接收到的数据包中同样会用data.offsets和offset_size指出每个Binder的位置和总个数。不过通常接收方可以 忽略这些信息,因为接收方是知道数据格式的,参考双方约定的格式定义就能知道这些Binder在什么位置。

分享到:
评论

相关推荐

    Android Binder设计与实现——设计篇

    罗升阳在介绍和学习Binder的Blog中推荐:《Android Binder设计与实现》一文,详细地介绍了内核空间的Binder驱动程序的数据结构和设计原理

    Android Binder设计与实现

    详细分析了android binder的设计与实现。

    Android_Binder设计与实现_-_设计篇

    Android_Binder设计与实现_-_设计篇

    Android Binder设计与实现.docx

    Android Binder设计与实现.docxAndroid Binder设计与实现.docxAndroid Binder设计与实现.docxAndroid Binder设计与实现.docxAndroid Binder设计与实现.docxAndroid Binder设计与实现.docxAndroid Binder设计与实现....

    Android Binder设计之道.pptx

    Android Binder设计之道.pptx

    AndroidBinder设计与实现-设计篇

    Binder是Android系统进程间通信(IPC)方式之一。Linux已经拥有管道,systemVIPC,socket等IPC手段,却还要倚赖Binder来实现进程间通信,说明Binder具有无可比拟的优势。深入了解Binder并将之与传统IPC做对比有助于...

    android中binder设计与实现

    android中binder设计与实现 与深入浅出结合,非常好的诠释了android 中的binder机制的实现,各有所长,希望对您有帮助 个人也是网络上找的

    Android Binder 实现原理

    很详细讲解了Binder实现原理,细节,设计思想

    Binder设计与实现

    Binder是Android系统进程间通信(IPC)方式之一。Linux已经拥有管道,system V IPC,socket等IPC手段,却还要倚赖Binder来实现进程间通信,说明Binder具有无可比拟的优势。深入了解Binder并将之与传统 IPC做对比有助...

    Android Binder通信案例

    AIDL实现IPC,手写Binder实现IPC,Binder连接池的设计

    Android10.0 Binder通信原理(九)-AIDL Binder示例

    摘要:本节主要来讲解Android10.0 Binder中如何使用AIDL 阅读本文大约需要花费20分钟。 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢! [Android取经之路] 的...

    Android Binder

    本文将对Binder的设计细节做一个全面的阐述,首先通过介绍Binder通信 模型和 Binder通信协议了解Binder的设计需求;然后分别阐述Binder在系统不同部分的表述方式和起的作用;最后还 会解释Binder在数据接收端的设计...

    Android代码-Android

    对于Binder机制的介绍可以看universus写的《Android Binder设计与实现》。另外还两个老外介绍Binder的PPT也不错。 Android Binder设计与实现 - 设计篇 inter-process method invocation in Android (相对入门一点...

    android native层 binder通信机制演示源码

    该压缩包的内容主要是基于android系统演示native层进行binder通信的源码,里面分为bp和bn直接如何设计,可以给那些需要再native层进行binder通信的开发提供一个参考

    Android的设计与实现(卷1)

    android的设计与实现:卷i》是android应用开发工程师和android系统工程师进阶修炼的必读之作。它由资深android内核专家亲自执笔,从源代码角度,系统、深入、透彻剖析android系统框架层(framework)的设计思想和...

    基于Android的家庭理财系统的设计与实现.rar(毕业论文设计+程序源码) android studio导入可直接打开

    2.4.4 Binder 机制 15 2.5本章小结 16 第3章 需求分析与数据库设计 16 3.1需求分析 16 3.1.1功能性需求分析 16 3.12非功能性需求分析 17 3.2系统数据库设计 17 3.2.1数据库概念结构设计 17 3.2.2数据库逻辑结构设计 ...

    Android进程间通信Binder扩展模型的设计与实现.pdf

    Android进程间通信Binder扩展模型的设计与实现.pdf

    Android Binder入门学习笔记

    理解Binder能帮助我们更好的理解Android的系统设计,比如说四大组件,AMS,WMS等系统服务的底层通信机制就都是基于Binder机制的。当然了,Binder机制的底层驱动实现很复杂,本文的目的只是为了理清Binder的使用和在...

Global site tag (gtag.js) - Google Analytics