android Binder设计与实现二
4 Binder 协议
Binder协议基本格式是(命令+数据),使用ioctl(fd, cmd, arg)函数实现交互。命令由参数cmd承载,数据由参数arg承载,随cmd不同而不同。下表列举了所有命令及其所对应的数据:
表 2 Binder通信命令字
命令 | 含义 | arg |
BINDER_WRITE_READ | 该命令向Binder写入或读取数据。参数分为两段:写部分和读部分。如果write_size不为0就先将write_buffer里的数据写入Binder;如果read_size不为0再从Binder中读取数据存入read_buffer中。write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读出的数据个数。 | struct binder_write_read { signed long write_size; signed long write_consumed; unsigned long write_buffer; signed long read_size; signed long read_consumed; unsigned long read_buffer; }; |
BINDER_SET_MAX_THREADS | 该命令告知Binder驱动接收方(通常是Server端)线程池中最大的线程数。由于Client是并发向Server端发送请求的,Server端必须开辟线程池为这些并发请求提供服务。告知驱动线程池的最大值是为了让驱动在线程达到该值时不要再命令接收端启动新的线程。 | int max_threads; |
BINDER_SET_CONTEXT_MGR | 将当前进程注册为SMgr。系统中同时只能存在一个SMgr。只要当前的SMgr没有调用close()关闭Binder驱动就不能有别的进程可以成为SMgr。 | — |
BINDER_THREAD_EXIT | 通知Binder驱动当前线程退出了。Binder会为所有参与Binder通信的线程(包括Server线程池中的线程和Client发出请求的线程)建立相应的数据结构。这些线程在退出时必须通知驱动释放相应的数据结构。 | — |
BINDER_VERSION | 获得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写 操作支持的命令:
表 3 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读出的命令字及其相应的参数:
表 4 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)。
摘自 LuoXianXiong,您的伙伴
补充:移动开发 , Android ,