binder驱动源码全注释上

本文深入剖析了Binder驱动的数据结构,包括binder_object、binder_transaction_data等,并详细解释了Binder驱动中关键组件的作用与交互方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要是自己阅读binder驱动时的注释。

大概会先描述下数据结构,然后贴上主要的代码部分。


 //描述一个binder对象
struct flat_binder_object {
	/* 8 bytes for large_flat_header. */
	__u32		type;//binder类型,如BINDER_TYPE_BINDER
	__u32		flags;//只对第一个传递binder实体时有效,因为需要在内核中创建相应的实体节点

	/* 8 bytes of data. */
	union {
		binder_uintptr_t	binder;	//传递binder实体时使用,指向binder实体在应用程序中的地址
		__u32			handle;	//传递binder引用时使用,存放binder在进程中的引用
	};

	/* extra data associated with local object */
	binder_uintptr_t	cookie;//只对binder实体有效,存放与该binder有关的附加信息
};

/*
 * On 64-bit platforms where user code may run in 32-bits the driver must
 * translate the buffer (and local binder) addresses appropriately.
 */
//binder读写数据
struct binder_write_read {
	binder_size_t		write_size;	/* bytes to write */
	binder_size_t		write_consumed;	/* bytes consumed by driver */
	binder_uintptr_t	write_buffer;
	binder_size_t		read_size;	/* bytes to read */
	binder_size_t		read_consumed;	/* bytes consumed by driver */
	binder_uintptr_t	read_buffer;
};

/* Use with BINDER_VERSION, driver fills in fields. */
struct binder_version {
	/* driver protocol version -- increment with incompatible change */
	__s32       protocol_version;
};
//事务传递数据结构
struct binder_transaction_data {
	/* The first two are only used for bcTRANSACTION and brTRANSACTION,
	 * identifying the target and contents of the transaction.
	 */
	union {
		/* target descriptor of command transaction */
		__u32	handle;//binder实体的句柄
		/* target descriptor of return transaction */
		binder_uintptr_t ptr;//指向binder对象的指针,binder驱动将handle转化为ptr
	} target;//接收数据端
	binder_uintptr_t	cookie;	//驱动不关心此值
	__u32		code;	//收发双方约定的命令码	

	/* General information about the transaction. */
	__u32	        flags;
	pid_t		sender_pid;//发送方的进程pid,驱动负责填入
	uid_t		sender_euid;//发送方的user id
	binder_size_t	data_size;//发送方填入,表示data.buffer指向的缓冲区存放的数据长度
	binder_size_t	offsets_size;//偏移数组offsets的大小

	/* If this transaction is inline, the data immediately
	 * follows here; otherwise, it ends with a pointer to
	 * the data buffer.
	 */
	union {
		struct {
			/* transaction data */
			binder_uintptr_t	buffer;//存放发送或者接收的数据
			/* offsets from buffer to flat_binder_object structs */
			binder_uintptr_t	offsets;//数组,指向每个binder引用在data中的偏移位置
		} ptr;
		__u8	buf[8];
	} data;
};


//用来描述待处理的工作项,这些工作项可能属于同一个进程,也可能属于一个进程中的某一个线程
struct binder_work {
	struct list_head entry;//binder work list
	enum {
		BINDER_WORK_TRANSACTION = 1,
		BINDER_WORK_TRANSACTION_COMPLETE,
		BINDER_WORK_NODE,
		BINDER_WORK_DEAD_BINDER,
		BINDER_WORK_DEAD_BINDER_AND_CLEAR,
		BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
	} type;//工作类型
};
//binder本地对象
struct binder_node {
	int debug_id;//标志binder实体对象的身份,帮助调试
	struct binder_work work;
	//一个进程可能用到多个binder对象(可能用到多个service),所有binder对象保存在rb tree中
	union {
		struct rb_node rb_node;
		struct hlist_node dead_node;//如果实体对象的宿主进程死亡,实体对象就保存在全局的hash list中
	};
	struct binder_proc *proc;//binder实体对象的宿主进程
	struct hlist_head refs;//保存引用该实体对象的引用对象的hash list
	int internal_strong_refs;//强引用计数
	int local_weak_refs;
	int local_strong_refs;
	binder_uintptr_t ptr;//指向用户空间service内部的引用计数的地址
	binder_uintptr_t cookie;//指向用户空间service组件的地址
	unsigned has_strong_ref:1;
	unsigned pending_strong_ref:1;
	unsigned has_weak_ref:1;
	unsigned pending_weak_ref:1;
	unsigned has_async_transaction:1;//binder实体对象是否在处理异步事务
	unsigned accept_fds:1;
	unsigned min_priority:8;//线程最小优先级
	struct list_head async_todo;//异步事务队列
};

