---
# System prepended metadata

title: Binder - 死亡通知
tags: [Binder]

---

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