---
# System prepended metadata

title: Binder - Native SeriveManager
tags: [Binder, Android 系統]

---

---
title: 'Binder - Native SeriveManager'
disqus: kyleAlien
---

Binder - Native SeriveManager
===

## OverView of Content

ServiceManager 啟動是 [**Android 啟動**](https://hackmd.io/pJpAeKAeRea0VIW3oI-mXw?view) 的一部分

[TOC]

## SeriveManager 啟動
簡單來說就是 啟動 init 進程，init 進程分析 init.rc 檔案，並啟動新進程
> ![](https://i.imgur.com/ro5JE0V.png)

* 從 [**init.rc**](https://android.googlesource.com/platform/system/core/+/master/rootdir/init.rc#448) 的 `on init` (action) 可以看到它最後啟動了 ServiceManager 服務進程，而啟動 ServiceManager 會先啟動到 [**servicemanager.rc**](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/servicemanager.rc) (真正啟動服務)

    ```shell=
    # /rootdir/init.rc 檔案

    on init
        ...    
        # Start essential services.    # essential 基礎
        start servicemanager    # 啟動 srvicemanager.rc
        start hwservicemanager
        start vndservicemanager
    
    # -----------------------------------------------------------------------

    # /cmds/servicemanager/servicemanager.rc
    # service 格式：service <name> <pathname>
    
    service servicemanager /system/bin/servicemanager    # 啟動 servicemanager
        class core animation        # 所屬的 class 為 animation
        user system    # 以用戶 sustem 的身份運行
        group system readproc
        
        critical    # 若失敗 4 次則進入恢復模式
        
        # 若重新啟動則需要 重起以下服務 （onrestart）
        onrestart restart apexd    
        onrestart restart audioserver
        onrestart restart gatekeeperd
        onrestart class_restart main
        onrestart class_restart hal
        onrestart class_restart early_hal
        
        writepid /dev/cpuset/system-background/tasks
        shutdown critical
    ```

* init 進程分析完 `servicemanager.rc` 後，才會啟動 ServiceManager 的 [**Android.bp**](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/Android.bp) 檔案
    :::info
    * Android 最新的啟動由 Android.mk 檔案，改成 **Android.bp** 檔案
    :::
    ```shell=
    ## /servicemanager/Android.bp
    
    cc_defaults {
        name: "servicemanager_defaults",
        cflags: [
            "-Wall",
            "-Wextra",
            "-Werror",
            "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
        ],
        srcs: [
            "Access.cpp",
            "ServiceManager.cpp",    // 啟動檔案
        ],
        shared_libs: [
            "libbase",
            "libbinder",     // 依賴 binder 動態檔案
            "libvintf",
            "libcutils",
            "liblog",
            "libutils",
            "libselinux",
        ],
        target: {
            vendor: {
                exclude_shared_libs: ["libvintf"],
            },
        },
    }
    
    ## 依賴 lib        
    ## 重點啟動 servicemanager#main
    cc_binary {
        name: "servicemanager",
        defaults: ["servicemanager_defaults"],    // 預設啟動配置
        init_rc: ["servicemanager.rc"],
        srcs: ["main.cpp"],
    }
    
    
    ... 省略部份
    ```

* 透過上面 `Android.dp` 檔案，可以知道它將會啟動 `servicemanager#main.cpp` 檔案

### [ServiceManager](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/main.cpp) - main 函數

* `servicemanager#main` 函數：先來了解一下使用到的重要類、還有其方法

    | 類 | 重點函數 | 功能 |
    | -------- | -------- | -------- |
    | ProcessState | initWithDriver | 開啟 `/dev/binder` 裝置 |
    | ProcessState | becomeContextManager | 將當前進程設定為 Binder 管理者 |
    | Looper | prepare | 準備 Looper，並設定可接受 callback |
    | Looper | pollAll | 等待客戶請求 |
    
    1. **`ProcessState::initWithDriver` 函數**：初始化，開啟指定設備（預設為 `/dev/binder` 裝置），映射到自身 (ServiceManager) 進程
        ```cpp=
        // /servicemanager/main.cpp

        int main(int argc, char** argv) {
            ...

            // 判斷輸入參數，不可大於 2 個
            if (argc > 2) {
                LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
            }

            // 目標開啟文件，預設為 "/dev/binder"
            const char* driver = argc == 2 ? argv[1] : "/dev/binder";

            // ProcessState 為進程單例
            // @ initWithDriver
            sp<ProcessState> ps = ProcessState::initWithDriver(driver);
            ...
            return EXIT_FAILURE;
        }
        ```
    2. ProcessState (也就是 ServiceManager) 設定最大 Thread 數量為 0、並 **將自身設定為 "manager" 並註冊到列表中**
        
        ```cpp=
        // /servicemanager/main.cpp

        int main(int argc, char** argv) {
            ... 開啟 /dev/binder

            // 設定 Binder thread 上限為 0
            ps->setThreadPoolMaxThreadCount(0);
            ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

            // 創建 ServiceManager 實例
            sp<ServiceManager> manager = 
                sp<ServiceManager>::make(std::make_unique<Access>());

            if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
                LOG(ERROR) << "Could not self register servicemanager";
            }

            ...

            return EXIT_FAILURE;
        }
        ```
    3. 將自身設定為 Binder 管理者
        ```cpp=
        // /servicemanager/main.cpp

        int main(int argc, char** argv) {
            ...

            // 設定 ServiceManager 處理 Binder 訊息
            IPCThreadState::self()->setTheContextObject(manager);

            // @becomeContextManager 將當前進程設定為 Binder 管理者
            ps->becomeContextManager();

            ...

            return EXIT_FAILURE;
        }
        ```
        
    4. 啟動 Looper，開始監聽 Binder 事件
        ```cpp=
        // /servicemanager/main.cpp

        int main(int argc, char** argv) {
            ...

            // 啟動 Looper
            sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
            BinderCallback::setupTo(looper);
            ClientCallbackCallback::setupTo(looper, manager);

            // Looper 進入循環監聽
            while(true) {
                looper->pollAll(-1);
            }

            return EXIT_FAILURE;
        }
        ```
    
### [**binder_open**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c) - 開啟 binder 文件

*  [**ProcessState**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/ProcessState.cpp)::**initWithDriver**：開啟目標文件，若是沒指定則開啟 `/dev/binder` 文件
    ```cpp=
    // ProcessState.cpp

    // 傳入 driver 為 "/dev/binder"
    sp<ProcessState> ProcessState::initWithDriver(const char* driver)
    {
        return init(driver, true /*requireDefault*/);
    }

    sp<ProcessState> ProcessState::init(const char *driver, 
                                        bool requireDefault)
    {
    #ifdef BINDER_IPC_32BIT
        log... 當前啟動方式不適用 32 bit 裝置

    #endif
        if (driver == nullptr) {
            std::lock_guard<std::mutex> l(gProcessMutex);
            if (gProcess) {
                verifyNotForked(gProcess->mForked);
            }
            return gProcess;
        }

        // 單例呼叫
        [[clang::no_destroy]] static std::once_flag gProcessOnce;
        std::call_once(gProcessOnce, [&](){
            // 嘗試訪問目標裝置
            if (access(driver, R_OK) == -1) {
                ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
                // 如果訪問失敗，則轉為 預設 /dev/binder
                driver = "/dev/binder";
            }
            
            // 在實例化 ProcessState 之前先進行一些處理
            int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
                                     ProcessState::childPostFork);
            
            ... log 訊息
            
            std::lock_guard<std::mutex> l(gProcessMutex);
            gProcess = sp<ProcessState>::make(driver);
        });
        
        ... log 訊息
        
        verifyNotForked(gProcess->mForked);
        return gProcess;
    }
    ```
    
* ProcessState 初始化 (建構函數) 請參考 [**ProcessState**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#%E9%80%B2%E7%A8%8B%E5%96%AE%E4%BE%8B-ProcessState)，這邊大概說明一下
    1. ProcessState 透過 open 開啟 `/dev/binder` 裝置 (或指定裝置)
    2. 再透過 mmap 讓當前進程映射 binder 裝置 （下一小結說明）
        
* ProcessState#open 函數會呼叫到通過 systemcall 調用到 Kernel 空間的 [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c)#**binder_open 函數**

    | 類 | 運行空間 | 對應函數 |
    | -------- | -------- | -------- |
    | ProcessState.cpp | User space | open |
    | binder.c | Kernel space | binder_open |

    :::success
    * Kernel open 請參考 [**binder_open**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#ProcessState---open-%E9%96%8B%E5%95%9F-Binder) 分析
    :::
         
### [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c) - mmap 映射

* [**ProcessState**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/ProcessState.cpp) 建構函數會呼叫 [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c)#**mmap 函數** 開啟內存映射

    | 類 | 運行空間 | 函數 |
    | -------- | -------- | -------- |
    | ProcessState.cpp | User space | mmap |
    | binder.c | Kernel space | binder_mmap |

    ```cpp=
    // ProcessState.cpp

    ProcessState::ProcessState(const char* driver)
          : mDriverName(String8(driver)),
            mDriverFD(-1),
            mVMStart(MAP_FAILED),
            mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
            mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
            /* 省略部份*/) {

        // 開啟 /dev/binder 裝置
        base::Result<int> opened = open_driver(driver);

        if (opened.ok()) {
            // mmap binder，提供一塊虛擬地址空間來接收事務
            // 取得 mmap 後進程的虛擬地址
            mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
                            opened.value(), 0);
            if (mVMStart == MAP_FAILED) {
                ... 省略失敗處理
            }
        }

        ...

        if (opened.ok()) {
            // 儲存 Binder 驅動偏移量
            mDriverFD = opened.value();
        }
    }
    ```
    
    :::success
    * Kernel mmap 請參考 [**binder_mmap**](https://hackmd.io/8E1AyMAgRzym3g6ktNV37Q?view#binder_mmap-%E6%A6%82%E8%BF%B0) 分析
    :::

### [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c) - ioctl binder 通訊（BINDER_SET_CONTEXT_MGR）

:::info
ServiceManager 透過 `becomeContextManager` 將自身設定為 Binder 驅動管理者，在這之中就要傳送 `BINDER_SET_CONTEXT_MGR` 命令
:::
```c=
// binder.h

#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
```

* [**ProcessState**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/ProcessState.cpp)::**becomeContextManager**：主要是 **透過 ioctl 函數發送**`BINDER_SET_CONTEXT_MGR` Binder 命令，將自身設定為 Binder 管理者
    ```cpp=
    // ProcessState.cpp

    bool ProcessState::becomeContextManager()
    {
        AutoMutex _l(mLock);

        flat_binder_object obj {
            .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
        };

        // mDriverFD 是 '/dev/binder' 的偏移量 (在 open 時就儲存)

        // 1. 首先嘗試設定 安全傳輸
        int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);

        // fallback to original method
        if (result != 0) {

            // 失敗則使用 default 0
            int unused = 0;
            // 透過 @ ioctl 傳輸 BINDER_SET_CONTEXT_MGR 命令給 Binder
            result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &unused);
        }

        ... 省略失敗處理

        return result == 0;
    }
    ```

* ProcessState::`becomeContextManager` 最終會呼叫 [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c)#**`ioctl` 函數** 開始與 Binder kernel 通訊（對應函數是 `binder_ioctl`）

    | 類 | 運行空間 | 函數 |
    | -------- | -------- | -------- |
    | ProcessState.cpp | User space | ioctl |
    | binder.c | Kernel space | binder_ioctl |



* **binder_ioctl** 函數分析 ServiceManager 設定為 Binder 管理者
    > ![](https://i.imgur.com/tawSKgY.png)

    1. 取出 App 進程的 **binder_proc** 變量 (proc 就是進程資訊)，接著計算指令大小 (**透過 \_IOC_SIZE 宏**)

        :::info
        * binder_proc 在 Native 層表現就是 **ProcessState.cpp**
        :::
        ```c=
        // /drivers/staging/android/binder.c

        static long binder_ioctl(struct file *filp, 
                                 unsigned int cmd, 
                                 long arg)
        {
            int ret;
            
            // 從 filp 中抽取 proc 變量，也就是 binder_open 中創建的實例
            // private_data 的類型就是 binder_proc（進程資訊）
            struct binder_proc *proc = filp->private_data;    // ServiceManager 在 Kernel 的表示方式
            
            struct binder_thread *thread;

            // 命令大小
            unsigned int size = _IOC_SIZE(cmd);
            void __user *ubuf = (void __user *)arg;

            ...
            return ret;
        }
        ```

    2. **堵塞操作**：判斷當前進程是否需要掛起（`wait_event_interruptible` 函數決定），當前情況來說並不會掛起（binder_stop_on_user_error < 2 成立）
        ```c=
        // /drivers/staging/android/binder.c

        static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        {
            int ret;
            struct binder_proc *proc = filp->private_data;
            struct binder_thread *thread;
            unsigned int size = _IOC_SIZE(cmd);
            void __user *ubuf = (void __user *)arg;
            
            ...

            // wait_event_interruptible 掛起調用者進程
            // 滿足 binder_stop_on_user_error < 2 就不會將該進程掛起
            ret = wait_event_interruptible(binder_user_error_wait, 
                binder_stop_on_user_error < 2);
                
            if (ret)
                goto err_unlocked;
            
            ...
        err_unlocked:
            trace_binder_ioctl_done(ret);
            return ret;
        }
        ```

    3. **查看 proc 中的 threads 的鏈表是否添加了當前線程的節點**，若是沒有則創建 & 插入一個 thread 節點
        :::info
        proc 中的 threads 鏈表是 **按照 pid 大小做排序的**
        :::
        > 如果無法取得 binder_thread 它也會幫你創建一個 binder_thread
        ```c=
        // /drivers/staging/android/binder.c

        static int binder_stop_on_user_error;

        static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        {
            int ret;
            struct binder_proc *proc = filp->private_data;
            struct binder_thread *thread;
            unsigned int size = _IOC_SIZE(cmd);
            void __user *ubuf = (void __user *)arg;
            ...

            binder_lock(__func__);
            
            // 取得呼叫者的線程
            thread = binder_get_thread(proc);
            // 查看最終結果是否失敗
            if (thread == NULL) {
                ret = -ENOMEM;
                goto err;
            }
            
            ...
            
            ret = 0;
        err:
            if (thread)
                thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
            binder_unlock(__func__);
            wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
            if (ret && ret != -ERESTARTSYS)
                pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
                
            ...
            return ret;
        }
        ```
    4. **處理具體命令**：目前要把 ServiceManager 設定為 Binder 管理者，所以 **傳入的命令是 `BINDER_SET_CONTEXT_MGR_EXT` 命令**
        
        :::success
        讀取使用者空間的資料後會轉換為 `flat_binder_object` 結構，其中就儲存了
        
        * cookie：BinderServer 虛擬空間的地址
        * BinderServer 的弱計數 `weakref_type` 地址
        :::
        
        ```c=
        // /drivers/staging/android/binder.c

        static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        {
            int ret;
            // 自身進程核心 (proc) 的空間
            struct binder_proc *proc = filp->private_data;
            struct binder_thread *thread;
            unsigned int size = _IOC_SIZE(cmd);
            void __user *ubuf = (void __user *)arg;    // User space 的資料
            
            ...
    
            switch (cmd) {
                case BINDER_SET_CONTEXT_MGR_EXT: {
                    struct flat_binder_object fbo;
                    
                    // 把 User space 資料複製到 Kernel space
                    if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {    // ubuf 中的資料複製到 fbo 結構中
                        ret = -EINVAL;
                        goto err;
                    }
                    // @ 追蹤 binder_ioctl_set_ctx_mgr
                    ret = binder_ioctl_set_ctx_mgr(filp, &fbo);
                    if (ret)
                        goto err;
                    break;
                }
            ... 
            return ret;
        }
        ```
    
    5. 將當前 uid 設定給 servicemanager 進程（如果已經被設定過，則會判斷 uid 是否相同），並創建一個 **++binder node 節點 串接到 Kernel space 的紅黑數中++**

        :::warning
        裝置只允許有一個 BinderManager
        :::
        ```c=
        // binder.c
            
        static int binder_ioctl_set_ctx_mgr(struct file *filp,
				    struct flat_binder_object *fbo)
        {
            int ret = 0;    // 0 為成功
            
            // 從 Binder 文件取回進程資料
            struct binder_proc *proc = filp->private_data;
            struct binder_context *context = proc->context;
            struct binder_node *new_node;
            kuid_t curr_euid = current_euid();

            // 互斥鎖
            mutex_lock(&context->context_mgr_node_lock);
            if (context->binder_context_mgr_node) {
                pr_err("BINDER_SET_CONTEXT_MGR already set\n");
                ret = -EBUSY;
                goto out;
            }
            
            // 將當前進程 (service manager) 設定為 
            ret = security_binder_set_context_mgr(proc->cred);
            
            if (ret < 0)
                goto out;
            
            // 判斷 service manager uid
            if (uid_valid(context->binder_context_mgr_uid)) {
                // curr_euid 是當前進程的 uid
                if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
                    ... 省略錯誤訊息
                        
                    ret = -EPERM;
                    goto out;
                }
            } else {
                // 將 servicemanager uid 設定為當前 uid
                context->binder_context_mgr_uid = curr_euid;
            }
            
            // 創建一個 binder 節點 （fbo 是 flat_binder_object）
            // @ 追蹤 binder_new_node 方法
            new_node = binder_new_node(proc, fbo);
            if (!new_node) {
                ret = -ENOMEM;
                goto out;
            }
            // 安全鎖
            binder_node_lock(new_node);
            // 增加本地強弱計數、指針引用
            new_node->local_weak_refs++;
            new_node->local_strong_refs++;
            new_node->has_strong_ref = 1;
            new_node->has_weak_ref = 1;
            // 將新節點設定為 binder manager
            context->binder_context_mgr_node = new_node;
            binder_node_unlock(new_node);
            binder_put_node(new_node);
        out:
            // 解除互斥鎖
            mutex_unlock(&context->context_mgr_node_lock);
            return ret;
        }
        ```
    6. `binder_new_node` 函數：在 Kernal space 開闢一個新的 `binder_node` 區塊，並將 `flat_binder_object` 加入到 proc 的紅黑樹上

        :::success
        * 首先檢查 (透過 ptr，也就是 BBinder 的若參考計數當地址) 當前 proc 內是否有相對應的 binder_node，沒有的話則創建
        :::
        ```c=
        // binder.c

        static struct binder_node *binder_new_node(struct binder_proc *proc,
                               struct flat_binder_object *fp)
        {
            // 創建一個 binder_node 空間
            struct binder_node *node;
            struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL);

            if (!new_node)
                return NULL;
            binder_inner_proc_lock(proc);

            // @ 追蹤 binder_init_node_ilocked 函數
            node = binder_init_node_ilocked(proc, new_node, fp);

            binder_inner_proc_unlock(proc);
            if (node != new_node)
                /*
                 * binder_node 已經被其他 thread 添加
                 */
                kfree(new_node);

            return node;
        }

        static struct binder_node *binder_init_node_ilocked(
                                struct binder_proc *proc,
                                struct binder_node *new_node,
                                struct flat_binder_object *fp)
        {
            struct rb_node **p = &proc->nodes.rb_node;
            struct rb_node *parent = NULL;
            struct binder_node *node;

            binder_uintptr_t ptr = fp ? fp->binder : 0;
            binder_uintptr_t cookie = fp ? fp->cookie : 0;
            __u32 flags = fp ? fp->flags : 0;

            s8 priority;

            assert_spin_locked(&proc->inner_lock);

            // 找到紅黑樹可以插入的點
            while (*p) {

                parent = *p;
                node = rb_entry(parent, struct binder_node, rb_node);

                if (ptr < node->ptr)
                    p = &(*p)->rb_left;
                else if (ptr > node->ptr)
                    p = &(*p)->rb_right;
                else {
                    /*
                     * A matching node is already in
                     * the rb tree. Abandon the init
                     * and return it.
                     */
                    binder_inc_node_tmpref_ilocked(node);
                    return node;
                }
            }
            node = new_node;
            binder_stats_created(BINDER_STAT_NODE);
            node->tmp_refs++;
            rb_link_node(&node->rb_node, parent, p);
            rb_insert_color(&node->rb_node, &proc->nodes);

            ... 省略部份

            return node;
        }
        ```



## [ServiceManager](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/main.cpp) 進入循環 - [Looper](https://android.googlesource.com/platform/system/core/+/master/libutils/Looper.cpp)

* 在上面已經分析 Binder 的啟動（open）、開啟 Binder 對應用進程的映射（mmap）、並對 Binder 傳送命令將 ServiceManager 設定為 Binder 管理者（ioctl）

    現在是進入 Loop 循環等待使用者的請求
    ```cpp=
    // /servicemanager/main.cpp

    int main(int argc, char** argv) {

        ... 省略部份

        // 1-1. 啟動 Looper
        sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
        
        // 1-2. 設定 callback
        BinderCallback::setupTo(looper);    // 會透過 IPCThreadState 進入 Binder 循環
        ClientCallbackCallback::setupTo(looper, manager);

        // Looper 進入循環監聽
        while(true) {
            // 2. 讀取 Binder 驅動
            looper->pollAll(-1);
        }

        return EXIT_FAILURE;
    }
    ```

### [**Looper**](https://cs.android.com/android/platform/superproject/+/master:system/core/libutils/Looper.cpp) 啟動循環 - 設定 Callback
1. 使用 [**Looper**](https://android.googlesource.com/platform/system/core/+/master/libutils/Looper.cpp)#prepare 函數創建 Looper 對象

    ```cpp=
    // Looper.cpp

    sp<Looper> Looper::prepare(int opts) {
        bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
        sp<Looper> looper = Looper::getForThread();

        if (looper == nullptr) {
            // 目前 allowNonCallbacks 是 false
            looper = new Looper(allowNonCallbacks);
            Looper::setForThread(looper);
        }

        ... log 訊息

        return looper;
    }
    ```

2. 設定 Looper 的 Callback
    * `setupTo` 函數：設定 Looper 的 fd，讓 Looper 拉取指定檔案 FD 的訊息 (目前就是 `/dev/binder`)

    * `handleEvent` 函數：未來接收到 Looper 訊息時，由 BinderCallback 接手處理

        ```cpp=
        // /cmds/servicemanager/main.cpp

        class BinderCallback : public LooperCallback {
        public:
            static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
                sp<BinderCallback> cb = sp<BinderCallback>::make();
                int binder_fd = -1;

                // 將 binder_fd 丟入
                // @ 之後分析 setupPolling
                IPCThreadState::self()->setupPolling(&binder_fd);

                ... log 訊息

                // 讓該 looper 對指定的 FD 觀察 
                int ret = looper->addFd(binder_fd,
                                        Looper::POLL_CALLBACK,
                                        Looper::EVENT_INPUT,
                                        cb,
                                        nullptr /*data*/);

                ... log 訊息

                return cb;
            }

            int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
                // 由 IPCThreadState#handlePolledCommands 接手處理 BinderClient 傳入的命令
                IPCThreadState::self()->handlePolledCommands();
                return 1;  // 繼續接收
            }
        };
        ```

### [IPCThreadState](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/IPCThreadState.cpp) - 設定 Thread 為 BinderThread

:::info
目前主要處理的命令是 `ENTER_LOOPER`
:::

* Looper 在準備時，會呼叫 [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/IPCThreadState.cpp)#setupPolling 方法，並在這裡會對 Binder 傳送 `BC_ENTER_LOOPER` 命令，而 Binder 傳送命令就必須由 ioctl 函數開始

    > `BC_ENTER_LOOPER` 命令會將當前 Thread 註冊為 BinderThread

    ```cpp=
    // IPCThreadState.cpp

    status_t IPCThreadState::setupPolling(int* fd)
    {
        if (mProcess->mDriverFD < 0) {
            return -EBADF;
        }
        // 對 BinderDriver 寫入 BC_ENTER_LOOPER 命令
        mOut.writeInt32(BC_ENTER_LOOPER);
        // @ 查看 flushCommands
        flushCommands();

        // 改變 fd 數值 （/dev/binder）
        // fd 為 ServiceManager 映射 （/dev/binder） 在自身進程上的描述偏移
        *fd = mProcess->mDriverFD;
        pthread_mutex_lock(&mProcess->mThreadCountLock);
        mProcess->mCurrentThreads++;
        pthread_mutex_unlock(&mProcess->mThreadCountLock);
        return 0;
    }

    void IPCThreadState::flushCommands()
    {
        if (mProcess->mDriverFD < 0)
            return;
        // @ 追蹤 talkWithDriver 方法
        talkWithDriver(false);

        if (mOut.dataSize() > 0) {
            talkWithDriver(false);
        }
        if (mOut.dataSize() > 0) {
            ALOGW("mOut.dataSize() > 0 after flushCommands()");
        }
    }
    ```
    > ![](https://i.imgur.com/AE5UOfb.png)

* **IPCThreadState# talkWithDriver 函數**：準備要與 Binder 通訊的資料，在透過 User space 的 `ioctl` 函數呼叫到 Kernel Space 的 `binder_ioctl` 函數
    ```cpp=
    // IPCThreadState.cpp

    status_t IPCThreadState::talkWithDriver(bool doReceive)    // doReceive = true
        {
            if (mProcess->mDriverFD < 0) {
                return -EBADF;
            }

            binder_write_read bwr

            // 判斷 mIn＃position 位置 是否有移動
            // 有移動並大於 dataSize 代表有資料
            const bool needRead = mIn.dataPosition() >= mIn.dataSize();

            // 在讀取 mIn 時我們不想寫入任何 mOut 資料
            const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

            bwr.write_size = outAvail;
            bwr.write_buffer = (uintptr_t)mOut.data();    // 寫入資料

            // 目前狀況是 doReceive = true
            // 並且 needRead = true (有資料要讀取)
            if (doReceive && needRead) {
                // 要讀取的資料
                bwr.read_size = mIn.dataCapacity();
                bwr.read_buffer = (uintptr_t)mIn.data();
            } else {
                bwr.read_size = 0;
                bwr.read_buffer = 0;
            }

            ... log 訊息

            // 如果沒有任何事情要做（不須 read | write）則即時返回
            if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

            // consumed 設定為 0
            bwr.write_consumed = 0;
            bwr.read_consumed = 0;

            status_t err;
            do {
                ... log 訊息

        #if defined(__ANDROID__)
                // 呼叫 Kernel#binder_ioctl 函數
                if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
                    err = NO_ERROR;
                else
                    err = -errno;
        #else
                err = INVALID_OPERATION;

        #endif
                if (mProcess->mDriverFD < 0) {
                    err = -EBADF;
                }
                ... log 訊息

            } while (err == -EINTR);

            ... 省略 err 錯誤處理

            return err;
        }
    ```
    
* 到這個步驟（binder_ioctl）後就進入了 Kernel space (BinderDriver) 空間
    
    1. 如果沒有新的請求，就會讓當前進入 Binder 的 Thread 休眠
        
        ```cpp=
        // binder.c

        static long binder_ioctl(struct file *filp, 
                                 unsigned int cmd,     // BINDER_WRITE_READ
                                 unsigned long arg)
        {
            int ret;
            // 從 Binder 文件中取出 proc 訊息
            struct binder_proc *proc = filp->private_data;
            struct binder_thread *thread;
            unsigned int size = _IOC_SIZE(cmd);
            void __user *ubuf = (void __user *)arg;

            ... 省略部份

            ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);

        }
        ```
    2. 取得進入 Kernel space 的 proc thread，並處理 `BINDER_WRITE_READ` 命令
        ```cpp=
        // binder.c

        static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        {
            int ret;
            // 從 Binder 文件中取出 proc 訊息
            struct binder_proc *proc = filp->private_data;
            struct binder_thread *thread;
            unsigned int size = _IOC_SIZE(cmd);
            void __user *ubuf = (void __user *)arg;

            ... 省略部份

            // 取得進入 Kernel space 的 proc thread (目前來講就是 ServiceManager 的 MainThread)
            thread = binder_get_thread(proc);
            if (thread == NULL) {
                ret = -ENOMEM;
                goto err;
            };

            
            switch (cmd) {
            case BINDER_WRITE_READ:
                // @ binder_ioctl_write_read
                ret = binder_ioctl_write_read(filp, cmd, arg, thread);
                if (ret)
                    goto err;
                break;
                    
            ... 省略其他 case
            
            }
            
            ... 省略錯誤處理
    
            return ret;
        }
        ```
    3. **binder_ioctl_write_read 函數**：首先先將使用者空間數據進行拷貝 (`copy_from_user`)，再針對 read/write 呼叫不同函數處理

        | 行為 | 處理函數 |
        | -------- | -------- |
        | read | binder_thread_read |
        | write | binder_thread_write |

        ```cpp=
        // binder.c

        static int binder_ioctl_write_read(struct file *filp,
                        unsigned int cmd, unsigned long arg,
                        struct binder_thread *thread)
        {
            int ret = 0;
            struct binder_proc *proc = filp->private_data;
            unsigned int size = _IOC_SIZE(cmd);
            void __user *ubuf = (void __user *)arg;
            struct binder_write_read bwr;

            ... 省略部份

            // 將使用者空間數據 (ubuf) 複製到 bwr 結構中
            if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
                ret = -EFAULT;
                goto out;
            }

            if (bwr.write_size > 0) {
                // @ 分析 binder_thread_write
                ret = binder_thread_write(proc, thread,
                              bwr.write_buffer,    // 目前內部指令是 BC_ENTER_LOOPER
                              bwr.write_size,
                              &bwr.write_consumed);
                ... 省略錯誤處理
            }

            // 由於當前要處理 `BC_ENTER_LOOPER` 並沒有 read
            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);
                ... 省略錯誤處理
            }
            
            ... debug 訊息

            // 將內核空間數據 (bwr) 複製到使用者空間（ubuf）
            if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
                ret = -EFAULT;
                goto out;
            }
        
            out:
                return ret;
        }
        ```
    4. **binder_thread_write 函數**：處理 `BC_ENTER_LOOPER` 命令，最終會把 ServiceManager 用來跟 Binder 通訊的 **thread 設置狀態為 `BINDER_LOOPER_STATE_ENTERED`**
        ```c=
        // binder.cpp

        static int binder_thread_write(
                        struct binder_proc *proc,     
                        struct binder_thread *thread,  
                        binder_uintptr_t binder_buffer,  // bwr.write_buffer 
                        size_t size,                     // bwr.write_size
                        binder_size_t *consumed)         // bwr.write_consumed
            {
                uint32_t cmd;
                // buffer = cmd + 對應數據
                // 取得調用者的 buffer address
                void __user *buffer = (void __user *)(uintptr_t)binder_buffer;

                // 1. 設定開頭、結尾的指針
                void __user *ptr = buffer + *consumed;    // 跳過已處理過得部份，取得開始部份
                void __user *end = buffer + size;        // 指向 buffer 結尾


                while (ptr < end && thread->return_error == BR_OK) {
                    // 2. 獲取 cmd
                    // 當前 cmd 是 `BC_ENTER_LOOPER` 
                    if (get_user_preempt_disabled(cmd, (uint32_t __user *)ptr))
                        return -EFAULT;

                    // 取出指令後移動指針，讓指針移動到數據開頭    
                    ptr += sizeof(uint32_t);

                    // 3. 統計數據
                    if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
                        binder_stats.bc[_IOC_NR(cmd)]++;
                        proc->stats.bc[_IOC_NR(cmd)]++;
                        thread->stats.bc[_IOC_NR(cmd)]++;
                    }

                    // 判斷 cmd
                    switch (cmd) {
                        ... 省略部份 case

                    case BC_ENTER_LOOPER:

                        if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
                            // 已註冊
                            ... 錯誤處理
                        }
                        // 為該 Binder_thread 設定 flag
                        thread->looper |= BINDER_LOOPER_STATE_ENTERED;
                        break;
                    }

                }
            }
        ```
    > ![](https://i.imgur.com/icuCuSp.png)

### Looper 循環

* Binder 準備好後，Loop 就準備進入 while 循環，持續拉取資料處理，再有資料時調用 Callback (BinderCallback 類)，詳細請看註解說明

    ```cpp=
    // Looper.h

    // 宣告
    int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);

    // 使用內聯 pollAll
    inline int pollAll(int timeoutMillis) {
        // @ 查看 pollAll
        return pollAll(timeoutMillis, nullptr, nullptr, nullptr);
    }



    // --------------------------------------------------
    // Looper.cpp

    // 目前 timeoutMillis 傳入是 -1
    int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
        if (timeoutMillis <= 0) {
            int result;
            do {
                // @ 查看 pollOnce
                result = pollOnce(timeoutMillis, outFd, outEvents, outData);
            } while (result == POLL_CALLBACK);
            return result;

        } else {
            ... 省略
        }
    }


    int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
        int result = 0;
        for (;;) {

            ... 省略部份

            // @ 查看 pollInner 函數
            result = pollInner(timeoutMillis);
        }
    }

    int Looper::pollInner(int timeoutMillis) {
        ... 省略部份

        // Poll.
        int result = POLL_WAKE;
        mResponses.clear();
        mResponseIndex = 0;

        // We are about to idle.
        mPolling = true;

        struct epoll_event eventItems[EPOLL_MAX_EVENTS];
        int eventCount = epoll_wait(mEpollFd.get(), 
                                    eventItems, 
                                    EPOLL_MAX_EVENTS, 
                                    timeoutMillis);    // -1
        // No longer idling.
        mPolling = false;
        // Acquire lock.
        mLock.lock();

        // Rebuild epoll set if needed.
        if (mEpollRebuildRequired) {
            mEpollRebuildRequired = false;
            rebuildEpollLocked();
            goto Done;
        }

        // Check for poll error.
        if (eventCount < 0) {
            if (errno == EINTR) {
                goto Done;
            }
            ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
            result = POLL_ERROR;
            goto Done;
        }

        // Check for poll timeout.
        if (eventCount == 0) {        // 沒有任何事件
    #if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - timeout", this);
    #endif
            result = POLL_TIMEOUT;
            goto Done;
        }
        
        // 處理事件
        for (int i = 0; i < eventCount; i++) {
            const SequenceNumber seq = eventItems[i].data.u64;
            
            uint32_t epollEvents = eventItems[i].events;
            
            if (seq == WAKE_EVENT_FD_SEQ) {
                ... 省略    // 喚醒指定檔案並進行觀察

            } else {
                const auto& request_it = mRequests.find(seq);
                if (request_it != mRequests.end()) {
                    const auto& request = request_it->second;
                    int events = 0;
                    if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                    if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                    if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                    if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
                    
                    // 添加要通知的事件到列表
                    mResponses.push({.seq = seq, .events = events, .request = request});
                } else {
                    ... log 訊息
                }
            }
        }

    Done: ;

        ... 省略部份

        // 調用 callback
        for (size_t i = 0; i < mResponses.size(); i++) {
            Response& response = mResponses.editItemAt(i);
            
            if (response.request.ident == POLL_CALLBACK) {    // 該事件需要 CallBack
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;

                // 呼叫 callback
                int callbackResult = response.request.callback->handleEvent(fd, events, data);

                if (callbackResult == 0) {
                    AutoMutex _l(mLock);
                    removeSequenceNumberLocked(response.seq);
                }
                // Clear the callback reference in the response structure promptly because we
                // will not clear the response vector itself until the next poll.
                response.request.callback.clear();
                result = POLL_CALLBACK;
            }
        }
        return result;
    }
    ```
> ![](https://i.imgur.com/uLlBksG.png)


### Looper 接收訊息 - BinderCallBack

* 在上面我們有分析過 ServiceManager 的 Looper 啟動、循環，它監聽 Binder 文件的改動，並自己透過 **BinderCallback#==handleEvent==** 處理 Binder 接收到的 command

    ```cpp=
    // /servicemanager/main.cpp

    class BinderCallback : public LooperCallback {
    public:
        ... 省略部份

        int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
            // @ 由 IPCThreadState#handlePolledCommands 接手處理 Binder 命令
            IPCThreadState::self()->handlePolledCommands();
            return 1;  // 繼續接收
        }
    };

    int main(int argc, char** argv) {
        
        ... 省略部份
        
        // 創建 ServiceManager 實例
        sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());

        if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
            LOG(ERROR) << "Could not self register servicemanager";
        }

        // 設定 ServiceManager 處理 Binder 訊息
        IPCThreadState::self()->setTheContextObject(manager);

        // @ becomeContextManager 將當前進程設定為 Binder 管理者
        ps->becomeContextManager();
        
        // 啟動 Looper
        sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
        BinderCallback::setupTo(looper);
        ClientCallbackCallback::setupTo(looper, manager);

        // Looper 進入循環監聽
        while(true) {
            looper->pollAll(-1);
        }

        return EXIT_FAILURE;
    }
    ```

    * [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/IPCThreadState.cpp;l=1;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=IPCThreadState.cpp&ss=android%2Fplatform%2Fsuperproject)#handlePolledCommands 方法：接手處理 Binder 所收到的命令

        ```cpp=
        // IPCThreadState.cpp

        status_t IPCThreadState::handlePolledCommands()
        {
            status_t result;

            do {
                // @ 追蹤 getAndExecuteCommand
                result = getAndExecuteCommand();
            } while (mIn.dataPosition() < mIn.dataSize());

            processPendingDerefs();
            flushCommands();
            return result;
        }


        status_t IPCThreadState::getAndExecuteCommand()
        {
            status_t result;
            int32_t cmd;

            result = talkWithDriver();    // 去 kernel space (BinderDriver) 取得指令
            if (result >= NO_ERROR) {
                size_t IN = mIn.dataAvail();
                if (IN < sizeof(int32_t)) return result;
                cmd = mIn.readInt32();

                ... 省略部份

                // @ 追蹤 executeCommand
                result = executeCommand(cmd);

                ... 省略部份
            }

            ...

            return result;
        }

        sp<BHwBinder> the_context_object;

        // ServiceManager 有指定由自身處理
        void IPCThreadState::setTheContextObject(sp<BHwBinder> obj)
        {
            the_context_object = obj;
        }

        status_t IPCThreadState::executeCommand(int32_t cmd)
        {
            BHwBinder* obj;
            RefBase::weakref_type* refs;
            status_t result = NO_ERROR;
            switch ((uint32_t)cmd) {

            ... 省略其他 case

            // 收到 BinderDriver 訊息，要求 ServiceManager 交易
            case BR_TRANSACTION_SEC_CTX:
            case BR_TRANSACTION:
                    {
                    binder_transaction_data_secctx tr_secctx;
                    binder_transaction_data& tr = tr_secctx.transaction_data;

                    ... 省略

                    const pid_t origPid = mCallingPid;
                    const char* origSid = mCallingSid;
                    const uid_t origUid = mCallingUid;
                    const int32_t origStrictModePolicy = mStrictModePolicy;
                    const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;

                    ... 省略

                    Parcel reply;
                    status_t error;
                    bool reply_sent = false;

                    ... 省略
                        
                        
                    // 訪問物件是 ServiceManager 時，ptr 設定為 0
                    if (tr.target.ptr) {    
                        // 有指定目標
                        if (reinterpret_cast<RefBase::weakref_type*>(
                                tr.target.ptr)->attemptIncStrong(this)) {    // 嘗試增加目標的強引用計數
                            
                            error = reinterpret_cast<BHwBinder*>(tr.cookie)->transact(tr.code, buffer,
                                    &reply, tr.flags, reply_callback);
                            reinterpret_cast<BHwBinder*>(tr.cookie)->decStrong(this);
                        } else {
                            error = UNKNOWN_TRANSACTION;
                        }

                    } else {
                        // 沒有指定目標 （目前狀況）
                        // @ 分析 transact 函數
                        error = the_context_object
                            ->transact(tr.code, 
                                       buffer, 
                                       &reply, 
                                       tr.flags, 
                                       reply_callback);
                    }

                    ... 省略

                }
                break;

            }
        }
        ```

* [**Binder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/Binder.cpp)#`transact` 函數：這裡就可以看到 Service 主要在負責的 `onTransact` 函數

    ```java=
    status_t BBinder::transact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        data.setDataPosition(0);

        if (reply != nullptr && (flags & FLAG_CLEAR_BUF)) {
            reply->markSensitive();
        }

        status_t err = NO_ERROR;
        switch (code) {
            
            ... 省略部分 case

            default:
                // @ 查看 onTransact
                err = onTransact(code, data, reply, flags);
                break;
        }

        ...

        return err;
    }
    ```
        
### ServiceManager 重寫 transact - addService

* IPCThreadState#`transact` 函數：

    1. 如果是作為 Server 方 (像是 ServiceManager)，在 `transact` 函數時，就會去 **重寫 `onTransact` 函數**
    
    2. 真正的命令則是在 重寫 `onTransact` 函數 處理

    
* ServiceManager 在 [**BnServiceManager**](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder_aidl_test_stub-cpp-source/gen/android/os/IServiceManager.cpp) 中複寫 `onTransact` 函數，這裡關注 `addService` 這個命令，在接收到這個命令後，會去讀取 BinderDriver 傳入的 服務名稱、IBinder ...

    最後會呼叫 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp)#`addService` 函數

    ```c=
    // BnServiceManager.cpp

    ::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code,
                             const ::android::Parcel& _aidl_data, 
                             ::android::Parcel* _aidl_reply, 
                             uint32_t _aidl_flags) {

        ::android::status_t _aidl_ret_status = ::android::OK;
        switch (_aidl_code) {

        ... 省略其他 case

        case BnServiceManager::TRANSACTION_addService:
        {
            ::std::string in_name;
            ::android::sp<::android::IBinder> in_service;
            bool in_allowIsolated;
            int32_t in_dumpPriority;

            _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);

            ...

            // @ 有空可以看一下 readStrongBinder 函數
            _aidl_ret_status = _aidl_data.readStrongBinder(&in_service);
            
            ... 省略讀取 Parcel 資料

            // 呼叫 addService 方法
            ::android::binder::Status _aidl_status(
                // @ 追蹤 addService
                addService(in_name, 
                           in_service, 
                           in_allowIsolated, 
                           in_dumpPriority)
            );

            // 回覆 BinderDriver
            _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);

            if (((_aidl_ret_status) != (::android::OK))) {
              break;
            }
            if (!_aidl_status.isOk()) {
              break;
            }
        }
    }
    ```
    :::success
    * [**Parcel**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/Parcel.cpp)#`readStrongBinder` 函數：創建本地 Proxy，並讀取 BinderDriver 的數據，並 **透過 Parcel#`readObject` 來讀取 BinderServer**

        ```cpp=
        // Parcel.cpp
        status_t Parcel::readStrongBinder(sp<IBinder>* val) const
        {
            // @ 查看 readNullableStrongBinder
            status_t status = readNullableStrongBinder(val);
            ...
            return status;
        }

        status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
        {
            // @ 查看 unflatten_binder
            return unflatten_binder(ProcessState::self(), *this, val);
        }

        status_t unflatten_binder(const sp<ProcessState>& proc,
            const Parcel& in, sp<IBinder>* out)
        {
            const flat_binder_object* flat = in.readObject<flat_binder_object>();

            if (flat) {
                switch (flat->hdr.type) {
                    case BINDER_TYPE_BINDER:
                        *out = reinterpret_cast<IBinder*>(flat->cookie);
                        return finish_unflatten_binder(nullptr, *flat, in);

                    // 使用者註冊 Service 時，傳入會進這個 casee
                    case BINDER_TYPE_HANDLE:
                        // 創建一個本地代理，對應到 Binder ref
                        *out = proc->getStrongProxyForHandle(flat->handle);
                        return finish_unflatten_binder(
                            static_cast<BpHwBinder*>(out->get()), *flat, in);
                }
            }
            return BAD_TYPE;
        }
        ```
    :::

* [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp)#`addService` 函數：將 Service 存到 Map (`mNameToService`) 中

    > Key：**使用者設定的 Name**
    > 
    > Value：**ServiceManager 的代理對象**；方便之後在 BinderDriver 找到對應的 binder_ref
    ```cpp=
    // ServiceManager.h

    class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
    public:
        ...
    private
        struct Service {
            sp<IBinder> binder; // not null
            bool allowIsolated;
            int32_t dumpPriority;
            bool hasClients = false; // notifications sent on true -> false.
            bool guaranteeClient = false; // forces the client check to true
            Access::CallingContext ctx;   // process that originally registers this

            // the number of clients of the service, including servicemanager itself
            ssize_t getNodeStrongRefCount();
        };

        ...
        using ServiceMap = std::map<std::string, Service>;

        ServiceMap mNameToService;
    }

    // -----------------------------------------------------------------
    // ServiceManager.cpp

    Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
        auto ctx = mAccess->getCallingContext();

        ... 省略部分

        // implicitly unlinked when the binder is removed
        if (binder->remoteBinder() != nullptr &&
            binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
            ALOGE("Could not linkToDeath when adding %s", name.c_str());
            return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
        }

        auto it = mNameToService.find(name);
        
        ... 省略檢查

        // 覆蓋舊的同名 Service
        mNameToService[name] = Service{
                .binder = binder,
                .allowIsolated = allowIsolated,
                .dumpPriority = dumpPriority,
                .ctx = ctx,
        };

        ...

        return Status::ok();
    }
    ```
    :::info
    * 這邊我們可以看出 Service Name 的重要性，**Service Name 必須是唯一值** 
    :::

## IMediaDeathNotifier - getService 系統服務

這裡以客戶端 [**IMediaDeathNotifier**](https://android.googlesource.com/platform/frameworks/av/+/master/media/libmedia/IMediaDeathNotifier.cpp) 要取得 MediaPlayerService 為例（兩者不同進程），客戶端要透過 ServiceManager 取得 `"media.player"` 服務 

```cpp=
// IMediaDeathNotifier.cpp

sp<IMediaPlayerService> IMediaDeathNotifier::sMediaPlayerService;

const sp<IMediaPlayerService>
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    
    if (sMediaPlayerService == 0) {
        // 產生 BpServiceManager
        sp<IServiceManager> sm = defaultServiceManager();
        
        sp<IBinder> binder;
        do {
            // 透過代理 BpServiceManager 與 ServiceManager 通訊
            // @ 追蹤 getService 函數
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);
        
        // 監聽 binder 死亡
        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        
        // 透過 interface_cast 取得 IMediaPlayerService 的代理
        // 最終會轉換成 ++BpMediaPlayerService++
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}
```

:::info
* **`interface_cast`  宏 ?**

    可以產生 `BpMediaPlayerService`，而其內部包裝的就是 BpBinder，而 BpBinder 的建構函數就需要傳入一個 handle (服務描述)

    所以其原理都是透過 BpBinder 的 **handle 來找到對應服務**，由此我們可以知道 **`sm->getService` 是在 ServiceManager 中 ==找尋 handle !!==** 
    > (handle 也稱為控制碼)
    > 
    > eg. ServiceManager's handle 固定為 0
:::
> ![](https://i.imgur.com/ZJluvKB.png)


### [IServiceManager.cpp](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_vendor.UpsideDownCake_x86_64_silvermont_shared/gen/aidl/android/os/IServiceManager.cpp) - getService 取得 BpBinder

:::info
新版沒有 [**BpServiceManager**](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_vendor.UpsideDownCake_x86_64_silvermont_shared/gen/aidl/android/os/IServiceManager.cpp) 實做（新版改為 aidl 自動產生 code）
:::

```java=
// IServiceManager.cpp

// ServiceManager 介面名
namespace os {
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")
}

::android::binder::Status BpServiceManager::getService(
                        const ::std::string& name, 
                       ::android::sp<::android::IBinder>* _aidl_return) {
    
    ::android::Parcel _aidl_data;
    _aidl_data.markForBinder(remoteStrong());
    ::android::Parcel _aidl_reply;
    ::android::status_t _aidl_ret_status = ::android::OK;
    
    ...

    // ServiceManager 的介面名稱
    _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());

    ...

    // 要搜尋的 Service 的介面名稱
    _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);

    ...

    // 查看 
    _aidl_ret_status = remote()->transact(
                                    BnServiceManager::TRANSACTION_getService, // 給 ServiceManager 的命令
                                    _aidl_data, 
                                    &_aidl_reply, 
                                    0);
    
    ...
    
    _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
    ...

    // 讀取 ServiceMananger 回覆，也就是讀取 Binder Service 的 ref 引用
    _aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);

    ...
    return _aidl_status;
}
```
:::success
* [**Parcel**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/Parcel.cpp)#`readNullableStrongBinder` 函數：讀取 Binder 物件

    ```cpp=
    // Parcel.cpp

    status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
    {
        // @ 查看 unflatten_binder
        return unflatten_binder(ProcessState::self(), *this, val);
    }

    // 這個函數上面有說明
    status_t unflatten_binder(const sp<ProcessState>& proc,
        const Parcel& in, sp<IBinder>* out)
    {
        const flat_binder_object* flat = in.readObject<flat_binder_object>();

        if (flat) {
            switch (flat->hdr.type) {
                case BINDER_TYPE_BINDER:
                    *out = reinterpret_cast<IBinder*>(flat->cookie);
                    return finish_unflatten_binder(nullptr, *flat, in);
                case BINDER_TYPE_HANDLE:
                    *out = proc->getStrongProxyForHandle(flat->handle);
                    return finish_unflatten_binder(
                        static_cast<BpHwBinder*>(out->get()), *flat, in);
            }
        }
        return BAD_TYPE;
    }
    ```
:::

* 這裡取得的 remote() 函數取得的就是 [**BpBinder 對象**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/BpBinder.cpp)，所以其實它是在呼叫 BpBinder#**transact** (內部存有控制碼 handle) 方法
    
    :::info
    這邊呼叫 IPCThreadState#transact 傳入的 Handle 控制碼是 0
    :::
    ```cpp=
    // BpBinder.cpp

    status_t BpBinder::transact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        // Once a binder has died, it will never come back to life.
        if (mAlive) {
            ... 省略部份

            status_t status;
            if (CC_UNLIKELY(isRpcBinder())) {
                // Rpc Binder...
            } else {
                // @ IPCThreadState#transact 分析
                status = IPCThreadState::selTextf()->transact(
                    binderHandle(),     // 0 (ServiceManager)
                    code,             // CHECK_SERVICE_TRANSACTION
                    data, 
                    reply, 
                    flags
                );
            }

            ... 省略部份

            // Server 已死亡
            if (status == DEAD_OBJECT) mAlive = 0;

            return status;
        }
        return DEAD_OBJECT;
    }
    ```
    > ![](https://i.imgur.com/dw16GPp.png)

### [IPCThreadState](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/IPCThreadState.cpp) - transact 傳送

:::info
這裡我們是作為客戶端在使用 `transact` 函數，向 BindeDriver 發送資料
:::

* 在了解 IPCThreadState 後 ([**IPCThreadState 介紹**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#IPCThreadState---TLS))，我們接著來看 BpServiceManager#`addService` 函數所使用到的 `transact` 方法，這裡有幾個重要函數

    | 函數名 | 功能 |
    | -------- | -------- |
    | writeTransactionData | 傳輸數據到 BinderDriver (kernel) |
    | waitForResponse | 等待 BinderDriver (kernel) 回覆 |
    :::success
    * BinderDriver 指令取名方式
        傳向 BinderDriver 的指令是有規則的，`BC_` 開頭的是向 BinderDriver 發送，而 `BR_` 則是 BinderDriver 回覆使用者
    :::
    ```cpp=
    // IPCThreadState.cpp

    status_t IPCThreadState::transact(int32_t handle,    // 0
                                      uint32_t code,     // ADD_SERVICE_TRANSACTION
                                      const Parcel& data,
                                      Parcel* reply, uint32_t flags)
    {
        ... log 訊息

        status_t err;
        flags |= TF_ACCEPT_FDS;

        ... log 訊息

        // @ writeTransactionData 函數
        // 傳遞 cmd 為 BC_TRANSACTION
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);

        if (err != NO_ERROR) {
            if (reply) reply->setError(err);
            return (mLastError = err);
        }

        if ((flags & TF_ONE_WAY) == 0) {    // 需要等待回應

            ... 省略部份

            if (reply) {
                err = waitForResponse(reply);
            } else {
                Parcel fakeReply;
                err = waitForResponse(&fakeReply);
            }

            ... 省略部份

        } else {    // 不須等待回應
            err = waitForResponse(nullptr, nullptr);
        }
        return err;
    }
    ```

1. **writeTransactionData 函數**：首先會準備要傳向 BinderDriver (kernel) 的數據結構 `（binder_transaction_data）` 結構，對該結構填充數據

    | binder_transaction_data 成員 | 功能 | 當前數據 |
    | -------- | -------- | - |
    | cmd | BinderDriver (kernel) 需要處理的指令 | `BC_TRANSACTION` |
    | handle | 標示要傳遞的目標 | `0` (ServiceManager) |
    | code | 接收進程會收到的命令 | 傳遞給 ServiceManager 命令 `CHECK_SERVICE_TRANSACTION` |
    
    ```cpp=
    // IPCThreadState.cpp

    // 傳遞 cmd 為 BC_TRANSACTION
    status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
        int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
    {
        binder_transaction_data tr;

        // 不要將未初始化的堆棧數據傳遞給遠程進程
        tr.target.ptr = 0; 
        
        tr.target.handle = handle;    // 目前是 0
        
        tr.code = code;    // 目前是 CHECK_SERVICE_TRANSACTION
        
        tr.flags = binderFlags;
        tr.cookie = 0;
        tr.sender_pid = 0;
        tr.sender_euid = 0;
        
        const status_t err = data.errorCheck();    // 檢查 Parcel 資料結構是否有錯誤
        
        if (err == NO_ERROR) {
            tr.data_size = data.ipcDataSize();
            tr.data.ptr.buffer = data.ipcData();
            tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
            tr.data.ptr.offsets = data.ipcObjects();

        } else if (statusBuffer) {
            tr.flags |= TF_STATUS_CODE;
            *statusBuffer = err;
            tr.data_size = sizeof(status_t);
            tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
            tr.offsets_size = 0;
            tr.data.ptr.offsets = 0;
        } else {
            return (mLastError = err);
        }
        
        // 將給 BinderKernel 的命令寫入 mOut 中
        mOut.writeInt32(cmd);    // 目前是 BC_TRANSACTION
        
        // 將數據包寫入 mOut 中
        mOut.write(&tr, sizeof(tr));
        
        return NO_ERROR;
    }
    ```
    
2. **waitForResponse 函數**：主要是與 Binder kernel 通訊，並處理 BinderDriver 的回覆（處理以 `BR_` 開頭的命令），其中有兩個較重要的函數
    | 函數名 | 功能 |  
    | - | - |
    | talkWithDriver | 對 BinderDriver (kernel) 寫入(mOut)  or 讀取(mIn) |
    | executeCommand | 處理從 Binder kernel 回傳的命令 |

    ```cpp=
    // IPCThreadState.cpp

    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
    {
        uint32_t cmd;
        int32_t err;

        while (1) {

            // 與 Binder 通訊
            // @ 分析 talkWithDriver 函數
            if ((err=talkWithDriver()) < NO_ERROR) break;

            // 到這裡就代表 Binder kernel 有回覆 （mIn 有資料）
            err = mIn.errorCheck();

            if (err < NO_ERROR) break;

            if (mIn.dataAvail() == 0) continue;

            cmd = (uint32_t)mIn.readInt32();

            ... log 訊息

            // 有許多 BR_ 開頭的 command，這裡只留下幾個
            switch (cmd) {

            ...

            case BR_TRANSACTION_COMPLETE:    // BinderDriver 回覆使用者，傳輸完成
                if (!reply && !acquireResult) goto finish;
                break;

            ... 其他 case

            default:
                // 處理各種命令
                err = executeCommand(cmd);
                if (err != NO_ERROR) goto finish;
                break;
            }
        }

    finish:
        ...
        return err;
    }

    status_t IPCThreadState::talkWithDriver(bool doReceive)    // 預設 doReceive = true
    {
        if (mProcess->mDriverFD < 0) {
            return -EBADF;
        }

        binder_write_read bwr

        // 判斷 mIn＃position 位置 是否有移動
        // 有移動並大於 dataSize 代表有資料
        const bool needRead = mIn.dataPosition() >= mIn.dataSize();

        // 在讀取 mIn 時我們不想寫入任何 mOut 資料
        const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

        bwr.write_size = outAvail;
        bwr.write_buffer = (uintptr_t)mOut.data();    // 寫入資料

        // 目前狀況是 doReceive = true
        // 並且 needRead = true (有資料要讀取)
        if (doReceive && needRead) {
            // 要讀取的資料
            bwr.read_size = mIn.dataCapacity();
            bwr.read_buffer = (uintptr_t)mIn.data();
        } else {
            bwr.read_size = 0;
            bwr.read_buffer = 0;
        }

        ... log 訊息

        // 如果沒有任何事情要做（不須 read | write）則即時返回
        if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

        // consumed 設定為 0
        bwr.write_consumed = 0;
        bwr.read_consumed = 0;

        status_t err;
        do {
            ... log 訊息

    #if defined(__ANDROID__)
            // 呼叫 Kernel#binder_ioctl 函數
            if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
                err = NO_ERROR;
            else
                err = -errno;
    #else
            err = INVALID_OPERATION;

    #endif
            if (mProcess->mDriverFD < 0) {
                err = -EBADF;
            }
            ... log 訊息

        } while (err == -EINTR);

        ... 省略 err 錯誤處理

        return err;
    }
    ```
    > ![](https://i.imgur.com/D3g3Igs.png)

* 客戶端的 IPCThreadState#writeTransactionData 向 Binder 發送 `BC_TRANSACTION` 命令後，Binder 驅動會將命令轉為 `BR_TRANSACTION`，併發送給 ServiceManager
    
    > ![](https://i.imgur.com/hSHn18f.png)



### [ServiceManager](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_vendor.UpsideDownCake_x86_64_silvermont_shared/gen/aidl/android/os/IServiceManager.cpp) - onTransact 接收命令

:::info
ServiceManager 繼承 BBinder，並透過 AIDL 複寫 `onTransact` 函數
:::

* 首先我們要先知道 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.h;l=19;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=ServiceManager.h&sq=&ss=android%2Fplatform%2Fsuperproject) **繼承於 BBinder 類**，IPCThreadState#`executeCommand` 才可以呼叫 `transact` 的方法
    
    1. ServiceManager：繼承 BnServiceManager
    
    2. BnServiceManager：繼承 BnInterface<IServiceManager\>，[**BnInterface**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/IInterface.h;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f;l=84) 是一個模板類，而 [**BnServiceManager**](https://cs.android.com/android/platform/superproject/+/master:prebuilts/vndk/v32/x86/include/generated-headers/frameworks/native/libs/binder/libbinder/android_vendor.32_x86_shared/gen/aidl/android/os/BnServiceManager.h;l=10;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=BnServiceManager&ss=android%2Fplatform%2Fsuperproject) 由 aidl 自動產生，並實作 `onTransact` 方法
    
    3. BnInterface：繼承於 [**BBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/Binder.h;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f;l=30)，實作 `transact` 方法，**處理完後將實際業務邏輯交給 ServiceManager#onTransact 方法**
        > ![](https://i.imgur.com/pGomAhb.png)

        ```cpp=
        // ServiceManager.h

        class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
            ...
        }

        // --------------------------------------------------------------
        // BnServiceManager.h

        class BnServiceManager : public ::android::BnInterface<IServiceManager> {

        public:
          static constexpr uint32_t TRANSACTION_getService = ::android::IBinder::FIRST_CALL_TRANSACTION + 0;
          static constexpr uint32_t TRANSACTION_checkService = ::android::IBinder::FIRST_CALL_TRANSACTION + 1;
          static constexpr uint32_t TRANSACTION_addService = ::android::IBinder::FIRST_CALL_TRANSACTION + 2;
          static constexpr uint32_t TRANSACTION_listServices = ::android::IBinder::FIRST_CALL_TRANSACTION + 3;
          static constexpr uint32_t TRANSACTION_registerForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 4;
          static constexpr uint32_t TRANSACTION_unregisterForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 5;
          static constexpr uint32_t TRANSACTION_isDeclared = ::android::IBinder::FIRST_CALL_TRANSACTION + 6;
          static constexpr uint32_t TRANSACTION_getDeclaredInstances = ::android::IBinder::FIRST_CALL_TRANSACTION + 7;
          static constexpr uint32_t TRANSACTION_updatableViaApex = ::android::IBinder::FIRST_CALL_TRANSACTION + 8;
          static constexpr uint32_t TRANSACTION_registerClientCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 9;
          static constexpr uint32_t TRANSACTION_tryUnregisterService = ::android::IBinder::FIRST_CALL_TRANSACTION + 10;
          static constexpr uint32_t TRANSACTION_getServiceDebugInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 11;
          explicit BnServiceManager();

          // BnServiceManager.cpp 會實作
          ::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) override;
        }


        // --------------------------------------------------------------
        // IInterface.h
        template<typename INTERFACE>
        class BnInterface : public INTERFACE, public BBinder
        {
        public:
            virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
            virtual const String16&     getInterfaceDescriptor() const;

        protected:
            typedef INTERFACE           BaseInterface;
            virtual IBinder*            onAsBinder();
        };

        // --------------------------------------------------------------
        // Binder.h

        class BBinder : public IBinder
        {
        public:
            ...

        protected:

            // 繼承該類必須 override 該方法
            virtual status_t    onTransact( uint32_t code,
                                            const Parcel& data,
                                            Parcel* reply,
                                            uint32_t flags = 0);
        };
        ```
        
* BnServiceManager#`onTransact` 函數：取出使用者傳入的 ServiceName 開始搜尋

    ```cpp=
    ::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code, 
                                         const ::android::Parcel& _aidl_data, 
                                         ::android::Parcel* _aidl_reply, 
                                         uint32_t _aidl_flags) {

        ::android::status_t _aidl_ret_status = ::android::OK;
        switch (_aidl_code) {
        case BnServiceManager::TRANSACTION_getService:
        {
            ::std::string in_name;
            ::android::sp<::android::IBinder> _aidl_return;

            ...

            // 使用者搜尋的 Service Name
            _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
            if (((_aidl_ret_status) != (::android::OK))) {
              break;
            }
            ...

            ::android::binder::Status _aidl_status(
                // @ 查看 getService 函數
                getService(in_name, &_aidl_return)
            );

            // 將搜尋結果寫入 Parcel
            _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);

            ... 省略檢查

            // 增加強計數
            _aidl_ret_status = _aidl_reply->writeStrongBinder(_aidl_return);
            if (((_aidl_ret_status) != (::android::OK))) {
              break;
            }
        }
        return _aidl_ret_status;
        }
    }
    ```
    
    * [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp)#`getService` 函數：透過 ServiceName 查詢 ServiceManager 中的列表，並找到對應的 IBinder 返回

        ```cpp=
        // ServiceManager.cpp

        Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
            // @ 查看 tryGetService
            *outBinder = tryGetService(name, true);
            return Status::ok();
        }

        sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
            auto ctx = mAccess->getCallingContext();

            sp<IBinder> out;
            Service* service = nullptr;
            if (auto it = mNameToService.find(name); it != mNameToService.end()) {
                service = &(it->second);

                ... 省略部分

                // 找到目標 Service
                out = service->binder;
            }
            ...

            if (!out && startIfNotFound) {
                // 啟動服務
                tryStartService(name);
            }
            ...

            return out;
        }
        ```

## ServiceManager 方法


### 檢查服務 - checkService
* Client 端會透過 Proxy 傳遞 `CHECK_SERVICE_TRANSACTION` 命令到 ServiceManager 中
    > ![](https://i.imgur.com/LtclI3n.png)


* 由於實現 onTransact 方法的 BnServiceManager 類是由 aidl 自動產生，所以這裡我們跳過，只需要知道目前的 `CHECK_SERVICE_TRANSACTION` 命令會對應到 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp;l=1;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=ServiceManager.cpp&sq=&ss=android%2Fplatform%2Fsuperproject)#`checkService` 方法
    > 其實 CHECK_SERVICE_TRANSACTION 會對應 TRANSACTION_checkService

    ```cpp=
    // ServiceManager.cpp

    // 傳入的 name 是 "media.player"
    Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
        *outBinder = tryGetService(name, false);
        // returns ok regardless of result for legacy reasons
        return Status::ok();
    }

    // 傳入的 name 是 "media.player"
    sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
        auto ctx = mAccess->getCallingContext();

        sp<IBinder> out;
        Service* service = nullptr;
        
        // 透過 name 尋找 service
        if (auto it = mNameToService.find(name); it != mNameToService.end()) {
            service = &(it->second);

            if (!service->allowIsolated) {
                uid_t appid = multiuser_get_app_id(ctx.uid);
                bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;

                if (isIsolated) {
                    return nullptr;
                }
            }
            out = service->binder;
        }

        if (!mAccess->canFind(ctx, name)) {
            return nullptr;
        }

        if (!out && startIfNotFound) {
            tryStartService(name);
        }

        ...

        return out;
    }
    ```
    從上面可以看到 ServiceManager 會 **透過 `mNameToService.find(name)` 來找到對應的 Service 結構**，而該結構內就會有 目標 IBinder
    ```cpp=
    // ServiceManager.h

    class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
        ...
        
    private:
        
        struct Service {
            sp<IBinder> binder; // not null
            bool allowIsolated;
            int32_t dumpPriority;
            bool hasClients = false; // notifications sent on true -> false.
            bool guaranteeClient = false; // forces the client check to true
            pid_t debugPid = 0; // the process in which this service runs

            // the number of clients of the service, including servicemanager itself
            ssize_t getNodeStrongRefCount();
        };
        using ServiceMap = std::map<std::string, Service>;
        
        ServiceMap mNameToService;
    }
    ```
    
    :::info
    * 從這裡可以知道，ServiceManager 有一個 Map，透過 name 作為 key 找到目標 IBinder
        
        這個 IBinder 可能是本地（BBinder）、代理（BpBinder）
    :::
    
### 添加服務 - addService

* Native 端註冊流程請參考 [**Binder - Native Binder 原理篇**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#Client-%E5%90%91-ServiceManager-%E8%A8%BB%E5%86%8A)
    > ![](https://i.imgur.com/kSbYHjX.png)

* 由於實現 onTransact 方法的 BnServiceManager 類是由 aidl 自動產生，所以這裡我們跳過，只需要知道目前的 `ADD_SERVICE_TRANSACTION` 命令會對應到 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp;l=1;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=ServiceManager.cpp&sq=&ss=android%2Fplatform%2Fsuperproject)#`addService` 方法
    > 其實 ADD_SERVICE_TRANSACTION 會對應 addService

    ```cpp=
    // ServiceManager.cpp

    // 傳入的 name 是 "media.player"
    Status ServiceManager::addService(const std::string& name, 
                          const sp<IBinder>& binder,     // BBinder
                          bool allowIsolated, 
                          int32_t dumpPriority) {
        auto ctx = mAccess->getCallingContext();

        ... 省略部分

        // 將 Service 存在 Map 中 (如果存在的話就覆蓋)
        mNameToService[name] = Service {
            .binder = binder,
            .allowIsolated = allowIsolated,
            .dumpPriority = dumpPriority,
            .debugPid = ctx.debugPid,
        };

        auto it = mNameToRegistrationCallback.find(name);
        
        if (it != mNameToRegistrationCallback.end()) {
            for (const sp<IServiceCallback>& cb : it->second) {
                mNameToService[name].guaranteeClient = true;
                // 在 registerForNotifications 中檢查權限
                cb->onRegistration(name, binder);
            }
        }

        return Status::ok();
    }
    ```
    
    :::success
    * IBinder 不是序列化！
        
        Server 在 ServiceManager 註冊完 IBinder 訊息後，Client 取用就必須透過 Kernel space 轉換才能使用
    :::
    
### adb 查看 Service

* 可以透過 adb 查看該裝置所有的 Service
    
    ```shell=
    adb shell

    service list
    ```
    > ![](https://i.imgur.com/F5iugl1.png)


## Appendix & FAQ

:::info
:::

###### tags: `Binder` `Android 系統`
