Android ActivityManagerService 註冊到 Service Manager 的流程(中)

接上一章.

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 函數來處理源線程 threadtodo 隊列中類型爲 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 處判斷線程 threadtodo隊列不爲 NULL, 這裏命中 if, 取出線程 threadtodo隊列中類型爲 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處再檢查它所屬進程 proctodo 隊列中是否有工作項需要處理. 只要兩個中的任何一個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 的成員變量 flagsTF_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 結構體 msgreply. 其中 msg 用來解析從 Binder 驅動程序讀取回來的進程間通信數據, 而 reply 用來將進程間通信結果數據保存到緩衝區 rdata 中, 以便後面可以將它返回給 Binder 驅動程序. 它們分別使用 bio_initbio_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_refbinder_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_BUFFERBC_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_BUFFERBC_REPLY 命令協議發送給 Binder 驅動程序的. 所以在代碼 01 處定義了一個 binder_write_read 結構體 bwr.

在代碼 02 處將 binder_write_read 結構體 bwr 的輸入緩衝區 write_buffer 設置爲由參數 data 所描述的一塊用戶緩衝區. 參數 data 所描述的一塊用戶空間緩衝區包含了一個 BC_FREE_BUFFERBC_REPLY 命令協議.

binder_write_read 結構體 bwr 的輸入緩衝區 read_buffer 及其長度都被設置爲 0. 因此, 當 SM 通過 IO 控制命令 BINDER_WRITE_READ 進入到 Binder 驅動程序時, Binder 驅動程序調用函數 binder_thread_write 處理完成 binder_write_read 結構體 bwr 的輸出緩衝區中的 BC_FREE_BUFFERBC_REPLY 命令協議之後, 就會馬上返回到 SM 的用戶空間.

接着分析在 Binder 驅動程序處理 BC_FREE_BUFFERBC_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_releasebinder_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 命令協議, 其中參數 replyfalse, 現在分析的是它處理 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)

未完待續...

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