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),//};
- Android Binder驱动中的基础数据结构整理
- Android Binder 驱动分析 - 数据结构
- Android Binder 驱动分析 - 数据结构
- Android Binder 驱动分析 - 数据结构
- android Binder机制2---Binder的数据结构以及Binder驱动
- Android Binder机制(二) Binder中的数据结构
- Android Binder机制(二) Binder中的数据结构
- android binder机制---Binder驱动
- binder 3 驱动层数据结构
- Binder机制2---Binder的数据结构以及Binder驱动
- Binder机制2---Binder的数据结构以及Binder驱动
- Binder机制2---Binder的数据结构以及Binder驱动
- android Binder驱动研究
- Android Binder 驱动分析
- Android--Binder驱动浅析
- Android - Binder驱动
- Android Binder 驱动分析
- android系统学习笔记——binder基础数据结构1
- Liferay DXP数字体验平台,荣耀绽放:端对端的客户体验
- The Definitive Antlr 4 第7章学习笔记
- 11_奇偶数分离
- POJ 1742 dp
- 动态管理内存之new和delete
- Android Binder驱动中的基础数据结构整理
- hdu2098
- struct hypot typedef
- Mac OS X 利用 Automator/Xcode 控制隐藏文件
- const与class
- igrimace V3 VX 3.0 ig 闪退解决方式
- /usr/local/Trolltech/QtEmbedded-4.8.5-arm/include/QtCore/qatomic_armv5.h:131: 错误:no such instruction
- Android防止多次点击
- 【LeetCode】145. Binary Tree Postorder Traversal 解题报告