关于AIDL接口定义中oneway的修饰符源码解析.

深入解析Android Binder机制中oneway修饰符的作用,阐述其如何确保异步调用的串行执行,以及对不同进程间远程接口调用的影响。

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

以下源码出自于Android 8.1

该部分源码基于我另外一篇文章,Binder通信流程浅析有提到,在binder进行传输数据时有提到这个方法binder_proc_transaction,该方法是把当前client要发送的数据t加入到队列中,并唤起binder线程执行该事务,当时忽略了一个细节oneway修饰符:

static bool binder_proc_transaction(struct binder_transaction *t,
				    struct binder_proc *proc,
				    struct binder_thread *thread)
{
	struct list_head *target_list = NULL;
	struct binder_node *node = t->buffer->target_node;
	struct binder_priority node_prio;
	bool oneway = !!(t->flags & TF_ONE_WAY);
	bool wakeup = true;

	BUG_ON(!node);
	binder_node_lock(node);
	node_prio.prio = node->min_priority;
	node_prio.sched_policy = node->sched_policy;

	if (oneway) {
		BUG_ON(thread);
		if (node->has_async_transaction) {
			target_list = &node->async_todo;
			wakeup = false;
		} else {
			node->has_async_transaction = 1;
		}
	}

	binder_inner_proc_lock(proc);

	if (proc->is_dead || (thread && thread->is_dead)) {
		binder_inner_proc_unlock(proc);
		binder_node_unlock(node);
		return false;
	}

	if (!thread && !target_list)
		thread = binder_select_thread_ilocked(proc);

	if (thread) {
		target_list = &thread->todo;
		binder_transaction_priority(thread->task, t, node_prio,
					    node->inherit_rt);
	} else if (!target_list) {
		target_list = &proc->todo;
	} else {
		BUG_ON(target_list != &node->async_todo);
	}

	binder_enqueue_work_ilocked(&t->work, target_list);

	if (wakeup)
		binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);

	binder_inner_proc_unlock(proc);
	binder_node_unlock(node);

	return true;
}

我们在定义AIDL接口的时候,可以在方法返回值前,加个oneway进行修饰,如下:

interface ITest {
    oneway void test1();//异步
    oneway void test2();//异步
    int test3();// 同步
}

简单的说,oneway表示的异步调用,串行执行,什么意思呢,看代码:
如果接口方法加了oneway修饰,那么通过 bool oneway = !!(t->flags & TF_ONE_WAY);这行代码得到的bool为1.
假设有两个进程分别为B跟C同时调用ITest.test1(),服务端是否能同时响应这两个binder请求?

我们看第一次的执行逻辑:

static bool binder_proc_transaction(struct binder_transaction *t,
				    struct binder_proc *proc,
				    struct binder_thread *thread)
{
	struct list_head *target_list = NULL;
	struct binder_node *node = t->buffer->target_node;
	struct binder_priority node_prio;
	bool oneway = !!(t->flags & TF_ONE_WAY);
	bool wakeup = true;

	BUG_ON(!node);
	binder_node_lock(node);
	node_prio.prio = node->min_priority;
	node_prio.sched_policy = node->sched_policy;
    //第一次进来,oneway为1,表示true
	if (oneway) {
		BUG_ON(thread);
		//node->has_async_transaction默认为0的,表示false
		if (node->has_async_transaction) {
		//不执行这个if
			target_list = &node->async_todo;
			wakeup = false;
		} else {
			node->has_async_transaction = 1;
		}
	}

	binder_inner_proc_lock(proc);

	if (proc->is_dead || (thread && thread->is_dead)) {
		binder_inner_proc_unlock(proc);
		binder_node_unlock(node);
		return false;
	}

    //第一次oneway调用,thread为空,target_list也为空,找到一个空闲的线程,响应这次的调用
	if (!thread && !target_list)
		thread = binder_select_thread_ilocked(proc);

	if (thread) {
	   //第一次调用执行这个if
		target_list = &thread->todo;
		binder_transaction_priority(thread->task, t, node_prio,
					    node->inherit_rt);
	} else if (!target_list) {
		target_list = &proc->todo;
	} else {
		BUG_ON(target_list != &node->async_todo);
	}
    //把任务入队
	binder_enqueue_work_ilocked(&t->work, target_list);
    //第一次wakeup为true,唤醒一条线程执行工作队列中的任务
	if (wakeup)
		binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);

	binder_inner_proc_unlock(proc);
	binder_node_unlock(node);

	return true;
}

第二次的执行逻辑:

static bool binder_proc_transaction(struct binder_transaction *t,
				    struct binder_proc *proc,
				    struct binder_thread *thread)
{
	struct list_head *target_list = NULL;
	struct binder_node *node = t->buffer->target_node;
	struct binder_priority node_prio;
	bool oneway = !!(t->flags & TF_ONE_WAY);
	bool wakeup = true;

	BUG_ON(!node);
	binder_node_lock(node);
	node_prio.prio = node->min_priority;
	node_prio.sched_policy = node->sched_policy;
    //第二次执行ITest.test2(),因为调用的是同一个服务,所以实体node是之前是一样的,也就是说经过第一次调用,node->has_async_transaction已经为1.
	if (oneway) {
		BUG_ON(thread);
		if (node->has_async_transaction) {
		//所以第二次调用执行这个if
			target_list = &node->async_todo;
			wakeup = false;
		} else {
			node->has_async_transaction = 1;
		}
	}

	binder_inner_proc_lock(proc);

	if (proc->is_dead || (thread && thread->is_dead)) {
		binder_inner_proc_unlock(proc);
		binder_node_unlock(node);
		return false;
	}
   //第二次调用oneway方法,不执行这个if,即thread为空,但target_list已经赋值为node->async_todo,但值还是为null.
	if (!thread && !target_list)
	//不执行
		thread = binder_select_thread_ilocked(proc);

	if (thread) {
		target_list = &thread->todo;
		binder_transaction_priority(thread->task, t, node_prio,
					    node->inherit_rt);
	} else if (!target_list) {
		target_list = &proc->todo;
	} else {
	//执行这里
		BUG_ON(target_list != &node->async_todo);
	}
   //第二次调用把任务放到target_list,此时target_list就是node->async_todo,不会立即执行改请求
	binder_enqueue_work_ilocked(&t->work, target_list);
   //wakeup为false
	if (wakeup)
		binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);

	binder_inner_proc_unlock(proc);
	binder_node_unlock(node);

	return true;
}

结论:
1.当不同进程同时调用远程接口的同一个用oneway修饰的方法时,server端是不会同时响应的,必须等 前一个先执行完,排队一个个来.
2.当不同进程同时调用远程接口的不同(oneway修饰)方法时,结论同1一致,因为binder实体node是相同的,还是得排队一个个来.
3.如果node不同,则可以同时响应.
4.oneway修饰,表示调用端不会阻塞,无需等待服务端的返回结果,提高效率,非oneway反之,调用端会休眠,等待服务端的返回结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值