一. 概述
這裏以註冊服務爲例,當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
進程已經知道此時要發送給誰,到此該問題就完美解答了;