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