Binder機制情景分析之transaction_stack

一. 概述

這裏以註冊服務爲例,當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信息;
②: 記錄下要目標進程信息和線程信息;

這裏tstruct 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_tofrom的信息;

上面那部ServiceManager進程已經知道此時要發送給誰,到此該問題就完美解答了;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章