一. 概述
这里以注册服务为例,当led_control_service
请求注册服务时是通过handle找到的ServiceManager
,但是ServiceManager
是如何找到led_control_service
进行回复的呢?
答:这里驱动中用到了一个传送栈记录了发送和接收进程,线程的信息; 接下来我们讲下具体的流程;
二. transaction_stack的来源
主要代码在binder_transaction()
和binder_thread_read()
中;
2.1 BC_TRANSACTION
从led_control_service
调用BC_TRANSACTION
开始,此时驱动会调用binder_transaction()
函数;
如下是该函数中的一段代码,这段代码前面在深入驱动时未讲解:
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);
①: 判断是否需要回复,需要则记录下当前进程的thread信息;
②: 记录下要目标进程信息和线程信息;
这里t
是struct binder_transaction
结构,和transaction_stack
类型相同;
struct binder_transaction {
int debug_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;
.....
};
①: 记录发送线程信息;
②: 记录发送线程的传输栈的父栈;
③: 记录接收进程的进程信息;
④: 记录接收线程的进程信息;
⑤: 记录接收进程的传输栈的父栈;
此时t
变量中的主要信息如下:
transaction_starck | |
---|---|
from | led_control_service'thread |
to_proc | ServiceManager |
to_thread | ServiceManager'thread |
此时已经记录下了接收方的信息了,继续往下看(binder_transaction()
函数内):
if (reply) {
BUG_ON(t->buffer->async_transaction != 0);
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) { ①
BUG_ON(t->buffer->async_transaction != 0);
t->need_reply = 1;
t->from_parent = thread->transaction_stack; ②
thread->transaction_stack = t; ③
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo;
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
}
①: 判断是否需要回复;
②: 这里一个入栈操作将当前线程的传输压入,但是thread->transaction_stack
此时为NULL
,因为第一次执行前面没有赋值;
③: 接下给当前线程的传输栈赋值,;
此时led_control_service
线程的传输栈信息如下:
transaction_starck | |
---|---|
from | led_control_service'thread |
to_proc | ServiceManager |
to_thread | ServiceManager'thread |
from_parent | NULL |
2.2 BR_TRANSACTION
前面驱动讲解过,在led_contrl_server
执行binder_transaction()
后,ServiceManager
的进程会被唤醒,则ServiceManager
会从休眠中醒来继续执行binder_thread_read
;
binder_thread_read
有段代码如下:
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
t->to_parent = thread->transaction_stack; ①
t->to_thread = thread; ②
thread->transaction_stack = t; ③
} else {
t->buffer->transaction = NULL;
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
①: 将当前线程传输栈入栈;
②: 记录接收进程的信息,也就是自己本身,因为他本身是被唤醒的;
③: 当前线程传输栈记录下线程信息;
这里的t
是从带处理事务的链表中取出来的,也就是前面led_control_service
挂到ServiceManager
的todo链表上;
则ServiceManager
线程的传输栈的信息如下:
transaction_starck | |
---|---|
from | led_control_service'thread |
to_proc | ServiceManager |
to_thread | ServiceManager'thread |
from_parent | NULL |
to_parent | NULL |
到这里线程传输栈的数据来源和构造讲完;
三. transaction_stack的使用
ServiceManager
的用户态在处理完注册信息后,调用BC_REPLAY
命令回复注册结果给led_control_service
,此时驱动中也是调用到binder_transaction()
;
binder_transaction
代码片如下:
if (reply) {
in_reply_to = thread->transaction_stack; ①
ALOGD("%s:%d,%d %s in_reply_to = thread->transaction_stack\n", proc->tsk->comm, proc->pid, thread->pid, __FUNCTION__);
if (in_reply_to == NULL) {
binder_user_error("%d:%d got reply transaction with no transaction stack\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_empty_call_stack;
}
binder_set_nice(in_reply_to->saved_priority);
if (in_reply_to->to_thread != thread) { ②
return_error = BR_FAILED_REPLY;
in_reply_to = NULL;
goto err_bad_call_stack;
}
thread->transaction_stack = in_reply_to->to_parent; ③
target_thread = in_reply_to->from; ④
if (target_thread == NULL) {
return_error = BR_DEAD_REPLY;
goto err_dead_binder;
}
if (target_thread->transaction_stack != in_reply_to) {
return_error = BR_FAILED_REPLY;
in_reply_to = NULL;
target_thread = NULL;
goto err_dead_binder;
}
target_proc = target_thread->proc;
} else {
①: 用个临时变量记录下当前线程额传输栈信息;
②: 判断下接收的线程是否为自己本身,如果不是则出错,看迷糊的可以看下再2.2节;
③: 一次出栈操作,此时thread->transaction_stack
值为NULL
了;
④: 获取到目标线程,from
中记录着发送线程led_contol_service
的信息;
这里就通过ServiceManager
在read的时候入栈的传送栈信息,获取到发送进程的信息,即回复进程的信息;
接着往下看:
if (reply) {
BUG_ON(t->buffer->async_transaction != 0);
binder_pop_transaction(target_thread, in_reply_to); ①
} else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
} else {
...
}
①: 一个出栈操作;
此时led_control_service
的传输栈也指向了父栈,即为空且清除了in_reply_to
中from
的信息;
上面那部ServiceManager
进程已经知道此时要发送给谁,到此该问题就完美解答了;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。