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驱动中的基础数据结构整理的主要内容,如果未能解决你的问题,请参考以下文章

Android笔记 - Binder之数据结构

Android笔记 - Binder之数据结构

Android Binder实现浅析-Binder驱动

Android binder介绍

[RK3568 Android11] Binder驱动结构体

[RK3568 Android11] Binder驱动结构体