日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

红茶一杯话Binder(传输机制篇_下)

發(fā)布時(shí)間:2025/3/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 红茶一杯话Binder(传输机制篇_下) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 事務(wù)的傳遞和處理

??????? 從IPCThreadState的角度看,它的transact()函數(shù)是通過(guò)向binder驅(qū)動(dòng)發(fā)出BC_TRANSACTION語(yǔ)義,來(lái)表達(dá)其傳輸意圖的,而后如有必要,它會(huì)等待從binder發(fā)回的回饋,這些回饋語(yǔ)義常常以“BR_”開(kāi)頭。另一方面,當(dāng)IPCThreadState作為處理命令的一方需要向發(fā)起方反饋信息的話,它會(huì)調(diào)用sendReply()函數(shù),向binder驅(qū)動(dòng)發(fā)出BC_REPLY語(yǔ)義。當(dāng)BC_語(yǔ)義經(jīng)由binder驅(qū)動(dòng)遞送到目標(biāo)端時(shí),會(huì)被binder驅(qū)動(dòng)自動(dòng)修改為相應(yīng)的BR_語(yǔ)義,這個(gè)我們?cè)诤笪脑偌?xì)說(shuō)。

??????? 當(dāng)語(yǔ)義傳遞到binder驅(qū)動(dòng)后,會(huì)走到binder_ioctl()函數(shù),該函數(shù)又會(huì)調(diào)用到binder_thread_write()和binder_thread_read():

??????? 在上一篇文章中,我們大體闡述了一下binder_thread_write()和binder_thread_read()的喚醒與被喚醒關(guān)系,而且還順帶在“傳輸機(jī)制的大體運(yùn)作”小節(jié)中提到了todo隊(duì)列的概念。本文將在此基礎(chǔ)上再補(bǔ)充一些知識(shí)。需要強(qiáng)調(diào)的是,我們必須重視binder_thread_write()和binder_thread_read(),因?yàn)槭聞?wù)的傳遞和處理就位于這兩個(gè)函數(shù)中,它們的調(diào)用示意圖如下:

??????? binder_thread_write()的代碼截選如下。因?yàn)楸疚闹饕P(guān)心傳輸方面的問(wèn)題,所以只摘取了case BC_TRANSACTION、case BC_REPLY部分的代碼:

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,void __user *buffer, int size, signed long *consumed) {. . . . . .while (ptr < end && thread->return_error == BR_OK){. . . . . .switch (cmd){. . . . . .. . . . . .case BC_TRANSACTION:case BC_REPLY: {struct binder_transaction_data tr;if (copy_from_user(&tr, ptr, sizeof(tr)))return -EFAULT;ptr += sizeof(tr);binder_transaction(proc, thread, &tr, cmd == BC_REPLY);break;}. . . . . .. . . . . .}*consumed = ptr - buffer;}return 0; }

這部分代碼比較簡(jiǎn)單,主要是從用戶態(tài)拷貝來(lái)binder_transaction_data數(shù)據(jù),并傳給binder_transaction()函數(shù)進(jìn)行實(shí)際的傳輸。而binder_transaction()可是需要我們費(fèi)一點(diǎn)兒力氣去分析的,大家深吸一口氣,準(zhǔn)備開(kāi)始。

?

1.1 BC_TRANSACTION事務(wù)(攜帶TF_ONE_WAY標(biāo)記)的處理

??????? 首先我們要認(rèn)識(shí)到,同樣是BC_TRANSACTION事務(wù),帶不帶TF_ONE_WAY標(biāo)記還是有所不同的。我們先看相對(duì)簡(jiǎn)單的攜帶TF_ONE_WAY標(biāo)記的BC_TRANSACTION事務(wù),這種事務(wù)是不需要回復(fù)的。

1.1.1 binder_transaction()

