--- 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 系統`