Android Binder驱动中的基础数据结构整理
Posted 寄意兰州
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Binder驱动中的基础数据结构整理相关的知识,希望对你有一定的参考价值。
最近突然看到一个博客,是讲Binder原理的,以前看深入理解android I的时候看过,那时候就看不懂。感觉这个还有点意思,就看了好几天,发现越看越不懂,然后看老罗的博客,发现也不是太懂,现在想根据书上的东西好好梳理下Binder。
感觉里面应该重点掌握的应是bind_node是注册的服务在内核中的代表,bind_ref是客户端连接在驱动的代表。bind_buffer内核缓冲区,通过mmap之后可以在用户空间操作,然后在内核也可以访问,bind_proc是进程的代表,客户端和服务端都有,对上面的进行管理,未完,待续,等看完了艺术探索过来更新。
进程间通信根据Client和Server的状态设置该值
struct binder_work { struct list_head entry; // enum { BINDER_WORK_TRANSACTION = 1, 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结构体,并修改它work BINDER_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->node int 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 结束 0 unsigned pending_strong_ref:1; // 请求的时候为1,service增加后为0 unsigned has_weak_ref:1; //请求Service组件时 1 结束 0 unsigned 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->refs struct 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; 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; // struct rb_root nodes; //binder实体对象的集合 以ptr作为关键字 struct rb_root refs_by_desc; struct rb_root refs_by_node; int pid; //进程组的 struct 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小空间 ptrdiff_t user_buffer_offset; //内核缓冲区中 用户空间地址和内核空间地址的差值 struct list_head buffers; //指向指向该列表的头部 struct rb_root free_buffers; //已分配物理页面 struct rb_root allocated_buffers; size_t free_async_space; //保存异步事务数据缓冲区的大小 struct page **pages; //对于的物理页面 数组中每个元素指向一个物理页面 size_t buffer_size; //mmap后内核缓冲区的大小 uint32_t buffer_free; //空闲内核缓冲区的大小 struct list_head todo; //把待处理请求封装成一个工作项,加如到待处理工作项队列 wait_queue_head_t wait; //空闲binder线程会睡眠在等待队列里面 struct binder_stats stats; //统计进程数据的,进程见请求的次数 struct list_head delivered_death; //死亡通知封装成一个工作项保存在所描述的一个队列中,进程收到后会删除 int max_threads; int requested_threads; //驱动主动请求进程注册一个线程时加1,进程响应后减1 int requested_threads_started;//驱动程序主动请求进程注册的数目,进程响应后加1 int 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; //线程ID int 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_looper BINDER_LOOPER_STATE_ENTERED = 0x02, //表明准备就绪BC_ENTER_looper BINDER_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 int code; unsigned int flags; long priority; //线程优先级 long saved_priority; //保存原来的线程优先级 uid_t sender_euid; //线程用户ID };应用程序通过IO命令和驱动交互
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
进程间通信
struct binder_write_read { signed long write_size; /* bytes to write */ 缓冲区大小 signed long write_consumed; /* bytes consumed by driver */ 驱动从缓冲区处理的字节 unsigned long write_buffer; //描述输入数据 从用户空间传输到binder驱动程序的数据 指向一个用户缓冲区地址 signed long read_size; /* bytes to read */ signed long read_consumed; /* bytes consumed by driver */ unsigned long read_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_t handle; /* target descriptor of command transaction */ //引用对象的句柄值 void *ptr; /* target descriptor of return transaction */ //指向Service组件内部弱引用计数的地址 } target; void *cookie; /* target object cookie */ //目标Service组件的地址 unsigned int code; /* transaction command */ //双方约定好的通信代码 /* General information about the transaction. */ unsigned int flags; //描述进程间通信行为的特征 pid_t sender_pid; //进程的pid uid_t sender_euid; // size_t data_size; /* 通信数据的大小 */ size_t offsets_size; /* 偏移数组的大小 */ union { struct { /* transaction data */ const void *buffer; //指向数据缓冲区,真正保存通信数据的 大小由data_size决定 /* offsets from buffer to flat_binder_object structs */ const void *offsets; //保存每一个binder对象的位置,分别指向偏平结构的首地址 } ptr;//数据量大的时候 uint8_t buf[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 long type; //区分是Binder实体对象还是引用对象,亦或是文件描述符 unsigned long flags; //只有描述的是Binder实体,它才有意义 /* 8 bytes of data. */ union { void *binder; /* local Binder实体对象 指向一个内部弱引用对象的地址 */ signed long handle; /* 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 0x85 enum { 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),// };
以上是关于Android Binder驱动中的基础数据结构整理的主要内容,如果未能解决你的问题,请参考以下文章