struct binder_ref_death {
	struct binder_work work;
	binder_uintptr_t cookie;
};

//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;//引用对象id
	struct rb_node rb_node_desc;//以引用对象句柄值作关键字保存到宿主进程的rb tree
	struct rb_node rb_node_node;//以引用对应对应的实体对象的地址作关键字保存到宿主进程的rb tree
	struct hlist_node node_entry;//每个binder实体对象使用一个hash表保存所有引用他的引用对象,该值就是hash表
	struct binder_proc *proc;//binder引用对象的宿主进程
	struct binder_node *node;//引用对象对应的实体对象
	uint32_t desc;//应用对象的句柄,用来给用户进程使用,(对应binder代理对象)
	int strong;//强引用计数
	int weak;//弱引用计数
	struct binder_ref_death *death;//死亡接收通知,client注册死亡接收通知时创建的结构体
};

/*
描述内核缓冲区
*/
struct binder_buffer {
	struct list_head entry; //宿主进程内核缓冲区链表节点
	struct rb_node rb_node; //buffer所属的rb tree(正在使用或者空闲的红黑树)
				
	unsigned free:1;//如果缓冲区为空,该值为1,代表buffer在free rb tree中
	unsigned allow_user_free:1;//是否允许用户使用这个buffer
	unsigned async_transaction:1;//是否异步事务处理
	unsigned debug_id:29;//buffer id

	struct binder_transaction *transaction;//该缓冲区由哪个事务处理

	struct binder_node *target_node;//该缓冲区由哪个binder实体对象使用
/*
data 指向一块大小可变的数据缓冲区,它是用来保存真正的通信数据
数据缓冲区保存的数据可分为两类,一种是普通数据,一种是Binder对象。Binder驱动程序不关心数据缓冲区的普通数据,
但必须知道里面的Binder对象,因为它需要根据它们              来维护内核中的Binder实体对象和Binder引用对象的生命周期。在数据缓冲区的后面,有一个偏移数组,
它记录了数据缓冲区中每一个Binder对象在数据缓冲区中的位置。
偏移数组的大小保存在成员变量 offsets_size 中,而数据缓冲区的大小保存在变量 data_size 中。	
*/
	size_t data_size;//data大小
	size_t offsets_size;//数组,保存了每个binder对象的偏移
	uint8_t data[0];//保存通信数据,这里面保存了普通数据跟binder对象
};

enum binder_deferred_state {
	BINDER_DEFERRED_PUT_FILES    = 0x01,//为binder缓冲区创建一个文件描述符
	BINDER_DEFERRED_FLUSH        = 0x02, //延迟工作项,用来唤醒进程binder处理线程
	BINDER_DEFERRED_RELEASE      = 0x04,//释放binder资源比较耗时,创建一个延迟工作项来进行
};
//描述一个正在使用Binder进程间通信机制的进程
struct binder_proc {
	struct hlist_node proc_node;//所有binder_proc保存在一个hash list中
	struct rb_root threads;//进程线程池,rb tree存储,threads是rb tree root node
	//进程内部包含了一系列binder实体跟引用对象
	struct rb_root nodes;//binder实体对象,存储实体对象的ptr
	struct rb_root refs_by_desc;//引用对象,用desc作关键字查找
	struct rb_root refs_by_node;//引用对象,用node作关键字查找
	int pid;//进程pid
	struct vm_area_struct *vma;//内核缓冲区对应的vma
	struct mm_struct *vma_vm_mm;
	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;//用于内核地址跟用户空间地址转换
	/*
	binder_buffer小块缓冲区用list来组织,buffers指向list头。
	这些小块内存区再分成已经使用的和空闲的缓冲区,组织在两个rb tree中
	*/
	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;//内核缓冲区大小
	uint32_t buffer_free;//空闲内核缓冲区大小
	struct list_head todo;//进程待处理的工作队列
	wait_queue_head_t wait;//binder处理线程等待队列,进程有工作任务时唤醒队列中的处理线程
	struct binder_stats stats;
	struct list_head delivered_death;//用来向进程通知其使用的service dead 消息,
	int max_threads;//对该进程来说,binder驱动最大可注册的线程数
	int requested_threads;//binder驱动请求进程注册线程时的mutex值
	int requested_threads_started;//binder驱动主动请求进程注册了多少个线程
	int ready_threads;//当前进程空闲线程数(线程指的是专门用于处理binder通信的线程)
	long default_priority;//进程优先级
	struct dentry *debugfs_entry;
};


