接上一章.
33.binder_thread_read
源線程, 即 AMS, 從上一章的第 32 步函數 binder_transaction
返回第 29 步 binder_thread_write
之後, 繼續返回到第 28 步 binder_ioctl_write_read
函數中調用 binder_thread_read
函數.
爲什麼執行 binder_thread_read, 可見上一章第 27 步中的代碼 04-05 處的文字分析
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
...
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
trace_binder_write_done(ret);
...
}
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
...
}
...
}
執行 binder_thread_read
函數來處理源線程 thread
的 todo
隊列中類型爲 BINDER_WORK_TRANSACTION_COMPLETE
的工作項. 下面是 binder_thread_read
代碼
源碼路徑: kernel 3.18下的 /drivers/staging/android/binder.c
static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed, int non_block)
{
...
while (1) {
...
01 if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work,entry);
} else if (...) {
...
} else {
...
}
...
switch (w->type) {
...
case BINDER_WORK_TRANSACTION_COMPLETE: {
cmd = BR_TRANSACTION_COMPLETE;
02 if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
...
} break;
...
}
...
return 0;
}
在代碼 01 處判斷線程 thread
的 todo
隊列不爲 NULL, 這裏命中 if
, 取出線程 thread
的 todo
隊列中類型爲 BINDER_WORK_TRANSACTION_COMPLETE
的工作項保存在 binder_work
結構體 w
中.
接着在代碼 02 處將一個 BR_TRANSACTION_COMPLETE
返回協議寫入到用戶空間提供的緩衝區中.
這裏可以看出, Binder 驅動程序處理類型爲
BINDER_WORK_TRANSACTION_COMPLETE
的工作項的方式就是向相應的進程發送一個BR_TRANSACTION_COMPLETE
返回協議
函數 binder_thread_read
執行完之後, 返回到上一章第 27 步的 IPCThreadState.talkWithDriver
中的代碼06- 07 處將 Binder 驅動程序發送的返回協議保存在類內部的返回協議緩衝區 mIn
中. 再返回到第 26 步的時候. 就可以通過解析返回協議緩衝區 mIn
的內容來執行相對應的操作了.
現在返回到第 26步的 IPCThreadState.waitForResponse
中, 處理 Binder 驅動程序爲進程發送的 BR_TRANSACTION_COMPLETE
返回協議.
34. IPCThreadState.waitForResponse
源碼路徑: /frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
01 if ((err=talkWithDriver()) < NO_ERROR) break;
...
02 cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
}
...
}
return err;
}
上面所有的步驟都是在代碼 01 處完成. 現在代碼 01 處已經執行完畢, 並且將 Binder 驅動層發送的返回協議保存在類內部的返回協議緩衝區 mIn
中, 現在接着向下執行.
在代碼 02 處通過返回協議緩衝區 mIn
來獲得這個 BR_TRANSACTION_COMPLETE
返回協議.
這個返回協議的處理較爲簡單, 就是跳出 switch
語句後, 重新執行外層的 while
循環, 即再次調用 01 處代碼與 Binder 驅動程序交互.
再次進入到 talkWithDriver
函數時, 由於 IPCThreadState
類內部的命令協議緩衝區 mOut
中的命令協議, 以及返回緩衝區 mIn
中的返回協議都已經處理完成了, 因此當它再次通過 IO 控制命令 BINDER_WRITE_READ
進入到 Binder 驅動程序的函數 binder_ioctl
時, 就會直接調用函數 binder_thread_read
在內部休眠等待目標進程將上次發出的進程間通信請求的結果返回回來, 將其喚醒. 即休眠等待 SM 進程將註冊結果返回後喚醒.
OK ,現在到喚醒 SM 進程來處理它 todo
隊列中類型爲 BINDER_WORK_TRANSACTION
的工作項了.
35. binder_thread_read 喚醒 ServiceManager 進程
源碼路徑: kernel 3.18下的 /drivers/staging/android/binder.c
binder_thread_read
函數主要就是負責處理一個線程或者一個進程的todo
工作隊列中的工作項, 處理完成後, 就會向目標進程發送一個返回協議.
上一步將一個類型爲 BINDER_WORK_TRANSACTION
的工作項添加到了目標進程的 todo
隊列. 那麼接下來目標進程 SM 就會被喚醒, 繼續向下執行 binder_thread_read
函數. 後續代碼較多, 分爲兩段進行分析.
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
...
if (non_block) {
...
} else
01 ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} else {
...
}
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
02 if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work,entry);
03 } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
w = list_first_entry(&proc->todo, struct binder_work,entry);
} else {
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}
...
首先代碼 01 處就是之前 SM 休眠的地方, 現在有工作項進入了, 就接着向下分析.
在代碼 02 處檢查線程 thread
自己的 todo
隊列中是否有工作項需要處理. 如果沒有, 在代碼 03處再檢查它所屬進程 proc
的 todo
隊列中是否有工作項需要處理. 只要兩個中的任何一個todo
隊列中有工作項需要處理, 就會將它取出來保存在 binder_word
結構體 w
中.
binder_thread_read
代碼第二段
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
01 t = container_of(w, struct binder_transaction, work);
} break;
...
02 if (t->buffer->target_node) {
..
03 tr.target.ptr = target_node->ptr;
04 tr.cookie = target_node->cookie;
...
cmd = BR_TRANSACTION;
} else {
...
}
05 tr.code = t->code;
06 tr.flags = t->flags;
...
07 tr.data_size = t->buffer->data_size;
08 tr.offsets_size = t->buffer->offsets_size;
09 tr.data.ptr.buffer = (binder_uintptr_t)( (uintptr_t)t->buffer->data + proc->user_buffer_offset);
10 tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
...
11 list_del(&t->work.entry);
12 t->buffer->allow_user_free = 1;
13 if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;
} else {
...
}
break;
}
代碼 01 處由於 binder_word
結構體 w
的類型爲 BINDER_WORK_TRANSACTION
, 即它是一個嵌入在一個 binder_transaction
結構體中的工作項, 因此就可以安全的將它轉換爲一個 binder_transaction
結構體 t
.
Binder 驅動程序處理
BINDER_WORK_TRANSACTION
類型的工作項的方式是向目標線程thread
發送一個BR_TRANSACTION
返回協議.BR_TRANSACTION
返回協議是使用一個binder_transaction_data
結構體來描述的, 因此 Binder 驅動程序在向目標線程thread
發送BR_TRANSACTION
返回協議之前, 需要定義一個binder_transaction_data
結構體tr
, 同時將其保存在binder_transaction
結構體t
中.
因爲 binder_transaction
結構體 t
的內核緩衝區 buffer
的成員變量 target_node
指向了引用 SM 的 Binder 實體對象 binder_context_mgr_node
, 因此代碼 02 處直接命中 if
.
在代碼 03 與 04 處將 binder_transaction
結構體 t
裏面的目標 Binder 本地對象信息 copy 到 binder_transaction_data
結構體 tr
中. 以便目標線程thread
接收到 Binder 驅動程序給他發送的 BR_TRANSACTION
返回協議後, 可以將返回協議交給指定的 Binder 本地對象來處理. 接着設置返回命令協議爲 BR_TRANSACTION
.
代碼 05 與 06 處代是將 binder_transaction
結構體 t
中的進程間數據 copy 到 binder_transaction_data
結構體 tr
中. (變量 code 與 flag 的值分別爲 ADD_SERVICE_TRANSACTION 與 TF_ACCEPT_FDS)
代碼 07 至 10 處 將 binder_transaction
結構體 t
中的數據緩衝區與偏移數組的內容 copy 到 binder_transaction_data
結構體 tr
中
Binder 驅動程序爲進程分配的內核緩衝區是用來傳輸進程間通信數據的, 即將進程間通信數據傳輸到用戶地址空間. 爲了減少一次數據 copy 操作, Binder 驅動程序分配給進程的內核緩衝區同時映射到了進程的內核地址空間和用戶地址空間. 因此代碼 09 與 10 處其實並不是真的將
binder_transaction
結構體t
中的數據緩衝區與偏移數組的內容 copy 到binder_transaction_data
結構體tr
中, 而是修改binder_transaction_data
結構體tr
中的數據緩衝區和偏移數組的地址值, 使他們指向t
中的數據緩衝區與偏移數組.
代碼 11 處將 binder_work
結構體 w
從目標線程 thread
或者目標進程的 todo
隊列中刪除, 因爲它所描述的工作項已經得到處理了.
代碼 12 處將 binder_transaction
結構體 t
的成員變量 allow_user_free
設置爲 1 .表示 Binder 驅動程序爲它分配的內核緩衝區允許目標線程 thread
或者目標進程在用戶空間中發出 BC_FREE_BUFFER
命令協議來釋放.
代碼 13 處判斷當前 Binder 驅動程序向目標線程或者進程發送的是一個 BR_TRANSACTION
返回協議, 並且 binder_transaction
結構體 t
的成員變量 flags
的 TF_ONE_WAY
位等於 0. 那麼命中 if
, 說明 Binder 驅動程序正在請求目標線程或者進程執行一個同步的進程間通信請求. 接着在 if
內 就將 binder_transaction
接頭體 t
壓入到目標線程或者進程的事務堆棧 transaction_stack
中, 以便 Binder 驅動程序以後可以從目標線程所屬進程的 Binder 線程池中選擇一個最優的空閒 Binder 線程來處理其他的進程間通信請求.
這裏時候的目標線程 thread 或者進程, 指的是 SM進程.
至此 SM 進程在 Binder 驅動程序的函數 binder_thread_read
中被喚醒, 並且返回到用戶空間之後, 就會調用 SM 進程中的函數 biner_parse
來處理從 Binder 驅動程序接收到的返回協議. 即返回到 Android Service Manager 的啓動流程 中第8步中的 16 行代碼處.
36. binder_parse. 返回到 ServiceManager 處理 Binder 驅動程序的返回協議
源碼路徑: /frameworks/native/cmds/servicemanager/binder.c
int binder_parse(struct binder_state *bs, struct binder_io *bio, uintptr_t ptr, size_t size, binder_handler func)
{
...
while (ptr < end) {
01 uint32_t cmd = *(uint32_t *) ptr;
...
switch(cmd) {
...
case BR_TRANSACTION: {
02 struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
...
binder_dump_txn(txn);
if (func) {
unsigned rdata[256/4];
03 struct binder_io msg;
04 struct binder_io reply;
int res;
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
05 res = func(bs, txn, &msg, &reply);
06 binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
ptr += sizeof(*txn);
break;
}
...
}
}
return r;
}
按照目前流程, 只需要關心它處理 BR_TRANSACTION
返回協議的過程.
代碼 01 處從緩衝區 ptr
讀出 BR_TRANSACTION
返回協議代碼之後, 在代碼 02 處將返回協議的內容讀取到一個 binder_transaction_data
結構體 txn
中.
接着在代碼 03 與 04 處定義了兩個 binder_io
結構體 msg
與 reply
. 其中 msg
用來解析從 Binder 驅動程序讀取回來的進程間通信數據, 而 reply
用來將進程間通信結果數據保存到緩衝區 rdata
中, 以便後面可以將它返回給 Binder 驅動程序. 它們分別使用 bio_init
和 bio_init_from_txn
來初始化.
代碼 05處調用函數 func
來處理保存在 binder_io
結構體 msg
中的 BR_TRANSACTION
返回協議, 並將處理結果保存至 binder_io
結構體 reply
中.
最終在代碼 06 處調用函數 binder_send_reply
將進程間通信結果, 即 binder_io
結構體 reply
返回給 Binder
驅動程序.
那麼接下來還是分兩步來分析, 第一先看 func
是如何處理返回協議的. 第二再看 binder_send_reply
如何將進程間通信結果返回的.
在 Android Service Manager 的啓動流程 中第8步中調用
binder_parse
時傳入的參數func
有解釋, 它指向 SM 中的函數svcmgr_handler
, 它是用來處理 Service 組件和 Client 組件進程間通信請求的.
現在進入到 svcmgr_handler
37. svcmgr_handler. 處理 BR_TRANSACTION 返回協議
源碼路徑: /frameworks/native/cmds/servicemanager/service_manager.c
int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)
{
...
switch(txn->code) {
...
case SVC_MGR_ADD_SERVICE:
01 s = bio_get_string16(msg, &len);
...
02 handle = bio_get_ref(msg);
...
03 if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, txn->sender_pid))
return -1;
break;
...
}
bio_put_uint32(reply, 0);
return 0;
}
由於 AMS 進程請求 SM 執行的操作是註冊 Service 組件 AMS, 對應的操作代碼爲 SVC_MGR_ADD_SERVICE
. 因此接下來只需要分析 case SVC_MGR_ADD_SERVICE:
的情況.
代碼 01 處從 binder_io
結構體 msg
的數據緩衝區中取出要註冊的 Service 組件的名稱.
代碼 02 處調用函數 bio_get_ref
從 binder_io
結構體 msg
的數據緩衝區中獲得一個 Binder 引用對象的句柄值, 這個 Binder 引用對象是在 Binder 驅動程序中創建的. 它引用了即將要註冊的 Servie 組件.
獲得了用來描述即將要註冊的 Service 組件的一個句柄值 handle
之後, 在代碼 03 處就調用函數 do_add_service
將這個 Service 組件註冊到 SM 中.
38. do_add_service 註冊 AMS 到 SM 中.
源碼路徑: /frameworks/native/cmds/servicemanager/service_manager.c
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, pid_t spid)
{
...
01 if (!svc_can_register(s, len, spid, uid)) {
...
}
02 si = find_svc(s, len);
03 if (si) {
...
} else {
04 si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
...
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->next = svclist;
05 svclist = si;
}
...
}
參數 s
表示要註冊的 Service 組件的名稱.
參數 uid
表示請求 SM 註冊 Service 組件的進程的用戶 ID ,
代碼 01 處調用函數 svc_can_register
來檢查是否有權限請求 SM 註冊一個名稱爲 s
的 Service 組件.
如果沒有直接返回錯誤.
將 Service 組件註冊到 SM 是一種特權, 不是所有的進程都可以將 Service 組件註冊到 SM 中. SM 中定義了一個全局的
allwoed
, 它定義了那些進程可以註冊什麼名稱的 Service 組件.
通過了權限檢查後, 在代碼 02 處調用 find_svc
函數來檢查服務名稱是否已經被註冊了. 目前流程走到這裏, AMS 還未被註冊. 所以命中 else
, 從代碼 04 處至代碼 05 處之間, 就會創建一個 svcinfo
結構體來描述要註冊的 Service 組件. 並且將它添加到全局隊列 svclist
中.
至此一個AMS 進程就成的註冊到 SM 中了. 接着返回到 37 步 04 處代碼, 調用 bio_put_uint32
函數將註冊成功代碼 0 寫入到 binder_io
結構體 reply
中. 以便後面可以將它返回給請求註冊 Service 組件的過程.
int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)
{
...
switch(txn->code) {
...
case SVC_MGR_ADD_SERVICE:
01 s = bio_get_string16(msg, &len);
...
02 handle = bio_get_ref(msg);
...
03 if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, txn->sender_pid))
return -1;
break;
...
}
04 bio_put_uint32(reply, 0);
return 0;
}
OK, 繼續向上返回, 返回到第 36 步中的代碼 06 處. 代碼如下
int binder_parse(struct binder_state *bs, struct binder_io *bio, uintptr_t ptr, size_t size, binder_handler func)
{
...
while (ptr < end) {
01 uint32_t cmd = *(uint32_t *) ptr;
...
05 res = func(bs, txn, &msg, &reply);
06 binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
ptr += sizeof(*txn);
break;
}
...
}
}
return r;
}
SM 成功的將一個 Service 組件註冊到內部的 Service 組件列表 svclist
之後, 就會調用代碼 06 處的 binder_send_reply
函數將 Service 組件註冊結果返回給 Binder 驅動程序. Binder 驅動程序再將結果返回給請求註冊 Service 組件的進程.
39. binder_send_reply SM 將 AMS 的註冊結果返回給 Binder 驅動程序.
源碼路徑: /frameworks/native/cmds/servicemanager/binder.c
void binder_send_reply(struct binder_state *bs, struct binder_io *reply, binder_uintptr_t buffer_to_free, int status)
{
...
01 data.cmd_free = BC_FREE_BUFFER;
02 data.buffer = buffer_to_free;
03 data.cmd_reply = BC_REPLY;
data.txn.target.ptr = 0;
data.txn.cookie = 0;
data.txn.code = 0;
04 if (status) {
...
} else {
data.txn.flags = 0;
data.txn.data_size = reply->data - reply->data0;
data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
05 }
06 binder_write(bs, &data, sizeof(data));
}
參數 reply
指向了一個 binder_io
結構體, 內部包含了進程間通信結果數據.
參數 buffer_to_free
是一個用戶空間地址, 指向了一塊用來傳輸進程間通信數據的內核緩衝區.
參數 status
用來描述 SM 是否成功的處理了一個進程間通信請求. 即是否成功的註冊了一個 Service 組件.
BC_FREE_BUFFER
後面跟的通信數據是一個內核緩衝區的用戶空間地址.
BC_REPLY
後面跟的通信數據是一個binder_transaction_data
結構體.
代碼 01 處與 02 處設置匿名結構體 data
中的 BC_FREE_BUFFER
命令協議內容.
代碼 03 處到 05 處都是設置 BC_REPLY
命令協議內容.
代碼 04 處是判斷 SM 在處理一個進程間通信請求發生了錯誤. 即 if
語句爲 true
. 這種情況下, SM 需要將該錯誤代碼通過 BC_REPLY
命令協議返回給 Binder 驅動程序, 以便 Binder 驅動程序可以繼續將它返回給發出該進程通信請求的 Client 進程. 按以上流程執行到這裏是爲 false
的. 所以分析 else
中內容.
命中 else
說明 SM 成功的處理了一個進程間通信請求, 這種情況下, 進程間通信結果就保存在 binder_io
結構體 reply
中. 因此 else
中就將 binder_io
結構體 reply
的數據緩衝區和偏移數組設置到匿名結構體 data
中. 以便可以通過 BC_REPLY
命令協議返回給 Binder 驅動程序. Binder 驅動程序再將它們返回給發出該進程間通信請求的 Client 進程.
最後在代碼 06 處 調用函數 binder_write
將匿名結構體 data
中的 BC_FREE_BUFFER
與 BC_REPLY
命令協議發送給 Binder 驅動程序.
40. binder_write將 BC_FREE_BUFFER 與 BC_REPLY 命令協議發送給 Binder 驅動程序
源碼路徑: /frameworks/native/cmds/servicemanager/binder.c
int binder_write(struct binder_state *bs, void *data, size_t len)
{
01 struct binder_write_read bwr;
int res;
bwr.write_size = len;
bwr.write_consumed = 0;
02 bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
return res;
}
函數 binder_write
是通過 IO 控制命令 BINDER_WRITE_READ
來將 BC_FREE_BUFFER
與 BC_REPLY
命令協議發送給 Binder 驅動程序的. 所以在代碼 01 處定義了一個 binder_write_read
結構體 bwr
.
在代碼 02 處將 binder_write_read
結構體 bwr
的輸入緩衝區 write_buffer
設置爲由參數 data
所描述的一塊用戶緩衝區. 參數 data
所描述的一塊用戶空間緩衝區包含了一個 BC_FREE_BUFFER
和 BC_REPLY
命令協議.
binder_write_read
結構體bwr
的輸入緩衝區read_buffer
及其長度都被設置爲 0. 因此, 當 SM 通過 IO 控制命令BINDER_WRITE_READ
進入到 Binder 驅動程序時, Binder 驅動程序調用函數binder_thread_write
處理完成binder_write_read
結構體bwr
的輸出緩衝區中的BC_FREE_BUFFER
和BC_REPLY
命令協議之後, 就會馬上返回到 SM 的用戶空間.
接着分析在 Binder 驅動程序處理 BC_FREE_BUFFER
與 BC_REPLY
命令協議的過程.
BC_FREE_BUFFER
命令協議是在函數 binder_thread_write
中處理的.
41. binder_thread_write 處理 BC_FREE_BUFFER 與 BC_REPLY 命令協議
源碼路徑: kernel 3.18下的 /drivers/staging/android/binder.c
static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed)
{
...
while (ptr < end && thread->return_error == BR_OK) {
...
switch (cmd) {
...
case BC_FREE_BUFFER: {
...
01 if (get_user(data_ptr, (binder_uintptr_t __user *)ptr))
...
02 buffer = binder_buffer_lookup(proc, data_ptr);
...
03 binder_transaction_buffer_release(proc, buffer, NULL);
04 binder_free_buf(proc, buffer);
break;
}
case BC_TRANSACTION:
case BC_REPLY: {
...
05 binder_transaction(proc, thread, &tr,cmd == BC_REPLY, 0);
break;
}
...
return 0;
}
代碼 01 處獲得要釋放的內核緩衝區的用戶空間地址. 保存在變量 data_ptr
中.
代碼 02 處調用函數 binder_buffer_lookup
在進程 proc
中找到與用戶空間地址 data_ptr
對應的內核緩衝區 buffer
.
代碼 03與 04 處分別是調用函數 binder_transaction_buffer_release
與 binder_free_buf
來減少 Binder 實體對象或者 Binder 引用對象的引用計數與釋放內核緩衝區 buffer
.
接着是在代碼 05 處調用 binder_transaction
處理 BC_REPLY
命令協議.
42. binder_transaction
源碼路徑: kernel 3.18下的 /drivers/staging/android/binder.c
在上一章的第 30 步, 分析了 binder_transaction
處理 BC_TRANSACTION
命令協議, 其中參數 reply
是 false
, 現在分析的是它處理 BC_REPLY
協議的過程, 參數 reply
值爲 true
. 不要混亂了.
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size)
{
...
if (reply) {
01 in_reply_to = thread->transaction_stack;
...
...
02 thread->transaction_stack = in_reply_to->to_parent;
target_thread = in_reply_to->from;
...
target_proc = target_thread->proc;
} else {
...
}
...
03 if (reply) {
...
04 binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
...
} else {
...
}
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
if (target_wait)
05 wake_up_interruptible(target_wait);
return;
...
}
從上面調用可知傳進來的 reply
值爲 true
.所以命中 if
.
在第一個
if
內就來找到之前請求與 SM 進行進程間通信的線程 即 AMS, 找到了這個目標線程target_thread
之後, Binder 驅動程序就可以向它發出一個BC_REPLY
返回協議, 以便將進程間通信的結果返回給它
當 Binder 驅動程序分發一個進程間通信請求給一個線程處理時, 會將一個 binder_transaction
結構體壓入到它的事務堆棧中, 因此代碼 01 處從就從線程 thread
的事務堆棧中將該 binder_transaction
結構體取出來, 保存在變量 in_reply_to
中.
binder_transaction
結構體in_reply_to
的成員變量from
指向了之前請求與線程thread
進程進程間通信的線程, 因此, 後面就可以通過來獲得目標線程target_thread
, 那麼此時的 目標線程target_thread
是誰? 是 AMS, 因爲在 SM 中完成了註冊, 就需要通過 Binder 驅動程序將結果返回給 AMS. 需要處理的是類型爲BINDER_WORK_TRANSACTION
的工作項.
binder_transaction
結構體 in_reply_to
中的成員變量 to_parent
指向了用來處理它的線程 thread
的下一個需要處理的事務. 因此代碼 02 處就將這個事務放在線程 thread
的事務堆棧 transaction_stack
的頂端, 表示線程 thread
接下來要處理它.
代碼 04處調用函數 binder_pop_transaction
從目標線程 target_thead
的事務堆棧中刪除 binder_transaction
結構體 in_reply_to
, 因爲它所描述的一個事務已經處理完成了, 因此目標線程 target_thead
就不需要再保存它了.
剩下的就是和第 30步差不多了, 封裝工作項, 添加到 todo
隊列等. 那麼此時 AMS 與 SM 要處理的工作項類型如下
- ActivityManagerServie 要處理的工作項類型爲
BINDER_WORK_TRANSACTION
. - ServiceManager 要處理的工作項類型爲
BINDER_WORK_TRANSACTION_COMPLETE
.
那麼接下來就又是併發的去處理各自 todo
隊列中的工作項. 我們假設先處理的還是 AMS 中的工作項. 在本章第 34步 IPCThreadState.waitForResponse
函數中 AMS 在 binder_thread_read
中休眠等待進程間通信的結果. 那麼我們依然還是從 AMS 這裏開始. 在代碼 05 處喚醒 AMS. (上一章第 30 步喚醒的是 SM)
未完待續...