??????? 此時(shí),binder_transaction()所做的工作大概有:

  • 找目標(biāo)binder_node;
  • 找目標(biāo)binder_proc;
  • 分析并插入紅黑樹(shù)節(jié)點(diǎn);(我們?cè)谏弦黄恼轮幸言谡f(shuō)過(guò)這部分的機(jī)理了,只是當(dāng)時(shí)沒(méi)有貼出相應(yīng)的代碼)
  • 創(chuàng)建binder_transaction節(jié)點(diǎn),并將其插入目標(biāo)進(jìn)程的todo列表;
  • 嘗試喚醒目標(biāo)進(jìn)程。
  • ??????? binder_transaction()代碼截選如下:

    static void binder_transaction(struct binder_proc *proc,struct binder_thread *thread,struct binder_transaction_data *tr, int reply) {struct binder_transaction *t;. . . . . .struct binder_proc *target_proc;struct binder_thread *target_thread = NULL;struct binder_node *target_node = NULL;struct list_head *target_list;wait_queue_head_t *target_wait;. . . . . .. . . . . .{// 先從tr->target.handle句柄值,找到對(duì)應(yīng)的binder_ref節(jié)點(diǎn),及binder_node節(jié)點(diǎn)if (tr->target.handle){struct binder_ref *ref;ref = binder_get_ref(proc, tr->target.handle);. . . . . .target_node = ref->node;}else{// 如果句柄值為0,則獲取特殊的binder_context_mgr_node節(jié)點(diǎn),// 即Service Manager Service對(duì)應(yīng)的節(jié)點(diǎn)target_node = binder_context_mgr_node;. . . . . .}// 得到目標(biāo)進(jìn)程的binder_proctarget_proc = target_node->proc;. . . . . .}// 對(duì)于帶TF_ONE_WAY標(biāo)記的BC_TRANSACTION來(lái)說(shuō),此時(shí)target_thread為NULL,// 所以準(zhǔn)備向binder_proc的todo中加節(jié)點(diǎn). . . . . .target_list = &target_proc->todo;target_wait = &target_proc->wait;. . . . . .// 創(chuàng)建新的binder_transaction節(jié)點(diǎn)。t = kzalloc(sizeof(*t), GFP_KERNEL);. . . . . .t->from = NULL;t->sender_euid = proc->tsk->cred->euid;t->to_proc = target_proc;t->to_thread = target_thread;// 將binder_transaction_data的code、flags域記入binder_transaction節(jié)點(diǎn)。t->code = tr->code;t->flags = tr->flags;t->priority = task_nice(current);t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size,!reply && (t->flags & TF_ONE_WAY));. . . . . .t->buffer->transaction = t;t->buffer->target_node = target_node;. . . . . .// 下面的代碼分析所傳數(shù)據(jù)中的所有binder對(duì)象,如果是binder實(shí)體的話,要在紅黑樹(shù)中添加相應(yīng)的節(jié)點(diǎn)。// 首先,從用戶態(tài)獲取所傳輸?shù)臄?shù)據(jù),以及數(shù)據(jù)里的binder對(duì)象的偏移信息offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)). . . . . .if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)). . . . . .. . . . . .// 遍歷每個(gè)flat_binder_object信息,創(chuàng)建必要的紅黑樹(shù)節(jié)點(diǎn) ....for (; offp < off_end; offp++){struct flat_binder_object *fp;. . . . . .fp = (struct flat_binder_object *)(t->buffer->data + *offp);switch (fp->type){case BINDER_TYPE_BINDER:case BINDER_TYPE_WEAK_BINDER:{// 如果是binder實(shí)體struct binder_ref *ref;struct binder_node *node = binder_get_node(proc, fp->binder);if (node == NULL){// 又是“沒(méi)有則創(chuàng)建”的做法,創(chuàng)建新的binder_node節(jié)點(diǎn)node = binder_new_node(proc, fp->binder, fp->cookie);. . . . . .}. . . . . .// 必要時(shí),會(huì)在目標(biāo)進(jìn)程的binder_proc中創(chuàng)建對(duì)應(yīng)的binder_ref紅黑樹(shù)節(jié)點(diǎn)ref = binder_get_ref_for_node(target_proc, node);. . . . . .// 修改所傳數(shù)據(jù)中的flat_binder_object信息,因?yàn)檫h(yuǎn)端的binder實(shí)體到了目標(biāo)// 端,就變?yōu)閎inder代理了,所以要記錄下binder句柄了。fp->handle = ref->desc;. . . . . .} break;case BINDER_TYPE_HANDLE:case BINDER_TYPE_WEAK_HANDLE: {struct binder_ref *ref = binder_get_ref(proc, fp->handle);// 有時(shí)候需要對(duì)flat_binder_object做必要的修改,比如將BINDER_TYPE_HANDLE// 改為BINDER_TYPE_BINDER. . . . . .} break;case BINDER_TYPE_FD: {. . . . . .} break;. . . . . .}. . . . . .{. . . . . .if (target_node->has_async_transaction){target_list = &target_node->async_todo;target_wait = NULL;}elsetarget_node->has_async_transaction = 1;}t->work.type = BINDER_WORK_TRANSACTION;// 終于把binder_transaction節(jié)點(diǎn)插入target_list(即目標(biāo)todo隊(duì)列)了。list_add_tail(&t->work.entry, target_list);. . . . . .list_add_tail(&tcomplete->entry, &thread->todo);// 傳輸動(dòng)作完畢,現(xiàn)在可以喚醒系統(tǒng)中其他相關(guān)線程了,wake up!if (target_wait)wake_up_interruptible(target_wait);return;. . . . . .. . . . . . }

    ?

    ??????? 雖然已經(jīng)是截選,代碼卻仍然顯得冗長(zhǎng)。這也沒(méi)辦法,Android frameworks里的很多代碼都是這個(gè)樣子,又臭又長(zhǎng),大家湊合著看吧。我常常覺(jué)得google的工程師多少應(yīng)該因這樣的代碼而感到臉紅,不過(guò),哎,這有點(diǎn)兒說(shuō)遠(yuǎn)了。

    我們畫(huà)一張示意圖,如下:

    上圖體現(xiàn)了從binder_ref找到“目標(biāo)binder_node”以及“目標(biāo)binder_proc”的意思,其中“A端”表示發(fā)起方,“B端”表示目標(biāo)方。可以看到,攜帶TF_ONE_WAY標(biāo)記的事務(wù),其實(shí)是比較簡(jiǎn)單的,驅(qū)動(dòng)甚至不必費(fèi)心去找目標(biāo)線程,只需要?jiǎng)?chuàng)建一個(gè)binder_transaction節(jié)點(diǎn),并插入目標(biāo)binder_proc的todo鏈表即可。

    ??????? 另外,在將binder_transaction節(jié)點(diǎn)插入目標(biāo)todo鏈表之前,binder_transaction()函數(shù)用一個(gè)for循環(huán)分析了需要傳輸?shù)臄?shù)據(jù),并為其中包含的binder對(duì)象生成了相應(yīng)的紅黑樹(shù)節(jié)點(diǎn)。

    ??????? 再后來(lái),binder_transaction節(jié)點(diǎn)成功插入目標(biāo)todo鏈表,此時(shí)說(shuō)明目標(biāo)進(jìn)程有事情可做了,于是binder_transaction()函數(shù)會(huì)調(diào)用wake_up_interruptible()喚醒目標(biāo)進(jìn)程。

    ?

    1.1.2 binder_thread_read()

    ??????? 當(dāng)目標(biāo)進(jìn)程被喚醒時(shí),會(huì)接著執(zhí)行自己的binder_thread_read(),嘗試解析并執(zhí)行那些剛收來(lái)的工作。無(wú)論收來(lái)的工作來(lái)自于“binder_proc的todo鏈表”,還是來(lái)自于某“binder_thread的todo鏈表”,現(xiàn)在要開(kāi)始從todo鏈表中摘節(jié)點(diǎn)了,而且在完成工作之后,會(huì)徹底刪除binder_transaction節(jié)點(diǎn)。

    ???????? binder_thread_read()的代碼截選如下:

    static int binder_thread_read(struct binder_proc *proc,struct binder_thread *thread,void __user *buffer, int size,signed long *consumed, int non_block) {. . . . . . retry:// 優(yōu)先考慮thread節(jié)點(diǎn)的todo鏈表中有沒(méi)有工作需要完成wait_for_proc_work = thread->transaction_stack == NULL&& list_empty(&thread->todo);. . . . . .. . . . . .if (wait_for_proc_work){. . . . . .ret = wait_event_interruptible_exclusive(proc->wait,binder_has_proc_work(proc, thread));}else{. . . . . .ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));}. . . . . .thread->looper &= ~BINDER_LOOPER_STATE_WAITING;// 如果是非阻塞的情況,ret值非0表示出了問(wèn)題,所以return。 // 如果是阻塞(non_block)情況,ret值非0表示等到的結(jié)果出了問(wèn)題,所以也return。if (ret)return ret; while (1){. . . . . .// 讀取binder_thread或binder_proc中todo列表的第一個(gè)節(jié)點(diǎn)if (!list_empty(&thread->todo))w = list_first_entry(&thread->todo, struct binder_work, entry);else if (!list_empty(&proc->todo) && wait_for_proc_work)w = list_first_entry(&proc->todo, struct binder_work, entry);. . . . . . switch (w->type){case BINDER_WORK_TRANSACTION: {t = container_of(w, struct binder_transaction, work);} break;case BINDER_WORK_TRANSACTION_COMPLETE: {cmd = BR_TRANSACTION_COMPLETE;. . . . . .// 將binder_transaction節(jié)點(diǎn)從todo隊(duì)列摘下來(lái)list_del(&w->entry);kfree(w);binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);} break;. . . . . .. . . . . . }if (!t)continue;. . . . . .if (t->buffer->target_node) {struct binder_node *target_node = t->buffer->target_node;tr.target.ptr = target_node->ptr;// 用目標(biāo)binder_node中記錄的cookie值給binder_transaction_data的cookie域賦值,// 這個(gè)值就是目標(biāo)binder實(shí)體的地址tr.cookie = target_node->cookie; t->saved_priority = task_nice(current);. . . . . .cmd = BR_TRANSACTION;}. . . . . .tr.code = t->code;tr.flags = t->flags;tr.sender_euid = t->sender_euid;. . . . . .tr.data_size = t->buffer->data_size;tr.offsets_size = t->buffer->offsets_size;// binder_transaction_data中的data只是記錄了binder緩沖區(qū)中的地址信息,并再做copy動(dòng)作tr.data.ptr.buffer = (void *)t->buffer->data +proc->user_buffer_offset;tr.data.ptr.offsets = tr.data.ptr.buffer +ALIGN(t->buffer->data_size,sizeof(void *));// 將cmd命令寫(xiě)入用戶態(tài),此時(shí)應(yīng)該是BR_TRANSACTIONif (put_user(cmd, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);// 當(dāng)然,binder_transaction_data本身也是要copy到用戶態(tài)的if (copy_to_user(ptr, &tr, sizeof(tr)))return -EFAULT;. . . . . .. . . . . . // 將binder_transaction節(jié)點(diǎn)從todo隊(duì)列摘下來(lái)list_del(&t->work.entry); t->buffer->allow_user_free = 1;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;// TF_ONE_WAY情況,此時(shí)會(huì)刪除binder_transaction節(jié)點(diǎn)kfree(t);binder_stats_deleted(BINDER_STAT_TRANSACTION);}break;}. . . . . .. . . . . .return 0; }

    簡(jiǎn)單說(shuō)來(lái)就是,如果沒(méi)有工作需要做,binder_thread_read()函數(shù)就進(jìn)入睡眠或返回,否則binder_thread_read()函數(shù)會(huì)從todo隊(duì)列摘下了一個(gè)節(jié)點(diǎn),并把節(jié)點(diǎn)里的數(shù)據(jù)整理成一個(gè)binder_transaction_data結(jié)構(gòu),然后通過(guò)copy_to_user()把該結(jié)構(gòu)傳到用戶態(tài)。因?yàn)檫@次傳輸帶有TF_ONE_WAY標(biāo)記,所以copy完后,只是簡(jiǎn)單地調(diào)用kfree(t)把這個(gè)binder_transaction節(jié)點(diǎn)干掉了。

    ???????? binder_thread_read()嘗試調(diào)用wait_event_interruptible()或wait_event_interruptible_exclusive()來(lái)等待待處理的工作。wait_event_interruptible()是個(gè)宏定義,和wait_event()類(lèi)似,不同之處在于前者不但會(huì)判斷“蘇醒條件”,還會(huì)判斷當(dāng)前進(jìn)程是否帶有掛起的系統(tǒng)信號(hào),當(dāng)“蘇醒條件”滿足時(shí)(比如binder_has_thread_work(thread)返回非0值),或者有掛起的系統(tǒng)信號(hào)時(shí),表示進(jìn)程有工作要做了,此時(shí)wait_event_interruptible()將跳出內(nèi)部的for循環(huán)。如果的確不滿足跳出條件的話,wait_event_interruptible()會(huì)進(jìn)入掛起狀態(tài)。

    ??????? 請(qǐng)注意給binder_transaction_data的cookie賦值的那句:

    tr.cookie = target_node->cookie;

    binder_node節(jié)點(diǎn)里儲(chǔ)存的cookie值終于發(fā)揮作用了,這個(gè)值反饋到用戶態(tài)就是目標(biāo)binder實(shí)體的BBinder指針了。

    ??????? 另外,在調(diào)用copy_to_user()之前,binder_thread_read()先通過(guò)put_user()向上層拷貝了一個(gè)命令碼,在當(dāng)前的情況下,這個(gè)命令碼是BR_TRANSACTION。想當(dāng)初,內(nèi)核態(tài)剛剛從用戶態(tài)拷貝來(lái)的命令碼是BC_TRANSACTION,現(xiàn)在要發(fā)給目標(biāo)端了,就變成了BR_TRANSACTION。

    ?

    1.2 BC_TRANSACTION事務(wù)(不帶TF_ONE_WAY標(biāo)記)

    1.2.1 再說(shuō)binder_transaction()

    ??????? 然而,對(duì)于不帶TF_ONE_WAY標(biāo)記的BC_TRANSACTION事務(wù)來(lái)說(shuō),情況就沒(méi)那么簡(jiǎn)單了。因?yàn)閎inder驅(qū)動(dòng)不僅要找到目標(biāo)進(jìn)程,而且還必須努力找到一個(gè)明確的目標(biāo)線程。正如我們前文所說(shuō),binder驅(qū)動(dòng)希望可以充分復(fù)用目標(biāo)進(jìn)程中的binder工作線程。

    ??????? 那么,哪些線程(節(jié)點(diǎn))是可以被復(fù)用的呢?我們?cè)僬硪幌耣inder_transaction()代碼,本次主要截選不帶TF_ONE_WAY標(biāo)記的代碼部分:

    static void binder_transaction(struct binder_proc *proc,struct binder_thread *thread,struct binder_transaction_data *tr, int reply) {struct binder_transaction *t;. . . . . .. . . . . . if (tr->target.handle){. . . . . .target_node = ref->node;}else{target_node = binder_context_mgr_node;. . . . . .}. . . . . .// 先確定target_proctarget_proc = target_node->proc;. . . . . . if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack){ struct binder_transaction *tmp;tmp = thread->transaction_stack;. . . . . .// 找到from_parent這條鏈表中,最后一個(gè)可以和target_proc匹配 // 的binder_transaction節(jié)點(diǎn),// 這個(gè)節(jié)點(diǎn)的from就是我們要找的“目標(biāo)線程” while (tmp){ if (tmp->from && tmp->from->proc == target_proc)target_thread = tmp->from;tmp = tmp->from_parent;}}. . . . . .// 要確定target_list和target_wait了,如果能找到“目標(biāo)線程”,它們就來(lái)自目標(biāo)線程,否則// 就只能來(lái)自目標(biāo)進(jìn)程了。if (target_thread){e->to_thread = target_thread->pid;target_list = &target_thread->todo;target_wait = &target_thread->wait;}else {target_list = &target_proc->todo;target_wait = &target_proc->wait;}. . . . . .// 創(chuàng)建新的binder_transaction節(jié)點(diǎn)。t = kzalloc(sizeof(*t), GFP_KERNEL);. . . . . .. . . . . .t->from = thread; // 新節(jié)點(diǎn)的from域記錄事務(wù)的發(fā)起線程t->sender_euid = proc->tsk->cred->euid;t->to_proc = target_proc;t->to_thread = target_thread; // 新節(jié)點(diǎn)的to_thread域記錄事務(wù)的目標(biāo)線程t->code = tr->code;t->flags = tr->flags;t->priority = task_nice(current);// 從binder buffer中申請(qǐng)一個(gè)區(qū)域,用于存儲(chǔ)待傳輸?shù)臄?shù)據(jù)t->buffer = binder_alloc_buf(target_proc, tr->data_size,tr->offsets_size,!reply && (t->flags & TF_ONE_WAY));. . . . . .t->buffer->transaction = t;t->buffer->target_node = target_node;. . . . . .// 從用戶態(tài)拷貝來(lái)待傳輸?shù)臄?shù)據(jù)if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {. . . . . .}if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {. . . . . .}// 遍歷每個(gè)flat_binder_object信息,創(chuàng)建必要的紅黑樹(shù)節(jié)點(diǎn) ....for (; offp < off_end; offp++){struct flat_binder_object *fp;. . . . . .. . . . . .}. . . . . .t->need_reply = 1;// 新binder_transaction節(jié)點(diǎn)成為發(fā)起端transaction_stack棧的新棧頂t->from_parent = thread->transaction_stack;thread->transaction_stack = t;. . . . . .t->work.type = BINDER_WORK_TRANSACTION;// 終于把binder_transaction節(jié)點(diǎn)插入target_list(即目標(biāo)todo隊(duì)列)了。list_add_tail(&t->work.entry, target_list);tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;list_add_tail(&tcomplete->entry, &thread->todo);if (target_wait)wake_up_interruptible(target_wait);return;. . . . . .. . . . . . }

    其中,獲取目標(biāo)binder_proc的部分和前一小節(jié)沒(méi)什么不同,但是因?yàn)楸敬蝹鬏敳辉贁y帶TF_ONE_WAY標(biāo)記了,所以函數(shù)中會(huì)盡力去查一個(gè)合適的“目標(biāo)binder_thread”,此時(shí)會(huì)用到binder_thread里的“事務(wù)棧”(transaction_stack)概念。

    ???????? 那么,怎么找“目標(biāo)binder_thread”呢?首先,我們很清楚“發(fā)起端”的binder_thread節(jié)點(diǎn)是哪個(gè),而且也可以找到“目標(biāo)端”的binder_proc,這就具有了搜索的基礎(chǔ)。在binder_thread節(jié)點(diǎn)的transaction_stack域里,記錄了和它相關(guān)的若干binder_transaction,這些binder_transaction事務(wù)在邏輯上具有類(lèi)似堆棧的屬性,也就是說(shuō)“最后入棧的事務(wù)”會(huì)最先處理。

    從邏輯上說(shuō),線程節(jié)點(diǎn)的transaction_stack域體現(xiàn)了兩個(gè)方面的意義:

  • 這個(gè)線程需要?jiǎng)e的線程幫它做某項(xiàng)工作;
  • 別的線程需要這個(gè)線程做某項(xiàng)工作;
  • 因此,一個(gè)工作節(jié)點(diǎn)(即binder_transaction節(jié)點(diǎn))往往會(huì)插入兩個(gè)transaction_stack堆棧,示意圖如下:

    當(dāng)binder_transaction節(jié)點(diǎn)插入“發(fā)起端”的transaction_stack棧時(shí),它是用from_parent域來(lái)連接堆棧中其他節(jié)點(diǎn)的。而當(dāng)該節(jié)點(diǎn)插入“目標(biāo)端”的transaction_stack棧時(shí),卻是用to_parent域來(lái)連接其他節(jié)點(diǎn)的。關(guān)于插入目標(biāo)端堆棧的動(dòng)作,位于binder_thread_read()中,我們?cè)诤笪臅?huì)看到。

    ??????? 這么看來(lái),from_parent域其實(shí)將一系列邏輯上有先后關(guān)系的若干binder_transaction節(jié)點(diǎn)串接起來(lái)了,而且這些binder_transaction節(jié)點(diǎn)可能是由不同進(jìn)程、線程發(fā)起的。那么我們只需遍歷一下這個(gè)堆棧里的事務(wù),看哪個(gè)事務(wù)的“from線程所屬的進(jìn)程”和“目標(biāo)端的binder_proc”一致,就說(shuō)明這個(gè)from線程正是我們要找的目標(biāo)線程。為什么這么說(shuō)呢?這是因?yàn)槲覀兊男率聞?wù)將成為binder_transaction的新棧頂,而這個(gè)堆棧里其他事務(wù)一定是在新棧頂事務(wù)處理完后才會(huì)處理的,因此堆棧里某個(gè)事務(wù)的發(fā)起端線程可以理解為正處于等待狀態(tài),如果這個(gè)發(fā)起端線程所從屬的進(jìn)程恰恰又是我們新事務(wù)的目標(biāo)進(jìn)程的話,那就算合拍了,這樣就找到“目標(biāo)binder_thread”了。我把相關(guān)的代碼再抄一遍:

    struct binder_transaction *tmp; tmp = thread->transaction_stack;while (tmp) {if (tmp->from && tmp->from->proc == target_proc)target_thread = tmp->from;tmp = tmp->from_parent; }

    代碼用while循環(huán)來(lái)遍歷thread->transaction_stack,發(fā)現(xiàn)tmp->from->proc == target_proc,就算找到了。

    ??????? 如果能夠找到“目標(biāo)binder_thread”的話,binder_transaction事務(wù)就會(huì)插到它的todo隊(duì)列去。不過(guò)有時(shí)候找不到“目標(biāo)binder_thread”,那么就只好退而求其次,插入binder_proc的todo隊(duì)列了。再接下來(lái)的動(dòng)作沒(méi)有什么新花樣,大體上會(huì)嘗試喚醒目標(biāo)進(jìn)程。

    ?

    1.2.2 再說(shuō)binder_thread_read()

    ??????? 目標(biāo)進(jìn)程在喚醒后,會(huì)接著當(dāng)初阻塞的地方繼續(xù)執(zhí)行,這個(gè)已在前一小節(jié)闡述過(guò),我們不再贅述。值得一提的是binder_thread_read()中的以下句子:

    // 將binder_transaction節(jié)點(diǎn)從todo隊(duì)列摘下來(lái)list_del(&t->work.entry); t->buffer->allow_user_free = 1;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;// TF_ONE_WAY情況,此時(shí)會(huì)刪除binder_transaction節(jié)點(diǎn)kfree(t);binder_stats_deleted(BINDER_STAT_TRANSACTION);}

    因?yàn)闆](méi)有攜帶TF_ONE_WAY標(biāo)記,所以此處會(huì)有一個(gè)入棧操作,binder_transaction節(jié)點(diǎn)插入了目標(biāo)線程的transaction_stack堆棧,而且是以to_thread域來(lái)連接堆棧中的其他節(jié)點(diǎn)的。

    ?

    ??????? 總體說(shuō)來(lái),binder_thread_read()的動(dòng)作大體也就是:

    1) 利用wait_event_xxxx()讓自己掛起,等待下一次被喚醒;?
    2) 喚醒后找到合適的待處理的工作節(jié)點(diǎn),即binder_transaction節(jié)點(diǎn);?
    3) 把binder_transaction中的信息整理到一個(gè)binder_transaction_data中;?
    4) 整理一個(gè)cmd整數(shù)值,具體數(shù)值或者為BR_TRANSACTION,或者為BR_REPLY;?
    5) 將cmd數(shù)值和binder_transaction_data拷貝到用戶態(tài);?
    6) 如有必要,將得到的binder_transaction節(jié)點(diǎn)插入目標(biāo)端線程的transaction_stack堆棧中。

    ?

    1.2.3 目標(biāo)端如何處理傳來(lái)的事務(wù)

    ??????? binder_thread_read()本身只負(fù)責(zé)讀取數(shù)據(jù),它并不解析得到的語(yǔ)義。具體解析語(yǔ)義的動(dòng)作并不在內(nèi)核態(tài),而是在用戶態(tài)。

    ??????? 我們?cè)倩氐接脩魬B(tài)的IPCThreadState::waitForResponse()函數(shù)。

    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) {while (1){// talkWithDriver()內(nèi)部會(huì)完成跨進(jìn)程事務(wù)if ((err = talkWithDriver()) < NO_ERROR)break;// 事務(wù)的回復(fù)信息被記錄在mIn中,所以需要進(jìn)一步分析這個(gè)回復(fù). . . . . .cmd = mIn.readInt32();. . . . . .err = executeCommand(cmd);. . . . . .}. . . . . . }

    當(dāng)發(fā)起端調(diào)用binder_thread_write()喚醒目標(biāo)端的進(jìn)程時(shí),目標(biāo)進(jìn)程會(huì)從其上次調(diào)用binder_thread_read()的地方蘇醒過(guò)來(lái)。輾轉(zhuǎn)跳出上面的talkWithDriver()函數(shù),并走到executeCommand()一句。

    ??????? 因?yàn)閎inder_thread_read()中已經(jīng)把BR_命令整理好了,所以executeCommand()當(dāng)然會(huì)走到case BR_TRANSACTION分支:

    status_t IPCThreadState::executeCommand(int32_t cmd) {BBinder* obj;RefBase::weakref_type* refs;. . . . . .. . . . . .case BR_TRANSACTION:{binder_transaction_data tr;result = mIn.read(&tr, sizeof(tr));. . . . . .mCallingPid = tr.sender_pid;mCallingUid = tr.sender_euid;mOrigCallingUid = tr.sender_euid;. . . . . .Parcel reply;. . . . . .if (tr.target.ptr) {sp<BBinder> b((BBinder*)tr.cookie);const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);if (error < NO_ERROR) reply.setError(error);} else {const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);if (error < NO_ERROR) reply.setError(error);}. . . . . .if ((tr.flags & TF_ONE_WAY) == 0){LOG_ONEWAY("Sending reply to %d!", mCallingPid);sendReply(reply, 0);}. . . . . .. . . . . .}break;. . . . . .. . . . . .return result; }

    ??????? 最關(guān)鍵的一句當(dāng)然是b->transact()啦,此時(shí)b的值來(lái)自于binder_transaction_data的cookie域,本質(zhì)上等于驅(qū)動(dòng)層所記錄的binder_node節(jié)點(diǎn)的cookie域值,這個(gè)值在用戶態(tài)就是BBinder指針。

    ??????? 在調(diào)用完transact()動(dòng)作后,executeCommand()會(huì)判斷tr.flags有沒(méi)有攜帶TF_ONE_WAY標(biāo)記,如果沒(méi)有攜帶,說(shuō)明這次傳輸是需要回復(fù)的,于是調(diào)用sendReply()進(jìn)行回復(fù)。

    ?

    2 小結(jié)

    ??????? 至此,《紅茶一杯話Binder(傳輸機(jī)制篇)》的上、中、下三篇文章總算寫(xiě)完了。限于個(gè)人水平,文中難免有很多細(xì)節(jié)交代不清,還請(qǐng)各位看官海涵。作為我個(gè)人而言,只是盡力嘗試把一些底層機(jī)制說(shuō)得清楚一點(diǎn)兒,奈何Android內(nèi)部的代碼細(xì)節(jié)繁雜,邏輯交疊,往往搞得人頭昏腦漲,所以我也只是針對(duì)其中很小的一部分進(jìn)行闡述而已。因?yàn)楸救四壳暗闹饕d趣已經(jīng)不在binder了,所以這篇文章耽誤了好久才寫(xiě)完,呵呵,見(jiàn)諒見(jiàn)諒。

    原文地址:?https://my.oschina.net/youranhongcha/blog/167314

    與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

    總結(jié)

    以上是生活随笔為你收集整理的红茶一杯话Binder(传输机制篇_下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 九九热在线观看 | 亚洲五月婷婷 | 毛片官网 | 大陆极品少妇内射aaaaaa | 好吊妞视频这里只有精品 | 日韩中文字幕亚洲 | 秋霞欧美一区二区三区视频免费 | www.爆操 | 国产内射一区二区 | 国产在线xx | 天天色天天 | 日本人妻熟妇久久久久久 | 日本女人黄色片 | 国产精品激情 | 狠狠一区二区 | 午夜色影院| 夜夜看av | 国产欧美日韩精品在线 | 色图视频 | 一区二区三区国 | 日韩精品一区二区三区国语自制 | 最新中文字幕在线视频 | 日本少妇色 | 日韩三级在线 | 99久久人妻无码中文字幕系列 | 性欧美大战久久久久久久免费观看 | 欧美久久精品一级黑人c片 1000部多毛熟女毛茸茸 | 红桃视频一区二区三区免费 | 性毛片 | 日本一本高清 | 亚洲欧美日韩系列 | 中文字幕在线高清 | 佐佐木明希av在线 | 日韩毛片网站 | 色综合九九 | 黄色美女免费网站 | 完全免费在线视频 | 免费黄色国产 | av网站免费在线 | 郑艳丽三级 | www超碰| 伊人91| 国产片一区二区三区 | 日韩欧美不卡视频 | 国产人妻人伦精品1国产盗摄 | 97国产精品人人爽人人做 | 国产裸体永久免费视频网站 | 91婷婷色| www.伊人网| 麻豆黄色一级片 | 天天爱夜夜爱 | 国产日韩一级 | 国内自拍偷拍网 | 欧美日韩三级在线观看 | 色老汉视频 | 亚洲精品国产精品乱码不卡 | 小黄网站在线观看 | 乳罩脱了喂男人吃奶视频 | 中文字幕超清在线免费观看 | 欧美大片一区二区 | 三女警花合力承欢猎艳都市h | 成人污视频 | 黄页网站在线播放 | 成品短视频泡芙 | 欧美大片91 | 光明影院手机版在线观看免费 | 色偷偷成人 | 岛国av噜噜噜久久久狠狠av | 自拍偷拍小视频 | 中文字幕高清视频 | 97超碰碰碰 | 久久久999久久久 | 麻豆一区二区在线观看 | 2019国产在线 | jizzjizz日本免费视频 | www插插插无码免费视频网站 | 久久你懂的 | av丝袜在线| 电影一区二区三区 | 亚洲精品电影网 | 女人囗交吞精囗述 | 美女国产网站 | 人成在线视频 | av免费毛片 | 在线一区av| 精品少妇视频 | 亚洲第一综合 | 福利视频99| 一本加勒比hezyo黑人 | 免费在线成人 | 水蜜桃91| 可以看的av网址 | 特级西西人体 | 天天摸天天操天天干 | 成人有色视频 | 色七七网站 | 亚洲天堂麻豆 | 秋霞福利片 | 操人视频免费看 |