/*
 *   一个线程注册到Binder驱动程序时,Binder驱动程序会为它创建一个binder_thread结构体,并且将它的状态初始化为 BINDER_LOOPER_STATE_NEED_RETURN,表示该线程需要马上返回
 * 到用户空间。由于一个线程在注册为Binder线程时可能还没有准备好去处理进程间通信请求时,因此,最好返回到用户空间去做准备工作。此外,当进程调用函数 flush 来刷新它的Binder线程池
 * 时,Binder线程池中的线程状态也会被重置为BINDER_LOOPER_STATE_NEED_RETURN.
 *   一个线程注册到Binder驱动程序后,它接着就会通过BC_REGISTER_LOOPER或者BC_ENTER_LOOPER协议来通知Binder驱动程序,它可以处理进程间通信请求了,这时候Binder驱动程序
 * 就会将它的状态设置为BINDER_LOOPER_STATE_REGISTERED或者BINDER_LOOPER_STATE_ENTERED.如果一个线程是应用程序主动注册的,那么它就通过BC_ENTER_LOOPER协议来通知Binder
 * 驱动程序,它已经准备就绪处理进程间通信请求了;如果一个线程是Binder驱动程序请求创建的,那么它就通过BC_REGISTER_LOOPER协议来通知Binder驱动程序,这时候Binder驱动程序就会
 * 增加它所请求进程创建的Binder线程数目。
 *   当一个Binder线程处于空闲状态时,Binder驱动程序就会把它的状态设置为BINDER_LOOPER_STATE_WAITING;而当一个Binder线程退出时,它就会通过BC_EXIT_LOOPER协议来通知Binder
 * 驱动程序,这时候Binder驱动程序就会将它的状态设置为BINDER_LOOPER_STATE_EXITED.在异常情况下,一个Binder线程的状态会被设置为BINDER_LOOPER_STATE_INVALID,例如,当该线程
 * 已经处于BINDER_LOOPER_STATE_REGITERED状态时,如果它又再次通过BC_ENTER_LOOPER协议来通知Binder驱动程序它已经准备就绪,那么Binder驱动程序就会将它的状态设置为BINDER_LOOPER_STATE_INVALID.
 *   当一个来自Client进程的请求指定要由某一个Binder线程处理时,这个请求就会加入到相应的binder_thread结构体的成员变量todo所表示的队列中,并且唤醒这个线程来处理。
 *   当Binder驱动程序决定将一个事务交给一个Binder线程处理时,它就会将该事务封装成一个 binder_transaction 结构体,并且将它添加到线程结构体 binder_thread 的成员变量 transaction_stack
 * 所描述的一个事务堆栈中。
 *   一个Binder线程在处理一个事务时,如果出现了异常情况,那么Binder驱动程序就会将相应的错误码保存在 return_error 和 return_error2 中,这时候线程就会将错误码返回给用户空间应用程序处理。
 *   最后,stats是用来统计Binder线程数据的。例如,Binder线程接收到的进程间通信请求的次数。
*/

enum {
	BINDER_LOOPER_STATE_REGISTERED  = 0x01,
	BINDER_LOOPER_STATE_ENTERED     = 0x02,
	BINDER_LOOPER_STATE_EXITED      = 0x04,
	BINDER_LOOPER_STATE_INVALID     = 0x08,
	BINDER_LOOPER_STATE_WAITING     = 0x10,
	BINDER_LOOPER_STATE_NEED_RETURN = 0x20
};
//描述Binder线程池中的一个线程
struct binder_thread {
	struct binder_proc *proc;//该线程所属进程
	struct rb_node rb_node;//进程采用rb tree存储线程池
	int pid;//binder线程id
	int looper;//binder线程状态,取值为上面定义的enum BINDER_LOOPER_STATE_REGISTERED
	struct binder_transaction *transaction_stack;//当Binder驱动程序决定将一个事务交给一个Binder线程处理时,它就会将该事务封装成一个 binder_transaction 结构体,并且将它添加到线程结构体 binder_thread 的成员变量 transaction_stack
	struct list_head todo;//当一个来自Client进程的请求指定要由某一个Binder线程处理时,这个请求就会加入到相应的binder_thread结构体的成员变量todo所表示的队列中,并且唤醒这个线程来处理
	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;//binder线程等待队列
	struct binder_stats stats;//统计binder通信状态
};
//描述进程间通信过程,这个过程又称为一个事务
struct binder_transaction {
	int debug_id;//事物id
	struct binder_work work;
	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;//同步异步模式标识
	/* unsigned is_dead:1; */	/* not used at the moment */

	struct binder_buffer *buffer;//该事务占有的缓冲区
	unsigned int	code;
	unsigned int	flags;
	long	priority;//源线程优先级
	long	saved_priority;//保存线程之前的优先级
	kuid_t	sender_euid;//源线程user id
	//目标线程在处理一个事务时,它的线程优先级不能低于目标Service组件所要求的线程优先级,而且也不能低于源线程的优先级
};

