--- title: 'Binder - 死亡通知' disqus: kyleAlien --- Binder - 死亡通知 === ## OverView of Content 當 BinderServer 意外死亡時,必須通知 BinderKernel、BinderProxy ... 作出相應動作,像是通知 BinderRef、BinderProxy 物件已經死亡 [TOC] ## Binder 註冊死亡通知 Binder Client 可以手動註冊死亡通知,這樣 Binder Server 在死亡時 Client 就會收到通知;Binder 接收死亡通知重點如下 1. 定義一個死亡通知接收者 2. 該接收者必須繼承於 `DeathRecipient` 類 ```cpp= // IBinder.h class DeathRecipient : public virtual RefBase { public: virtual void binderDied(const wp<IBinder>& who) = 0; }; ``` ### Binder client - 註冊死亡通知 * Binder client 要註冊死亡通知可以透過 [**Binder**](https://cs.android.com/android/platform/superproject/+/master:prebuilts/vndk/v30/arm/include/frameworks/native/libs/binder/include/binder/IBinder.h)#`linkToDeath` 函數註冊 ```cpp= // IBinder.h class [[clang::lto_visibility_public]] IBinder : public virtual RefBase { public: ... virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0) = 0; } ``` * [**BpBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/BpBinder.cpp)#`linkToDeath` 函數實現:請看註解 | Member | 功能 | 注意 | | -------- | -------- | -------- | | `mObitsSent` | 判斷是否已經發送過死亡通知 | 如果已發送過則返回 `DEAD_OBJECT` 代表 BinderServer 已死亡 | | `mObituaries` | 該 BpBinder 需要通知死亡的列表 | | ```cpp= // BpBinder.h class BpBinder : public IBinder { ... private: volatile int32_t mObitsSent; Vector<Obituary>* mObituaries; // 待通知的接口列表 } // -------------------------------------------------------------------- // BpBinder.cpp status_t BpBinder::linkToDeath( const sp<DeathRecipient>& recipient, // 使用者待通知的類 void* cookie, // 標示死亡通知接收者的資訊 uint32_t flags) // 標示死亡通知接收者的資訊 { ... 省略部分 Obituary ob; ob.recipient = recipient; ob.cookie = cookie; ob.flags = flags; ... log msg { AutoMutex _l(mLock); // 互斥鎖 if (!mObitsSent) { // 是否發送過通知 if (!mObituaries) { // 死亡通知列表尚未創建,就創建列表 mObituaries = new Vector<Obituary>; if (!mObituaries) { return NO_MEMORY; // 創建失敗 } ... log msg if (!isRpcBinder()) { if constexpr (kEnableKernelIpc) { // 自身弱引用計數 + 1 getWeakRefs()->incWeak(this); IPCThreadState* self = IPCThreadState::self(); // @ 查看 requestDeathNotification // `binderHandle` 取得控制碼 self->requestDeathNotification(binderHandle(), this); // @ 查看 flushCommands // 立刻與 BinderKernel 通訊 self->flushCommands(); } } } // 添加死亡通知進列表 ssize_t res = mObituaries->add(ob); return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res; } } // BinderServer 已死亡 return DEAD_OBJECT; } ``` * [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/IPCThreadState.cpp)#`requestDeathNotification`:新增一個 `BC_REQUEST_DEATH_NOTIFICATION` 命令,並將 **控制碼、BpBinder 地址** 寫入 :::info 講到控制碼,我們就要知道該控制碼是拿來找尋對應 BpBinder 的 `binder_ref` 引用 ::: ```cpp= status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy) { mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION); mOut.writeInt32((int32_t)handle); // 控制碼 mOut.writePointer((uintptr_t)proxy); // BpBinder 地址 return NO_ERROR; } ``` * [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/IPCThreadState.cpp)`flushCommands`:重點是 `talkWithDriver`,透過該函數,會馬上與 BinderKernel 通訊 (**也就是立刻處理註冊命令**) ```cpp= // IPCThreadState.cpp void IPCThreadState::flushCommands() { if (mProcess->mDriverFD < 0) // 判斷是否已經取得 `/dev/binder` 描述 return; // 馬上與 BinderKernel 通訊 talkWithDriver(false); // 內部會傳 `BINDER_WRITE_READ` 命令 ... 省略部分 } ``` ### Binder kernel - 註冊死亡通知 :::info 目前在 Kernel 接收到 `BINDER_WRITE_READ` 命令,並準備處理死亡通知註冊命令 `BC_REQUEST_DEATH_NOTIFICATION` ::: * 在上面我們透過 `talkWithDriver` 對 BinderKernel 寫入 `BINDER_WRITE_READ` 命令,在裡我們直接轉跳到對應的處裡函數 `binder_thread_write`,主要步驟如下 1. BinderKernel 讀取 `控制碼`、`BpBinder 地址` 2. 透過 ***控制碼*** 取得 ***binder_ref*** 3. 透過 ***binder_ref*** 取得對應的 ***binder_node*** 4. 檢查 ***binder_ref*** 是否已經註冊過死亡通知 :::success * 從這裡可以看到一個 `binder_ref` 只能註冊一個死亡通知 ::: 5. **將 `ref->death->work` 加入 BinderClient proc 的 TODO 列表,等待 BinderClient 處理** ```c= static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed) { uint32_t cmd; struct binder_context *context = proc->context; void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; while (ptr < end && thread->return_error.cmd == BR_OK) { int ret; if (get_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); ... switch (cmd) { case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; binder_uintptr_t cookie; struct binder_ref *ref; struct binder_ref_death *death = NULL; // 取得 Client 寫入的 "控制碼" if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); // 跳到下個命令 // 取得 Client 寫入的 "BpBinder 地址" if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); // 跳到下個命令 ... binder_proc_lock(proc); // 透過 "控制碼" 取得 "binder_ref" ref = binder_get_ref_olocked(proc, target, false); if (ref == NULL) { ... err msg binder_proc_unlock(proc); kfree(death); break; } ... debug msg // 透過 "binder_ref" 取得對應的 binder_node binder_node_lock(ref->node); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) { // binder ref 已經設定 ... binder_node_unlock(ref->node); binder_proc_unlock(proc); kfree(death); break; } // 創建 `binder_ref_death` binder_stats_created(BINDER_STAT_DEATH); // 初始化列表 INIT_LIST_HEAD(&death->work.entry); // 設定 BpBinder 地址進去 death->cookie = cookie; // 設定 ref 對應的死亡通知 ref->death = death; if (ref->node->proc == NULL) { // 工作狀態改為 BINDER_WORK_DEAD_BINDER ref->death->work.type = BINDER_WORK_DEAD_BINDER; binder_inner_proc_lock(proc); // 將 `ref->death->work` 加入 BinderClient proc 的 TODO 列表 binder_enqueue_work_ilocked( &ref->death->work, &proc->todo); // 喚醒 BinderClient 的 proc 進程 binder_wakeup_proc_ilocked(proc); binder_inner_proc_unlock(proc); } } else { ... } binder_node_unlock(ref->node); binder_proc_unlock(proc); } break; } } } ``` ## Binder 發送死亡通知 Binder 驅動程式的檔案操作函數,在 **釋放時會呼叫 `binder_release`** **不論是否是意外關閉,都會呼叫該函數,只要一個是由 Server 呼叫 (自己關閉),另一個由 Kernel 呼叫 (意外)** ```c= // binder.c const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, .compat_ioctl = compat_ptr_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, .release = binder_release, }; ``` > 接著準備分析 `binder_release` 函數 ### Binder server - 發送死亡通知 :::info 現在是 Binder server 的角度來看 Binder kernel ::: * **`binder_release` 函數**:移除 proc 相關檔案,並 **將 proc 的移除放置到 延遲列表** :::success * 放入延遲列表等待有空閒時間再移除,因為是放 proc 資源是耗時操作 ::: ```c= // binder.c static int binder_release(struct inode *nodp, struct file *filp) { // 取得存在 `/dev/binder` 中的 binder_proc struct binder_proc *proc = filp->private_data; ... if (proc->binderfs_entry) { // 移除 proc 相關檔案 binderfs_remove_file(proc->binderfs_entry); proc->binderfs_entry = NULL; } // 移除 proc 任務加入延遲列表 // @ 查看 binder_defer_work binder_defer_work(proc, BINDER_DEFERRED_RELEASE); return 0; } ``` * **`binder_defer_work` 函數**:添加進全局列表等待釋放 ```c= // binder.c static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) { mutex_lock(&binder_deferred_lock); // 互斥鎖 proc->deferred_work |= defer; if (hlist_unhashed(&proc->deferred_work_node)) { hlist_add_head(&proc->deferred_work_node, &binder_deferred_list); schedule_work(&binder_deferred_work); } mutex_unlock(&binder_deferred_lock); } ``` * `BINDER_DEFERRED_RELEASE` 最終會 **由 `binder_deferred_release` 函數處理**: ```c= // binder.c static void binder_deferred_release(struct binder_proc *proc) // 準備要刪除的進程 { struct binder_context *context = proc->context; struct rb_node *n; int threads, nodes, incoming_refs, outgoing_refs, active_transactions; ... 省略部分 nodes = 0; incoming_refs = 0; while ((n = rb_first(&proc->nodes))) { struct binder_node *node; // 取得 binder_node node = rb_entry(n, struct binder_node, rb_node); nodes++; /* * take a temporary ref on the node before * calling binder_node_release() which will either * kfree() the node or call binder_put_node() */ binder_inc_node_tmpref_ilocked(node); // 移除 binder_node rb_erase(&node->rb_node, &proc->nodes); binder_inner_proc_unlock(proc); // @ 查看 binder_node_release incoming_refs = binder_node_release(node, incoming_refs); binder_inner_proc_lock(proc); } ... } ``` * **`binder_node_release` 函數**:檢查、釋放 binder_node,並返回來有多少 binder_ref 參照當前的 binder_node 節點 1. 在這裡會遍歷該 binder_node 相依的所有 binder_ref 2. 切換處理工作狀態為 `BINDER_WORK_DEAD_BINDER` 3. 通知對應的 proc 讀取新指令 ```c= // binder.c static int binder_node_release(struct binder_node *node, int refs) { struct binder_ref *ref; int death = 0; struct binder_proc *proc = node->proc; ... // 檢查 ref 引用的數量 if (hlist_empty(&node->refs) && node->tmp_refs == 1) { binder_inner_proc_unlock(proc); binder_node_unlock(node); // 釋放 binder_node binder_free_node(node); return refs; } node->proc = NULL; node->local_strong_refs = 0; // Binder kernel 中強引用次數 node->local_weak_refs = 0; // Binder kernel 中弱引用次數 binder_inner_proc_unlock(proc); spin_lock(&binder_dead_nodes_lock); // 將 node#dead_node 添加到全域的 binder_dead_nodes hlist_add_head(&node->dead_node, &binder_dead_nodes); spin_unlock(&binder_dead_nodes_lock); hlist_for_each_entry(ref, &node->refs, node_entry) { refs++; /* * Need the node lock to synchronize * with new notification requests and the * inner lock to synchronize with queued * death notifications. */ binder_inner_proc_lock(ref->proc); if (!ref->death) { binder_inner_proc_unlock(ref->proc); continue; } death++; ... // 切換處理工作狀態為 `BINDER_WORK_DEAD_BINDER` // 代表該 Server 已經死亡,待使用者處理 ref->death->work.type = BINDER_WORK_DEAD_BINDER; binder_enqueue_work_ilocked(&ref->death->work, &ref->proc->todo); // 喚醒 ref 內的 proc,就是使用者 proc binder_wakeup_proc_ilocked(ref->proc); binder_inner_proc_unlock(ref->proc); } ... return refs; } ``` ### Binder client - 讀取死亡通知 :::info 目前是站在 **Binder client** 使用 Binder kernel 的角度 ::: * 在 Binder Server 被釋放時,會喚醒 Binder client 作後續死亡通知;Binder client **Thread 會接續來處理 `binder_thread_read` 函數** 當前 BinderDriver 將 `BINDER_WORK_DEAD_BINDER` 增加到 Client 的 TODO 列表中;相關類型的任務如下 | 任務類型 | 說明 | | -------- | -------- | | `BINDER_WORK_DEAD_BINDER` | 通知 Client,BinderServer 已死亡 | | `BINDER_WORK_DEAD_BINDER_AND_CLEAR` | 告訴 Client,Kernel 已成功註銷了一個之前註冊的死亡通知 | | `BINDER_WORK_CLEAR_DEATH_NOTIFICATION` | 告訴 Client,Kernel 已成功註銷了一個之前註冊的死亡通知 & BinderServer 已死亡 | ```c= // binder.c static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed, int non_block) { void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; ... while (1) { uint32_t cmd; ... struct list_head *list = NULL; struct binder_work *w = NULL; ... // 決定待辦的列表 if (!binder_worklist_empty_ilocked(&thread->todo)) list = &thread->todo; else if (!binder_worklist_empty_ilocked(&proc->todo) && wait_for_proc_work) list = &proc->todo ... // 將 list 串接到 binder_work w = binder_dequeue_work_head_ilocked(list); ... switch (w->type) { case BINDER_WORK_DEAD_BINDER: // BinderServer 死亡通知 case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { struct binder_ref_death *death; uint32_t cmd; binder_uintptr_t cookie; // 透過 container_of 宏取得 binder_ref_death 頭地址 death = container_of(w, struct binder_ref_death, work); // 判斷 work 工作類型 if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) // 通知使用者已清除一個 Binder 死亡通知 cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else // 遠端的 BinderServer 已死亡 cmd = BR_DEAD_BINDER; cookie = death->cookie; ... debug msg if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { ... 釋放 death 結構 } else { // 將 w 加入 `proc->delivered_death` binder_enqueue_work_ilocked( w, &proc->delivered_death); binder_inner_proc_unlock(proc); } // 寫入 BR_XXXX,準備回覆使用者 if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); // 移動指標,往下一個讀取 // 寫入當初 User 註冊的 BpBinder 地址 !! if (put_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); // 移動指標,往下一個讀取 binder_stat_br(proc, thread, cmd); if (cmd == BR_DEAD_BINDER) goto done; /* DEAD_BINDER notifications can cause transactions */ } break; ... } } return 0; } ``` * 目前我們要分析的狀況是 BinderServer 死亡,所以 ^1.^ BinderClient 是接收 `BINDER_WORK_DEAD_BINDER` 命令,並經過分析後 BinderDriver 會 ^2.^ 向使用者空間傳送 `BR_DEAD_BINDER` > ![](https://i.imgur.com/aOrPDy7.png) ### Client user space - 處理死亡通知 * 使用者空間是靠 [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/IPCThreadState.cpp)#`executeCommand` 函數來處理 Binder 回傳的事件 (BR_XXX 命令);目前是要處理 `BR_DEAD_BINDER` 命令 ```cpp= // IPCThreadState.cpp status_t IPCThreadState::executeCommand(int32_t cmd) { BBinder* obj; RefBase::weakref_type* refs; status_t result = NO_ERROR; switch ((uint32_t)cmd) { ... 省略其它 case case BR_DEAD_BINDER: { BpBinder *proxy = (BpBinder*)mIn.readPointer(); // 取得 BpBinder 的地址 // @ 分析 sendObituary proxy->sendObituary(); mOut.writeInt32(BC_DEAD_BINDER_DONE); // 向 BinderDriver 說已通知完畢 mOut.writePointer((uintptr_t)proxy); } break; } if (result != NO_ERROR) { mLastError = result; } return result; } ``` * [**BpBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/BpBinder.cpp)#`sendObituary` 函數:通知相依的所有類 BinderServer 已死亡 ```cpp= // BpBinder.cpp void BpBinder::sendObituary() { ... 省略部分 mAlive = 0; // 已發送過死亡通知 if (mObitsSent) return; mLock.lock(); Vector<Obituary>* obits = mObituaries; if(obits != nullptr) { ... log info if (!isRpcBinder()) { if constexpr (kEnableKernelIpc) { IPCThreadState* self = IPCThreadState::self(); // 通知 Kernel 清除死亡通知 self->clearDeathNotification(binderHandle(), this); // 立即處理 self->flushCommands(); } } mObituaries = nullptr; } mObitsSent = 1; mLock.unlock(); ... log info if (obits != nullptr) { const size_t N = obits->size(); // 通知所有觀察者 for (size_t i=0; i<N; i++) { // 通知觀察者 // @ 查看 reportOneDeath 函數 reportOneDeath(obits->itemAt(i)); } // 刪除死亡通知列表 delete obits; } } ``` 1. 通知 Kernel 清除死亡通知 2. 遍歷通知所有 BpBinder 內的死亡通知列表 3. 使用 `reportOneDeath` 函數,通知 BinderServer 死亡 ```cpp= // BpBinder.h struct Obituary { wp<DeathRecipient> recipient; void* cookie; uint32_t flags; }; // ---------------------------------------------------------- // BpBinder.cpp void BpBinder::reportOneDeath(const Obituary& obit) { // 使用 `promote` 函數,將弱指標升級為強指標 sp<DeathRecipient> recipient = obit.recipient.promote(); ALOGV("Reporting death to recipient: %p\n", recipient.get()); if (recipient == nullptr) return; // 如果沒有升級,不就能操作物件 (因為 `->` 沒寫) recipient->binderDied(wp<BpBinder>::fromExisting(this)); } ``` ## Binder client 註銷死亡通知 * Binder client 要 **註銷** 死亡通知可以透過 [**Binder**](https://cs.android.com/android/platform/superproject/+/master:prebuilts/vndk/v30/arm/include/frameworks/native/libs/binder/include/binder/IBinder.h)#`unlinkToDeath` 函數註冊 ```cpp= // IBinder.h class [[clang::lto_visibility_public]] IBinder : public virtual RefBase { public: ... virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0, wp<DeathRecipient>* outRecipient = nullptr) = 0; } ``` * [**BpBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/BpBinder.cpp)#`unlinkToDeath` 函數: :::warning * 如果內部死亡通知列表已為空,則需要讓 BinderDriver 清除對應的通知;如果列表未空,就只從 BpBinder 內的通知列表移除 ::: ```cpp= // BpBinder.cpp status_t BpBinder::unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags, wp<DeathRecipient>* outRecipient) { ... AutoMutex _l(mLock); if (mObitsSent) { // 已發送死亡通知 return DEAD_OBJECT; // `DEAD_OBJECT` 代表 BinderServer 已死亡 } const size_t N = mObituaries ? mObituaries->size() : 0; for (size_t i=0; i<N; i++) { const Obituary& obit = mObituaries->itemAt(i); // 找尋目標要移除的 通知 if ((obit.recipient == recipient || (recipient == nullptr && obit.cookie == cookie)) && obit.flags == flags) { if (outRecipient != nullptr) { // 設定使用者傳入的指標 (已找到目標) *outRecipient = mObituaries->itemAt(i).recipient; } // 從死亡通知列表移除 mObituaries->removeAt(i); if (mObituaries->size() == 0) { ... log info if (!isRpcBinder()) { if constexpr (kEnableKernelIpc) { IPCThreadState* self = IPCThreadState::self(); // 通知 Kernel 清除死亡通知 self->clearDeathNotification(binderHandle(), this); // 立刻與 BinderDriver 交互 self->flushCommands(); } } // 列表已為空,刪除列表這個物件 delete mObituaries; mObituaries = nullptr; } return NO_ERROR; } } return NAME_NOT_FOUND; } ``` * [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/IPCThreadState.cpp)#`clearDeathNotification` 函數:請看註解 ```cpp= // IPCThreadState.cpp status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) { // 寫入指令 mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION); // 控制碼,可以透過控制碼找到對應的 ref mOut.writeInt32((int32_t)handle); // BpBinder 地址 mOut.writePointer((uintptr_t)proxy); return NO_ERROR; } ``` ### Binder kernel - 註銷死亡通知 :::info 目前在 Kernel 接收到 `BINDER_WRITE_READ` 命令,並準備處理死亡通知註冊命令 `BC_CLEAR_DEATH_NOTIFICATION` ::: * 在上面我們透過 `talkWithDriver` 對 BinderKernel 寫入 `BINDER_WRITE_READ` 命令,在裡我們直接轉跳到對應的 **處裡函數 `binder_thread_write`**,主要步驟如下 1. BinderKernel 讀取 `控制碼`、`BpBinder 地址` 2. 透過 ***控制碼*** 取得 ***binder_ref*** 3. 透過 ***binder_ref*** 取得對應的 ***binder_node*** 4. 檢查 ***death->work.entry*** 是否還有存在其它列表 * 列表為空:**將 `death->work` 加入 BinderClient 的 TODO 列表,等待 BinderClient 處理** * 列表不為空:代表 BinderServer 也死亡,將處理命令改為 `BINDER_WORK_DEAD_BINDER_AND_CLEAR` :::success * `BINDER_WORK_DEAD_BINDER_AND_CLEAR` 代表通知 Client 已清除通知 & BinderServer 已死亡 ::: ```c= static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed) { uint32_t cmd; struct binder_context *context = proc->context; void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; while (ptr < end && thread->return_error.cmd == BR_OK) { int ret; if (get_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); ... switch (cmd) { case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; binder_uintptr_t cookie; struct binder_ref *ref; struct binder_ref_death *death = NULL; // 取得 Client 寫入的 "控制碼" if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); // 跳到下個命令 // 取得 Client 寫入的 "BpBinder 地址" if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); // 跳到下個命令 ... binder_proc_lock(proc); // 透過 "控制碼" 取得 "binder_ref" ref = binder_get_ref_olocked(proc, target, false); if (ref == NULL) { ... err msg binder_proc_unlock(proc); kfree(death); break; } ... debug msg // 透過 "binder_ref" 取得對應的 binder_node binder_node_lock(ref->node); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { ... 省略 } else { // BC_CLEAR_DEATH_NOTIFICATION 處理 if (ref->death == NULL) { ... ref 中的 death 不存在 break; } death = ref->death; if (death->cookie != cookie) { ... 不同 BpBinder 對象 break; } ref->death = NULL; // 置為空 binder_inner_proc_lock(proc); // 判斷是否存在任何列表中 if (list_empty(&death->work.entry)) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; // 判斷是否有 Binder thread if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) // 加入 Client Thread 的 TODO binder_enqueue_thread_work_ilocked( thread, &death->work); else { // 加入 Client Proc 的 TODO binder_enqueue_work_ilocked( &death->work, &proc->todo); binder_wakeup_proc_ilocked( proc); } } else { ... // 清除並發送 BinderServer 的死亡通知 death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; } binder_inner_proc_unlock(proc); } binder_node_unlock(ref->node); binder_proc_unlock(proc); } break; } } } ``` ## Appendix & FAQ :::info ::: ###### tags: `Binder`