Android Binder驱动中的基础数据结构整理

来源:互联网 发布:mac的word文档 编辑:程序博客网 时间:2024/05/21 18:33

                  最近突然看到一个博客,是讲Binder原理的,以前看深入理解Android I的时候看过,那时候就看不懂。感觉这个还有点意思,就看了好几天,发现越看越不懂,然后看老罗的博客,发现也不是太懂,现在想根据书上的东西好好梳理下Binder。

感觉里面应该重点掌握的应是bind_node是注册的服务在内核中的代表,bind_ref是客户端连接在驱动的代表。bind_buffer内核缓冲区,通过mmap之后可以在用户空间操作,然后在内核也可以访问,bind_proc是进程的代表,客户端和服务端都有,对上面的进行管理,未完,待续,等看完了艺术探索过来更新。

handle, RPC代码和RPC数据保存在binder_transaction_data的结构体中,属于RPC范畴.

binder_write_read 等于binder_transaction_data(用户空间数据)加上binder协议,是IPC数据范畴.

binder_write_read中的write_size是发送ipc数据时使用,read_size是接收数据时使用.

flat_binder_object在内核中传输的时候,会判断type的类型,来判断是否创建binder节点(服务注册的时候存在)

进程间通信根据Client和Server的状态设置该值  

struct binder_work {//用户查找binder_transaction结构体struct list_head entry;   //enum {BINDER_WORK_TRANSACTION = 1,  //获取ipc数据BINDER_WORK_TRANSACTION_COMPLETE,BINDER_WORK_NODE,BINDER_WORK_DEAD_BINDER,      //Binder驱动检测到Service组件死亡时,找到Binder实体对象中的refs,找到引用它的client进程和Client进程主动注册死亡通知发现Service组件已死亡两种情况                BINDER_WORK_DEAD_BINDER_AND_CLEAR, //Client进程注销死亡通知时,相应的Service组件已死亡,binder驱动找到之前注册的binder_ref_death结构体,并修改它workBINDER_WORK_CLEAR_DEATH_NOTIFICATION,  //Client进程注销一个死亡通知,相应的Service组件没有死亡,Binder驱动程序会找到之前注册的,一个binder_ref_death结构体,并且将它的work修改为此, 然后将该结构体封装成一个工作项添加到Client进程的todo队列中                   } type; //工作项的类型};

binder实体对象   Service中的Binder在内核中的代表

struct binder_node {int debug_id;struct binder_work work;//引用计数发生变化时 BINDER_WORK_NODE,并且将它添加到响应进程的todo队列中union {struct rb_node rb_node;struct hlist_node dead_node;};struct binder_proc *proc;       //指向service进程struct hlist_head refs; //所有的Client的binder引用binder_ref->nodeint internal_strong_refs;int local_weak_refs;int local_strong_refs;void __user *ptr;  //指向Service组件内部的一个引用计数  weakref_impl 弱引用计数void __user *cookie;              //指向Service组件的地址unsigned has_strong_ref:1;        //请求Service组件时 1  结束 0unsigned pending_strong_ref:1;    // 请求的时候为1,service增加后为0unsigned has_weak_ref:1;          //请求Service组件时 1  结束 0unsigned pending_weak_ref:1;unsigned has_async_transaction:1;  //每一个事务都关联一个binder实体对象unsigned accept_fds:1; //是否接收含有文件描述符的进程间通信数据   防止源进程在目标进程中打开unsigned min_priority:8;           //线程优先级 struct list_head async_todo;       //异步事务队列};
Service组件,在驱动中的binder_node,binder_ref都维护引用计数

描述Client组件的死亡通知在驱动中的代表,

struct binder_ref_death {struct binder_work work;   //见第一个数据结构void __user *cookie;  //保存Client负责接收死亡通知对象的地址};

Binder驱动程序决定向客户端进程发送一个Service组件死亡通知时。会将binder_ref_death结构体封装成一个工作项。加到Client进程的todo队列中 ,Client进程在处理这个工作项,会通过binder_ref_death结构体成员变量的work来区是哪一种情况,见第一个结构体中的枚举值

描述一个Binder引用对象   Client进程中的Binder引用在驱动中的代表

struct binder_ref {/* Lookups needed: *//*   node + proc => ref (transaction) *//*   desc + proc => ref (transaction, inc/dec ref) *//*   node => refs + procs (proc exit) */int debug_id;struct rb_node rb_node_desc;      //保存进程内部所有的句柄值struct rb_node rb_node_node;struct hlist_node node_entry;  //hash列表中的节点 对应与binder_node->refsstruct binder_proc *proc;     //Binder引用对象的宿主进程struct binder_node *node;   //Binder引用对象所引用的Binder实体对象uint32_t desc;              //在Client进程的用户空间,Binder引用对象是使用一个句柄值来描述的,BInder驱动程序就可以通过该句柄值找到对于的,Binder引用对象即是binder_ref              int strong; int weak;struct binder_ref_death *death;  //Client进程注册的死亡通知保存的地方};

进程对应内核缓冲区  缓冲区中的事务会随着请求发送变化

struct binder_buffer {struct list_head entry; /* free and allocated entries by addesss */   //内核缓冲区列表的一个节点struct rb_node rb_node; /* free entry by size or allocated entry *//* by address */   //free 为1 表示为空闲内核缓冲区中的一个节点unsigned free:1;      //1表示内核缓冲区是空闲的  不会分配物理页面的unsigned allow_user_free:1;//Service组件处理完后发现为1,Service组件请求Binder驱动释放该内核缓冲区        unsigned async_transaction:1;   //为1表示异步事务unsigned debug_id:29;struct binder_transaction *transaction;  //每一个事务都关联一个目标Binder实体对象struct binder_node *target_node;         //目标的binder节点size_t data_size;     //数据缓冲区的大小size_t offsets_size; //偏移数组  记录了每一个Binder对象再数据缓冲区中的位置uint8_t data[0];    //指向大小可变的数据缓冲区,用来保存通信数据的  可保存普通数据和Binder对象   Binder驱动程序只关心Binder对象};

进程调用open /dev/binder的时候创建 将它保存在全局的hash  进程在驱动中的代表

struct binder_proc {struct hlist_node proc_node;   //是hash列表中的节点        struct rb_root threads;       // 拥有binder_thread结构体的红黑树的根struct rb_root nodes;         //binder实体对象的红黑树的根  以ptr作为关键字struct rb_root refs_by_desc;struct rb_root refs_by_node;   //带有binder_ref 结构体红黑树的根,使用binder_node结构体区分binder_refint pid;                        //创建binder_proc结构体的进程的pidstruct vm_area_struct *vma; //内核缓冲区地址     用户空间地址  在应用程序内部使用 struct task_struct *tsk;    //任务控制块 进程相关struct files_struct *files;    //文件结构体数组struct hlist_node deferred_work_node;       //进程延迟执行的工作项int deferred_work;              //延迟工作项的具体内容void *buffer; //内核缓冲区的地址   内核空间地址   大块空间  划分为Binder_buffer小空间 接收ipc数据的结构体指针ptrdiff_t user_buffer_offset;  //内核缓冲区中 用户空间地址和内核空间地址的差值 接收的ipc数据的内核和用户的地址偏移量,将接收到的ipc数据传递到用户空间struct list_head buffers;    //指向指向该列表的头部  为接收ipc数据而分配的binder_buffer结构体列表struct rb_root free_buffers;    //已分配物理页面 接收ipc数据后,要释放的binder_buffer结构体列表   根据RPC数据的大小分配binder_buffer结构体的datastruct rb_root allocated_buffers;size_t free_async_space; //保存异步事务数据缓冲区的大小struct page **pages;   //对于的物理页面   数组中每个元素指向一个物理页面size_t buffer_size;    //mmap后内核缓冲区的大小  内核中开辟的buffer大小 uint32_t buffer_free;    //空闲内核缓冲区的大小struct list_head todo;   //把待处理请求封装成一个工作项,加如到待处理工作项队列 进程从待机状态唤醒后要做的事情  和binder_work联系一块wait_queue_head_t wait;       //空闲binder线程会睡眠在等待队列里面  让进程进入待机状态        struct binder_stats stats;    //统计进程数据的,进程见请求的次数struct list_head delivered_death;   //死亡通知封装成一个工作项保存在所描述的一个队列中,进程收到后会删除int max_threads;int requested_threads;  //驱动主动请求进程注册一个线程时加1,进程响应后减1int requested_threads_started;//驱动程序主动请求进程注册的数目,进程响应后加1int ready_threads;   //当前空闲的Binder线程数目long default_priority;    //宿主进程的优先级struct dentry *debugfs_entry;};
deferred_work的可能取值

enum binder_deferred_state {BINDER_DEFERRED_PUT_FILES    = 0x01,  //进程关闭文件描述符BINDER_DEFERRED_FLUSH        = 0x02,   //唤醒线程检查进程是否有新的工作项需要处理BINDER_DEFERRED_RELEASE      = 0x04,  //不再使用binder进程间通信机制,驱动释放它分配的资源,释放进程结构体,binder实体对象};
binder驱动会为内核缓冲区分配文件描述符,进程可以通过文件描述符把内核缓冲区映射到自己的地址空间

binder线程池中的一个线程,线程注册到binder驱动时,驱动会创建该结构体

struct binder_thread {struct binder_proc *proc;  //指向宿主进程struct rb_node rb_node;   //一个节点int pid;    //线程IDint looper;    //状态struct binder_transaction *transaction_stack;   //一个事务交给一个线程处理时,事务封装成结构体 处理谁,谁放在最前端 查找另一端接收进程struct list_head todo;  //Client进程的请求uint32_t return_error; /* Write failed, return error code in read buf */  处理事务时出现的异常uint32_t return_error2; /* Write failed, return error code in read *//* buffer. Used when sending a reply to a dead process that *//* we are also waiting on */wait_queue_head_t wait;    //等待依赖的线程处理结束struct binder_stats stats;   //接收到进程间通信请求的次数};

线程的状态

enum {BINDER_LOOPER_STATE_REGISTERED  = 0x01,  //收到用户线程发送BC_register_looperBINDER_LOOPER_STATE_ENTERED     = 0x02,  //表明准备就绪BC_ENTER_looperBINDER_LOOPER_STATE_EXITED      = 0x04,BINDER_LOOPER_STATE_INVALID     = 0x08,BINDER_LOOPER_STATE_WAITING     = 0x10,   //binder线程处于空闲状态BINDER_LOOPER_STATE_NEED_RETURN = 0x20   //初始化状态};
线程是应用程序主动注册的,那么它通过BC_ENTER_looper来通知binder驱动

描述进程间通信过程

struct binder_transaction {int debug_id;struct binder_work work;   //binder驱动为目标线程创建一个事务后(由驱动负责)设置BINDER_WORK_TRANSACTION,并添加到目标线程的todo队列中struct binder_thread *from;   //发起事务的线程,成为源线程struct binder_transaction *from_parent;  //struct binder_proc *to_proc;    //负责处理该事务的进程struct binder_thread *to_thread;  //目标线程struct binder_transaction *to_parent;    //处理完本事务,然后返回父事务unsigned need_reply:1;  //为1 表示是同步事务/* unsigned is_dead:1; *//* not used at the moment */struct binder_buffer *buffer; //binder驱动程序为该事务分配的一块内存缓冲区unsigned intcode;unsigned intflags;longpriority;   //线程优先级longsaved_priority; //保存原来的线程优先级uid_tsender_euid;   //线程用户ID};
应用程序通过IO命令和驱动交互
#define BINDER_WRITE_READ   _IOWR('b', 1, struct binder_write_read)

进程间通信

struct binder_write_read {signed longwrite_size;/* bytes to write */ 缓冲区大小signed longwrite_consumed;/* bytes consumed by driver */ 驱动从缓冲区处理的字节unsigned longwrite_buffer;   //描述输入数据 从用户空间传输到binder驱动程序的数据 指向一个用户缓冲区地址signed long read_size;/* bytes to read */signed longread_consumed;/* bytes consumed by driver */unsigned longread_buffer; //指向一个用户空间缓冲区的地址};

全部是进程发送给binder驱动

enum BinderDriverCommandProtocol {       BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),       BC_REPLY = _IOW('c', 1, struct binder_transaction_data),       BC_FREE_BUFFER = _IOW('c', 3, int), //指向内核缓冲区       BC_INCREFS = _IOW('c', 4, int),  //binder引用对象的句柄值 弱引用       BC_ACQUIRE = _IOW('c', 5, int),   //增加 强引用计数       BC_RELEASE = _IOW('c', 6, int),       BC_DECREFS = _IOW('c', 7, int),   //弱引用       BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),       BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),        BC_REGISTER_LOOPER = _IO('c', 11),  //驱动请求进程注册线程到驱动       BC_ENTER_LOOPER = _IO('c', 12),    //线程主动注册       BC_EXIT_LOOPER = _IO('c', 13),   //线程要退出时       BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie), //注册       BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie), //清空        BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),  //指向一个死亡通知结构体binder_ref_death的地址          //Client用命令协议码通知binder驱动程序处理完Service组件的死亡通知了};
源进程使用命令协议代码BC_TRANSACTION请求binder驱动将通信数据传递到目标进程

目标进程处理完源进程的请求操作之后使用命令协议码BC_REPLY请求驱动将结果传递给源进程

返回协议代码

enum BinderDriverReturnProtocol {BR_ERROR = _IOR('r', 0, int), //驱动处理请求时出错     BR_OK = _IO('r', 1), //成功处理     BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), //通知Server进程来处理该进程间通信请求     BR_REPLY = _IOR('r', 3, struct binder_transaction_data),//server处理完请求之后,驱动以此协议返回Client进程        BR_DEAD_REPLY = _IO('r', 5),  //发现目标进程或线程已经死亡 驱动会返回这个协议代码        BR_TRANSACTION_COMPLETE = _IO('r', 6),//当binder驱动收到进程发来的BC_TRANSACTION或是BC_REPLY,驱动返回此码,告知进程已收到     BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),     BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),     BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),     BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),        BR_NOOP = _IO('r', 12), //通知应用进程执行了一个空操作        BR_SPAWN_LOOPER = _IO('r', 13),//发现进程没有足够的空闲Binder线程来处理进程间通信请求,通知该进程增加一个线程到Binder线程池中     BR_DEAD_BINDER = _IOR('r', 15, void *),//当驱动检测到Service组件死亡事件时,通知Client进程        BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),//binder驱动执行完注销后返回此码通知Client进程     BR_FAILED_REPLY = _IO('r', 17), // 处理进程发送的BC_TRANSACTION异常时,返回此码};


描述一个Binder实体对象或是引用

struct binder_ptr_cookie {void *ptr;  //Binder引用的句柄 或是void *cookie;//接收死亡通知对象的地址};
进程中线程的通信传输的数据   用户空间数据
struct binder_transaction_data {union {size_thandle;/* target descriptor of command transaction */ //引用对象的句柄值void*ptr;/* target descriptor of return transaction */  //指向Service组件内部弱引用计数的地址} target;void*cookie;/* target object cookie */  //目标Service组件的地址unsigned intcode;/* transaction command */ //双方约定好的通信代码/* General information about the transaction. */unsigned intflags;  //描述进程间通信行为的特征pid_tsender_pid;  //进程的piduid_tsender_euid;   //size_tdata_size;/* 通信数据的大小 */size_toffsets_size;/* 偏移数组的大小 */union {struct {/* transaction data */const void*buffer; //指向数据缓冲区,真正保存通信数据的 大小由data_size决定/* offsets from buffer to flat_binder_object structs */const void*offsets; //保存每一个binder对象的位置,分别指向偏平结构的首地址 } ptr;//数据量大的时候 uint8_tbuf[8]; //数据量小的时候 } data;   //数据缓冲区是 来传输数据};
上面的flags取值如下
enum transaction_flags {TF_ONE_WAY= 0x01,/* 1表示异步的进程间通信过程 */TF_ROOT_OBJECT= 0x04,/* contents are the component's root object */TF_STATUS_CODE= 0x08,/* 1表示data数据缓冲区的内容是一个4字节的状态码 */TF_ACCEPT_FDS= 0x10,/* 0表示源进程不允许结果护具中含有文件描述符 */};
数据缓冲区中每一个Binder对象都使用一个flat_binder_object来描述
struct flat_binder_object {/* 8 bytes for large_flat_header. */unsigned longtype;   //区分是Binder实体对象还是引用对象,亦或是文件描述符unsigned longflags;  //只有描述的是Binder实体,它才有意义/* 8 bytes of data. */union {void*binder;/* local Binder实体对象 指向一个内部弱引用对象的地址 */signed longhandle;/* remote Binder引用对象的句柄值 */};/* extra data associated with local object */void*cookie;  //指向该Service组件的地址};
扁平结构中的type的取值如下
#define B_PACK_CHARS(c1, c2, c3, c4) \((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))#define B_TYPE_LARGE 0x85enum {BINDER_TYPE_BINDER= B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),//强类型的Binder实体对象BINDER_TYPE_WEAK_BINDER= B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),//弱类型的实体对象BINDER_TYPE_HANDLE= B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),//描述的是强类型Binder引用对象BINDER_TYPE_WEAK_HANDLE= B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),//弱类型引用BINDER_TYPE_FD= B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),//};

0 0