//获取一个未使用的fd
static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
{
	struct files_struct *files = proc->files;//进程打开文件表
	unsigned long rlim_cur;
	unsigned long irqs;

	if (files == NULL)
		return -ESRCH;

	if (!lock_task_sighand(proc->tsk, &irqs))
		return -EMFILE;

	rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);//打开文件数量限制
	unlock_task_sighand(proc->tsk, &irqs);

	return __alloc_fd(files, 0, rlim_cur, flags);//给此进程分配一个未使用的文件标识符
}

/*
 * copied from fd_install
 */
static void task_fd_install(
	struct binder_proc *proc, unsigned int fd, struct file *file)
{
	if (proc->files)//file加入到进程fdt表中
		__fd_install(proc->files, fd, file);
}

/*
 * copied from sys_close
 */
 //关闭进程fd对应的文件
static long task_close_fd(struct binder_proc *proc, unsigned int fd)
{
	int retval;

	if (proc->files == NULL)
		return -ESRCH;

	retval = __close_fd(proc->files, fd);
	/* can't restart close syscall because file table entry was cleared */
	if (unlikely(retval == -ERESTARTSYS ||
		     retval == -ERESTARTNOINTR ||
		     retval == -ERESTARTNOHAND ||
		     retval == -ERESTART_RESTARTBLOCK))
		retval = -EINTR;

	return retval;
}

//调整CFS进程nice值
static void binder_set_nice(long nice)
{
	long min_nice;

	if (can_nice(current, nice)) {//当前进程优先级能否修改成nice值
		set_user_nice(current, nice);//修改进程优先级(调整load),然后重新入队等待调动
		return;
	}
	//上面nice值过小,找到最小可设置的nice值再调整进程优先级
	min_nice = 20 - current->signal->rlim[RLIMIT_NICE].rlim_cur;
	binder_debug(BINDER_DEBUG_PRIORITY_CAP,
		     "%d: nice value %ld not allowed use %ld instead\n",
		      current->pid, nice, min_nice);
	set_user_nice(current, min_nice);
	if (min_nice < 20)
		return;
	binder_user_error("%d RLIMIT_NICE not set\n", current->pid);
}

//用来获取binder_buffer中存储data数据的大小,data_size用途???
//主要理解进程缓冲区存储方式:按照list方式将binder_buffer组织起来
static size_t binder_buffer_size(struct binder_proc *proc,
				 struct binder_buffer *buffer)
{	//buffer的内存缓冲区节点是否是进程proc进程缓冲区list的最后一个节点
	if (list_is_last(&buffer->entry, &proc->buffers))
		return proc->buffer + proc->buffer_size - (void *)buffer->data; //进程proc剩余的内存缓冲区大小
	return (size_t)list_entry(buffer->entry.next,
			  struct binder_buffer, entry) - (size_t)buffer->data; //进程proc下个buffer节点地址减去data地址,
			                                                       //这段空间用来保存data数据
}
/*
往进程rb tree 中插入一个新的free buffer
进程的binder_buffer组织分成了两种数据结构,一个是所有buffer都依次插入list struct list_head buffers,
这些buffer同时会构建成两颗rb tree struct rb_root free_buffers,struct rb_root allocated_buffers
*/
static void binder_insert_free_buffer(struct binder_proc *proc,
				      struct binder_buffer *new_buffer)
{
	struct rb_node **p = &proc->free_buffers.rb_node;//free buffer rb tree
	struct rb_node *parent = NULL;
	struct binder_buffer *buffer;
	size_t buffer_size;
	size_t new_buffer_size;

	BUG_ON(!new_buffer->free);
	//获取binder_buffer有效存储data的大小
	new_buffer_size = binder_buffer_size(proc, new_buffer);

	binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
		     "%d: add free buffer, size %zd, at %p\n",
		      proc->pid, new_buffer_size, new_buffer);

	while (*p) {//rb tree查找,从free_buffers root节点开始,按照buffer size进行查找
		parent = *p;
		buffer = rb_entry(parent, struct binder_buffer, rb_node);
		BUG_ON(!buffer->free);

		buffer_size = binder_buffer_size(proc, buffer);

		if (new_buffer_size < buffer_size)
			p = &parent->rb_left;
		else
			p = &parent->rb_right;
	}
	//new_buffer插入到合适的节点
	rb_link_node(&new_buffer->rb_node, parent, p);
	rb_insert_color(&new_buffer->rb_node, &proc->free_buffers);//调整rb tree,使其满足着色要求
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值