以下源码出自于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反之,调用端会休眠,等待服务端的返回结果