binder源码分析(三)

本文详细剖析了Android Binder交易的源码流程,从binder_transaction开始,涉及binder_thread_read、service_manager的唤醒与处理,以及通信完成后service_manager的回复。文章分析了3.18内核与4.9内核在处理上的差异,强调了BR_TRANSACTION_COMPLETE在单向通信中的作用。同时,探讨了binder_proc中四棵红黑树的设计理念,为理解Binder机制提供了深入见解。
摘要由CSDN通过智能技术生成

binder源码分析(一)
binder源码分析(二)
binder源码分析(三)
binder源码分析(四)
binder源码分析(五)

binder_transaction

binder_transaction比较长,首先要有一些结构体的认识:

  1. binder_node 可以理解为binder实体的节点
  2. binder_work binder驱动中的事务
  3. binder_proc 进程所持有的binder信息,值得注意的是,binder_proc有四棵红黑树,分别是threads,nodes,refs_by_desc和refs_by_node
  4. binder_thread 线程持有的binder信息
  5. binder_buffer 用户线程与内核的内存映射

接着看函数实现,抛开前面的变量声明和reply的情况,首先是查找目标node和proc,可以的话获得对应的目标thread。

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply)
{
   
	... //变量声明
	if (reply) {
   
		...
	} else {
   
		// 1.这里handle为0代表service_manager,所以直接将binder_context_mgr_node赋值给target_node,
		// 	之前说到过,service_manager启动时就是创建binder_context_mgr_node节点。
		// 2.否则就会去查询proc的refs_by_desc是否包含该handle的节点。
		if (tr->target.handle) {
   
			struct binder_ref *ref;
			
			ref = binder_get_ref(proc, tr->target.handle);
			if (ref == NULL) {
   
				binder_user_error("%d:%d got transaction to invalid handle\n",
					proc->pid, thread->pid);
				return_error = BR_FAILED_REPLY;
				goto err_invalid_target_handle;
			}
			target_node = ref->node;
		} else {
   
			target_node = binder_context_mgr_node;
			if (target_node == NULL) {
   
				return_error = BR_DEAD_REPLY;
				goto err_no_context_mgr_node;
			}
		}
		e->to_node = target_node->debug_id;
		target_proc = target_node->proc;
		if (target_proc == NULL) {
   
			return_error = BR_DEAD_REPLY;
			goto err_dead_binder;
		}
		if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
   
			return_error = BR_FAILED_REPLY;
			goto err_invalid_target_handle;
		}
		// 如果是双向通信,且目标线程有事务栈。
		if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
   
			struct binder_transaction *tmp;

			tmp = thread->transaction_stack;
			// 事务栈栈顶的目标应该与持有该栈的线程相同。
			if (tmp->to_thread != thread) {
   
				binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n",
					proc->pid, thread->pid, tmp->debug_id,
					tmp->to_proc ? tmp->to_proc->pid : 0,
					tmp->to_thread ?
					tmp->to_thread->pid : 0);
				return_error = BR_FAILED_REPLY;
				goto err_bad_call_stack;
			}
			// 查找是否存在与当前thread沟通的历史事务,有的话直接与该事务的线程通信。
			while (tmp) {
   
				if (tmp->from && tmp->from->proc == target_proc)
					target_thread = tmp->from;
				tmp = tmp->from_parent;
			}
		}
	}

接着开始设置或者创建一些通信相关的变量。

// 设置目标todod队列和等待队列
if (target_thread) {
   
		e->to_thread = target_thread->pid;
		target_list = &target_thread->todo;
		target_wait = &target_thread->wait;
	} else {
   
		target_list = &target_proc->todo;
		target_wait = &target_proc->wait;
	}
	e->to_proc = target_proc->pid;

	/* TODO: reuse incoming transaction for reply */
	// 创建binder_transaction
	t = kzalloc(sizeof(*t), GFP_KERNEL);
	if (t == NULL) {
   
		return_error = BR_FAILED_REPLY;
		goto err_alloc_t_failed;
	}
	binder_stats_created(BINDER_STAT_TRANSACTION);

	// 创建binder_work
	tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
	if (tcomplete == NULL) {
   
		return_error = BR_FAILED_REPLY;
		goto err_alloc_tcomplete_failed;
	}
	binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);

	t->debug_id = ++binder_last_id;
	e->debug_id = t->debug_id;

	// debug相关

	// 设置此次通信事务的源头、目标进线程、code、flag等
	if (!reply && !(tr->flags & TF_ONE_WAY))
		t->from = thread;
	else
		t->from = NULL;
	t->sender_euid = task_euid(proc->tsk);
	t->to_proc = target_proc;
	t->to_thread = target_thread;
	t->code = tr->code;
	t->flags = tr->flags;
	t->priority = task_nice(current);

	trace_binder_transaction(reply, t, target_node);

	// 创建binder_buffer。注意binder_alloc_new_buf中的参数是目标进程的proc,
	// 意思是直接目标进程的内核空间中创建,这是一次拷贝的关键。
	t->buffer = binder_alloc_buf(target_proc, tr->data_size,
		tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
	if (t->buffer == NULL) {
   
		return_error = BR_FAILED_REPLY;
		goto err_binder_alloc_buf_failed;
	}
	t->buffer->allow_user_free = 0;
	t->buffer->debug_id = t->debug_id;
	t->buffer->transaction = t;
	t->buffer->target_node = target_node;
	trace_binder_transaction_alloc_buf(t->buffer);
	if (target_node)
		binder_inc_node(target_node, 1, 0, NULL);
	
	offp = (binder_size_t *)(t->buffer->data +
				 ALIGN(tr->data_size, sizeof(void *)));
	// 拷贝用户空间的数据。
	if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
			   tr->data.ptr.buffer, tr->data_size)) {
   
		binder_user_error("%d:%d got transaction with invalid data ptr\n",
				proc->pid, thread->pid);
		return_error = BR_FAILED_REPLY;
		goto err_copy_data_failed;
	}
	if (copy_from_user(offp, (const void __user *)(uintptr_t)
			   tr->data.ptr.offsets, tr->offsets_size)) {
   
		binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
				proc->pid, thread->pid);
		return_error = BR_FAILED_REPLY;
		goto err_copy_data_failed;
	}
	if 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值