死亡通知机制概述   

如果在 binder 通信已经建立的情况下,出现 binder 服务端的进程意外挂掉,这个挂掉的原因可能是因为进程本身内部发生的错误,也有可能是其它情况导致进程被系统强制结束,总之这个服务端进程是存在意外挂掉的可能的,如果出现这种情况,而 binder 代理端不知道的话,那么代理端继续调用不存在的服务端时肯定会出错.这个时候就需要有一种机制来通知到依赖这个服务的 binder 代理端,好让代理端作出相应的操作,以保证代理端进程不会因为 binder 服务端进程的意外挂掉而出错。这个机制就是 binder 提供的死亡通知机制。

在这种死亡通知机制中,首先是 Binder 代理对象(BpBinder)通过发送命令 BC_REQUEST_DEATH_NOTIFICATION 到驱动,告诉 Binder 驱动这个 Binder 代理对象要注册一个死亡接收通知,注册完成之后,驱动就会在对应 binder_ref 的 death 中做好标记.如果对应的 Binder 服务端的进程因为意外发生挂掉,Binder 驱动会释放掉这个服务端进程对应的 binder_proc 中 nodes 树的所有 binder_node 节点,在释放 binder_node 节点的过程中,会遍历所有引用这个节点的引用树 refs,其中 binder 代理对象在驱动中的表示 binder 引用 binder_ref 就链接在这个引用树中,这样驱动就会找到这个 binder_ref,并检查这个 binder 引用的 death 值是否为空,如果不为空则说明已经注册了死亡通知,如果为空,则说明没有注册死亡通知,这样驱动就根据 binder_ref 的 death 值来决定是否向其发送死亡通知,这个就是大体流程。

当然,如果一个 Binder 代理对象(BpBinder)不需要接收它所引用的 Binder 本地对象(BBinder)的死亡通知时,它也可以注销之前所注册的死亡接受通知。

下面我们从死亡通知的注册,注销,触发和处理四个方面分别阐述其过程,以了解其原理。最后分析下 java 层如何通过 JNI 和 native 进行通信以及使用例子。

相关代码路徑:

frameworks/base/core/java/android/os/Binder.java
frameworks/base/core/jni/android_util_Binder.cpp
frameworks/native/libs/binder/BpBinder.cpp

一 死亡通知的注册

Binder 代理对象(BpBinder)通过 linkToDeath 函数实现对死亡通知的注册,代码如下:

BpBinder.cpp

status_t BpBinder::linkToDeath(const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{Obituary ob;ob.recipient = recipient;// 具体的死亡接收通知ob.cookie = cookie; // 这个参数一般为 nullob.flags = flags; // 生成一个新的 Obituary,并赋值LOG_ALWAYS_FATAL_IF(recipient == NULL,"linkToDeath(): recipient must be non-NULL");{AutoMutex _l(mLock);//驱动是否已经发送过死亡通知,如果没有发送过则执行注册操作if (!mObitsSent) { if (!mObituaries) {//向量表不存在的话,生成新的向量表,
// 并向驱动发送注册请求,如果向量表存在的话,就不需要向驱动发送请求
// 直接把 Obituary 添加到 mObituaries 向量表中既可mObituaries = new Vector<Obituary>;if (!mObituaries) {return NO_MEMORY;}ALOGV("Requesting death notification: %p handle %d\n",
this, mHandle);getWeakRefs()->incWeak(this);IPCThreadState* self = IPCThreadState::self();
// 向mOut写入注册死亡通知的命令self->requestDeathNotification(mHandle, this);self->flushCommands();}
//把新生成的Obituary放入向量表中ssize_t res = mObituaries->add(ob);return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;}}return DEAD_OBJECT;
}

以上死亡通知的注册函数有以下几个关键变量需要注意:

mObituaries 是一个向量表,里边是 Obituary 的集合,而 Obituary 是封装了死亡接收通知 DeathRecipient 的一个对象,我们可以认为,每一个 Obituary 就代表注册了一个死亡接收通知,从代码中可以看出一个 Binder 代理对象可以注册多个死亡接收通知 Obituary,并把这些注册好的 Obituary 放到向量表 mObituaries 中。

mObitsSent 这个变量代表 Binder 驱动是否已经向 binder 代理发送了死亡通知,如果已经发送了则为1,否则为 0,如果已经发送了,则就不需要注册了,直接返回 DEAD_OBJECT。

从以上代码中还可以看到负责注册死亡通知的函数 requestDeathNotification 只会在第一次创建 mObituaries 的时候会被执行.其它情况下只需要把死亡接收通知 Obituary 直接添加到 mObituaries 中既可,不需要多次注册.也就是不管 binder 代理端调用 linkToDeath 函数多少次,实际上只会向驱动请求一次,并且是第一次的时候向驱动请求。

只向驱动请求一次的原因是 Binder 代理注册死亡通知后,驱动就已经知道了,如果服务端进程挂掉,那么我就要通知这个 Binder 代理,当 binder 代理收到死亡通知后,只需要遍历 mObituaries 向量表中的 Obituary,分别回调其中的 DeathRecipient 的 binderDied 方法既可,所以就不需要多次向 Binder 驱动重复请求了.

IPCThreadState.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);return NO_ERROR;
}

从以上代码中可以看到 requestDeathNotification 就是把 BC_REQUEST_DEATH_NOTIFICATION 命令发送到 Binder 驱动端,其中的参数是 binder 代理对象的句柄 handle,还有 binder 代理对象的地址 proxy,把这些数据填充到 mOut 中,然后整理成 binder_write_read 数据,通过 ioctl 的 BINDER_WRITE_READ 协议写入到 Binder 驱动中。其中的 BC_REQUEST_DEATH_NOTIFICATION 就是向 Binder 驱动注册死亡接收通知的命令。

接着看 binder 驱动端如何处理 BC_REQUEST_DEATH_NOTIFICATION 命令,代码如下:

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);trace_binder_command(cmd);if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);}switch (cmd) {case BC_INCREFS:case BC_ACQUIRE:case BC_RELEASE:.................case BC_REQUEST_DEATH_NOTIFICATION:case BC_CLEAR_DEATH_NOTIFICATION: {
// BpBinder对应的句柄值,用来找到驱动端对应的 binder_refuint32_t target; 
// 代理对象 BpBinder 的地址binder_uintptr_t cookie; struct binder_ref *ref;
// binder_ref 对应的死亡通知struct binder_ref_death *death = NULL;
// 从用户空间获取代理对象的句柄值if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT;ptr += sizeof(uint32_t);
// 获取代理对象的地址if (get_user(cookie, (binder_uintptr_t __user *)ptr))return -EFAULT;ptr += sizeof(binder_uintptr_t);if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {/** Allocate memory for death notification* before taking lock*/
// 给 binder_ref_death 分配地址空间death = kzalloc(sizeof(*death), GFP_KERNEL);if (death == NULL) {WARN_ON(thread->return_error.cmd !=BR_OK);thread->return_error.cmd = BR_ERROR;binder_enqueue_thread_work(thread,&thread->return_error.work);binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,"%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n",proc->pid, thread->pid);break;}}binder_proc_lock(proc);
// 根据句柄获得对应的 binder_refref = binder_get_ref_olocked(proc, target, false);if (ref == NULL) {binder_user_error("%d:%d %s invalid ref %d\n",proc->pid, thread->pid,cmd == BC_REQUEST_DEATH_NOTIFICATION ?"BC_REQUEST_DEATH_NOTIFICATION" :"BC_CLEAR_DEATH_NOTIFICATION",target);binder_proc_unlock(proc);kfree(death);break;}.......................binder_node_lock(ref->node);if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {if (ref->death) {binder_user_error(
"%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n",
proc->pid, thread->pid);binder_node_unlock(ref->node);binder_proc_unlock(proc);kfree(death);break;}binder_stats_created(BINDER_STAT_DEATH);
// 初始化 binder_ref_death 的 workINIT_LIST_HEAD(&death->work.entry);
// 把代理对象地址赋值给 death 的 cookiedeath->cookie = cookie;
// 把 binder_ref_death 赋值给 binder_ref 的 death,完成死亡通知的注册ref->death = death;
// 代理对象对应的服务端进程已经死亡(异常情况)if (ref->node->proc == NULL) {
// 修改 work type,这个代表死亡通知ref->death->work.type = BINDER_WORK_DEAD_BINDER;binder_inner_proc_lock(proc);
// 把 binder_ref_death 的 work 添加到代理端进程的等待队列 todo 中binder_enqueue_work_ilocked(&ref->death->work, &proc->todo);
// 唤醒代理端进程来处理死亡通知binder_wakeup_proc_ilocked(proc);binder_inner_proc_unlock(proc);}} else {......................}binder_node_unlock(ref->node);binder_proc_unlock(proc);} break;

从以上代码可以看到向 Binder 驱动注册死亡接收通知非常简单,其实就是新建一个 binder_ref_death 对象,把代表 Binder 代理对象的 cookie 赋值给 binder_ref_death 的 cookie,并初始化其中的 wrok,然后把 binder_ref_death 对象赋值给代理对象对应的 binder_ref 的 death 就可以了.以后 binder 驱动会根据 binder_ref 的 death 是否存在来决定是否向其发送死亡通知。

从代码中可以看到对 binder_ref 的 death 赋值完毕后,会有一个 ref->node->proc 是否为空的判断,也就是在刚注册完死亡通知后,驱动程序会立马判断服务端进程是否已经挂掉,如果已经挂掉了,那么把这个 death 的 work 赋值为 BINDER_WORK_DEAD_BINDER 并添加到代理端进程的等待队列 todo 中,并唤醒代理端进程,处理 BINDER_WORK_DEAD_BINDER 任务,这个就是处理死亡通知的事情了,后面会介绍.其中发送的 BINDER_WORK_DEAD_BINDER 就是发送死亡通知了.这个情况也是考虑到在注册死亡通知的时候,服务端进程其实已经挂掉了,虽然概率很低,但是如果不检查的话,那么注册后,后续 Binder 代理是收不到死亡通知的,这个需要注意。

struct binder_ref_death {/*** @work: worklist element for death notifications*        (protected by inner_lock of the proc that*        this ref belongs to)*/struct binder_work work;binder_uintptr_t cookie;
};

死亡接收通知的注册已经讲完了,说白了就是对 Binder 代理对象驱动层对应的 binder_ref 的 death 赋值,只要有了这个 death 值,驱动就知道这个 binder 引用 binder_ref 已经注册了死亡接收通知。这样一旦服务端进程意外挂掉的话,binder 驱动就会遍历服务端进程 binder_proc 中的 nodes 树中所有的 binder_node 节点,并对每个 binder_node 节点的 refs 链表做遍历操作,找出其中的每个依赖此 binder_node 节点的 binder_ref,然后检查 binder_ref 的 death 值,如果不为空,则就向其发送死亡通知。

二 死亡通知的注销

Binder 代理对象(BpBinder)通过 unlinkToDeath 函数实现对死亡通知的注销的,代码如下:

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;}const size_t N = mObituaries ? mObituaries->size() : 0;
// 遍历 mObituaries 查找匹配的已经注册过的 DeathRecipientfor (size_t i=0; i<N; i++) {const Obituary& obit = mObituaries->itemAt(i);if ((obit.recipient == recipient|| (recipient == NULL && obit.cookie == cookie))&& obit.flags == flags) {
// 匹配成功,找到之前已经注册过的 DeathRecipientif (outRecipient != NULL) {*outRecipient = mObituaries->itemAt(i).recipient;}mObituaries->removeAt(i); // 执行移除操作if (mObituaries->size() == 0) {
// 全部移除完毕了,才会向驱动发送清除死亡消息的命令ALOGV("Clearing death notification: %p handle %d\n", this, mHandle);IPCThreadState* self = IPCThreadState::self();self->clearDeathNotification(mHandle, this);self->flushCommands();delete mObituaries;mObituaries = NULL;}return NO_ERROR;}}return NAME_NOT_FOUND;
}

从以上代码可以看到 Binder 代理通过 unlinkToDeath 函数来注销注册过的死亡接收通知,每次执行一次注销操作,都会遍历 mObituaries 向量表,找出之前注册过的 Obituary,找到并匹配成功后,从 mObituaries 表中移除即可.当注册过的死亡通知全部被移除后,才会向 Binder 驱动发送注销死亡接收通知的命令,同注册时候一样,注销也是只向驱动发送一次注销命令.原因相同。

IPCThreadState.cpp

status_t IPCThreadState::clearDeathNotification(int32_t handle,BpBinder* proxy)
{mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);mOut.writeInt32((int32_t)handle);mOut.writePointer((uintptr_t)proxy);return NO_ERROR;
}

把 BC_CLEAR_DEATH_NOTIFICATION 命令 附带 binder 代理对象的句柄 handle 和 binder 代理对象的地址 proxy 添加到 mOut 中,然后发送给 binder 驱动,下面看驱动如何处理:

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);trace_binder_command(cmd);if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);}switch (cmd) {case BC_INCREFS:case BC_ACQUIRE:case BC_RELEASE:.................case BC_REQUEST_DEATH_NOTIFICATION:case BC_CLEAR_DEATH_NOTIFICATION: {uint32_t target;// binder 代理对象的句柄值binder_uintptr_t cookie; // binder 代理对象的地址struct binder_ref *ref;struct binder_ref_death *death = NULL;if (get_user(target, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);if (get_user(cookie, (binder_uintptr_t __user *)ptr))return -EFAULT;ptr += sizeof(binder_uintptr_t);.................binder_proc_lock(proc);
// 获取对应的 binder_refref = binder_get_ref_olocked(proc, target, false);if (ref == NULL) {......}.............................binder_node_lock(ref->node);if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {.......................} else { // 走入 BC_CLEAR_DEATH_NOTIFICATION 分支if (ref->death == NULL) {binder_user_error(
"%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n",proc->pid, thread->pid);binder_node_unlock(ref->node);binder_proc_unlock(proc);break;}death = ref->death;if (death->cookie != cookie) {......}
// 把 binder_ref 的 death 赋值为 null,实现对死亡接收通知的注销操作ref->death = NULL;binder_inner_proc_lock(proc);if (list_empty(&death->work.entry)) {death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;if (thread->looper &(BINDER_LOOPER_STATE_REGISTERED |BINDER_LOOPER_STATE_ENTERED))
// 当前线程为 binder 线程,则直接添加到当前线程的 todo 队列binder_enqueue_thread_work_ilocked(thread,&death->work);else {
// 否则添加到进程的 todo 队列binder_enqueue_work_ilocked(&death->work,&proc->todo);binder_wakeup_proc_ilocked(proc);}} else {
// 如果&death->work.entry 不为空,说明服务端进程已经死亡了,并且已经添加
// work 到进程或线程的 todo 队列了,直接修改 work type 为
// BINDER_WORK_DEAD_BINDER_AND_CLEAR 既可,不需要执行再次添加 work
// 到相关 todo 队列的操作了BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;}binder_inner_proc_unlock(proc);}binder_node_unlock(ref->node);binder_proc_unlock(proc);} break;

以上驱动对死亡接收通知的注销操作主要做了两件事情:

一)把 binder 代理对象对应的 binder 引用的 binder_ref 的 death 对象赋值为 null。这样驱动就不会再向其发送死亡通知了

二)注销后还需要把相关的消息反馈到 binder 代理端(通过添加 work 到代理端进程或线程的 todo 队列的方式),代理端需要执行一些操作,比如减少引用等操作

在把 binder_ref_death 的 work 提交到代理端进程或线程的 todo 队列的过程中,会对这个 work 进行判断,如果 work 的 entry 为空,则说明驱动还没有发送死亡通知,直接发送 BINDER_WORK_CLEAR_DEATH_NOTIFICATION 即可,如果 work 的 entry 不为空,则说明驱动已经发送死亡通知了,并且已经把 work 添加到 binder 代理端的进程或线程的 todo 队列中了,这个时候只需要修改 work type 为 BINDER_WORK_DEAD_BINDER_AND_CLEAR 即可,不需要在执行 todo 队列入队操作.正常的注销操作应该是 work 的 entry 为空,并且发送 BINDER_WORK_CLEAR_DEATH_NOTIFICATION。

接下来看代理端的 read 操作

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;int ret = 0;int wait_for_proc_work;if (*consumed == 0) {if (put_user(BR_NOOP, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);}
.....................case BINDER_WORK_DEAD_BINDER: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;
// 根据 work 找到对应的 binder_ref_deathdeath = container_of(w, struct binder_ref_death, work);if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
// 如果是单纯的 clear 操作,则向代理端发送 BR_CLEAR_DEATH_NOTIFICATION_DONE
// 命令,完成引用减少操作即可cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;else
// 如果不是单纯的 clear,则发送 BR_DEAD_BINDER,代理端执行发送死亡通知cmd = BR_DEAD_BINDER;
// death 中存储的代理端的代理对象地址,赋值给 cookiecookie = death->cookie;......if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {binder_inner_proc_unlock(proc);kfree(death);// 在驱动端 free 掉 deathbinder_stats_deleted(BINDER_STAT_DEATH);} else {
// 添加 work 到 delivered_death 中,在代理端发送死亡通知后,然后向驱动发送
// BC_DEAD_BINDER_DONE 命令,再这个命令中处理binder_enqueue_work_ilocked(w, &proc->delivered_death);/binder_inner_proc_unlock(proc);}if (put_user(cmd, (uint32_t __user *)ptr)) // 写命令到用户空间return -EFAULT;ptr += sizeof(uint32_t);if (put_user(cookie,(binder_uintptr_t __user *)ptr))
// 写 cookie 到用户空间,这个代表 binder 代理对象的地址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;
..............................
}

从以上代码可以看到先定位到 BINDER_WORK_CLEAR_DEATH_NOTIFICATION 命令,这个命令就是正常的注销操作,驱动端读取这个命令后,先设置 cmd 为BR_CLEAR_DEATH_NOTIFICATION_DONE,然后 free 掉这个 death,做后把命令和参数反馈到用户空间.接下来看用户空间对 BR_CLEAR_DEATH_NOTIFICATION_DONE 的处理过程

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 BR_ERROR:result = mIn.readInt32();break;case BR_OK:break;
.......................case BR_CLEAR_DEATH_NOTIFICATION_DONE:{BpBinder *proxy = (BpBinder*)mIn.readPointer();proxy->getWeakRefs()->decWeak(proxy);} break;...............}

很简单,就是通过读取从内核空间传过来的参数 cookie,获取 binder 代理对象 proxy,并对引用做 decWea 操作。

以上就是死亡通知的注销流程,简单总结就是 binder 代理端的 binder 代理对象发送 BC_CLEAR_DEATH_NOTIFICATION 命令,在驱动端先把 binder_ref 的 death 保存起来,然后把binder_ref 的 death 置为 null,最后把保存起来的这个 death 的 work type 修改为 BINDER_WORK_CLEAR_DEATH_NOTIFICATION,并且把这个 death 的 work 添加到代理端进程或线程的 todo 队列中。

当代理端接收到这个 work 后,会先把命令 cmd 赋值为 BR_CLEAR_DEATH_NOTIFICATION_DONE,然后 free 掉这个 binder_ref_death,最后向 binder 代理端返回,代理端在接收到这个命令后,执行对代理对象的引用做减少操作。

三 死亡通知的触发

当 Binder 服务所在的进程死亡后,会释放掉进程相关的资源,Binder 也是一种资源,也需要释放。

Binder 驱动将设备文件 /dev/binder 的释放操作方法设置为函数 binder_release,也就是释放 binder 驱动设备的时候,会回调到 binder_release 方法,这个是正常死亡的时候,然而如果是非正常死亡呢,即它没有正常关闭设备文件 /dev/binder,那么内核就会负责关闭它,这个时候也会触发函数 binder_release 的调用。因此,Binder 驱动程序只要在函数 binder_release 中释放相关 binder 资源就可以了,在释放 binder 资源的过程中,如果发现有对应的 binder_ref 引用其中的 binder_node,那么查看是否有 death 值,如果有则向其发送死亡通知,下面看详细过程

static const struct file_operations binder_fops = {.owner = THIS_MODULE,.poll = binder_poll,.unlocked_ioctl = binder_ioctl,.compat_ioctl = binder_ioctl,.mmap = binder_mmap,.open = binder_open,.flush = binder_flush,.release = binder_release,
};

接着调用 binder_release

static int binder_release(struct inode *nodp, struct file *filp)
{struct binder_proc *proc = filp->private_data;debugfs_remove(proc->debugfs_entry);binder_defer_work(proc, BINDER_DEFERRED_RELEASE);return 0;
}

binder_defer_work

static DECLARE_WORK(binder_deferred_work, binder_deferred_func);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);
}

主要操作为:把 proc 中的 deferred_work 赋值为 BINDER_DEFERRED_RELEASE,然后检查 proc 的 deferred_work_node 是否已经添加到哈希链表 binder_deferred_list 中,如果没有添加,则做添加操作,然后调用声明的 binder_deferred_func 函数执行 binder_deferred_work 工作队列

static void binder_deferred_func(struct work_struct *work)
{struct binder_proc *proc;int defer;do {mutex_lock(&binder_deferred_lock);if (!hlist_empty(&binder_deferred_list)) {proc = hlist_entry(binder_deferred_list.first,struct binder_proc, deferred_work_node);hlist_del_init(&proc->deferred_work_node);defer = proc->deferred_work;proc->deferred_work = 0;} else {proc = NULL;defer = 0;}mutex_unlock(&binder_deferred_lock);if (defer & BINDER_DEFERRED_FLUSH)binder_deferred_flush(proc);if (defer & BINDER_DEFERRED_RELEASE)binder_deferred_release(proc); /* frees proc */} while (proc);
}

从 binder_deferred_func 函数可以看到,会从 binder_deferred_list 中找到上面添加到头部的 deferred_work_node,然后根据 deferred_work_node 找到对应的 proc,最后调用 binder_deferred_release 方法进行释放资源操作

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;mutex_lock(&binder_procs_lock);hlist_del(&proc->proc_node); // 把 proc 从进程链表 procs 中删除mutex_unlock(&binder_procs_lock);mutex_lock(&context->context_mgr_node_lock);if (context->binder_context_mgr_node &&context->binder_context_mgr_node->proc == proc) {binder_debug(BINDER_DEBUG_DEAD_BINDER,"%s: %d context_mgr_node gone\n",__func__, proc->pid);
// 如果是 servicemanager 进程挂掉,则对相应的 binder_node 置为nullcontext->binder_context_mgr_node = NULL;}mutex_unlock(&context->context_mgr_node_lock);binder_inner_proc_lock(proc);/** Make sure proc stays alive after we* remove all the threads*/proc->tmp_ref++;proc->is_dead = true; // 进程标记为 deadthreads = 0;active_transactions = 0;while ((n = rb_first(&proc->threads))) {
// 遍历进程的线程树,找到每一个相关线程struct binder_thread *thread;thread = rb_entry(n, struct binder_thread, rb_node);binder_inner_proc_unlock(proc);threads++;
// 释放线程active_transactions += binder_thread_release(proc, thread);binder_inner_proc_lock(proc);}nodes = 0;incoming_refs = 0;while ((n = rb_first(&proc->nodes))) {
// 遍历进程的节点树,找到每一个相关节点struct binder_node *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);rb_erase(&node->rb_node, &proc->nodes);binder_inner_proc_unlock(proc);
// 释放节点incoming_refs = binder_node_release(node, incoming_refs);binder_inner_proc_lock(proc);}binder_inner_proc_unlock(proc);outgoing_refs = 0;binder_proc_lock(proc);while ((n = rb_first(&proc->refs_by_desc))) {
// 遍历进程的引用树,找到每一个相关引用struct binder_ref *ref;ref = rb_entry(n, struct binder_ref, rb_node_desc);outgoing_refs++;binder_cleanup_ref_olocked(ref);binder_proc_unlock(proc);
// 释放引用binder_free_ref(ref);binder_proc_lock(proc);}binder_proc_unlock(proc);// 释放进程的等待队列 todobinder_release_work(proc, &proc->todo);
// 释放进程的 delivered_deathbinder_release_work(proc, &proc->delivered_death);......binder_proc_dec_tmpref(proc);
}

此处的参数 proc 就是死亡的服务端进程,因为我们关注的是死亡通知的发送,所以我们重点关注 binder_node_release 函数,如下:

static int binder_node_release(struct binder_node *node, int refs)
{struct binder_ref *ref;int death = 0;struct binder_proc *proc = node->proc;binder_release_work(proc, &node->async_todo);binder_node_lock(node);binder_inner_proc_lock(proc);binder_dequeue_work_ilocked(&node->work);/** The caller must have taken a temporary ref on the node,*/BUG_ON(!node->tmp_refs);if (hlist_empty(&node->refs) && node->tmp_refs == 1) {binder_inner_proc_unlock(proc);binder_node_unlock(node);binder_free_node(node);return refs;}node->proc = NULL;node->local_strong_refs = 0;node->local_weak_refs = 0;binder_inner_proc_unlock(proc);spin_lock(&binder_dead_nodes_lock);hlist_add_head(&node->dead_node, &binder_dead_nodes);spin_unlock(&binder_dead_nodes_lock);hlist_for_each_entry(ref, &node->refs, node_entry) {
// 遍历 node 的引用链表 refsrefs++;/** 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_ref 的 death 为空,则跳出本次循环继续遍历binder_inner_proc_unlock(ref->proc);continue;}death++;BUG_ON(!list_empty(&ref->death->work.entry));ref->death->work.type = BINDER_WORK_DEAD_BINDER;
// death 不为空,则修改 work type,发送死亡通知// 并把 work 添加到代理端进程的 todo 队列中binder_enqueue_work_ilocked(&ref->death->work,&ref->proc->todo);// 唤醒代理端进程binder_wakeup_proc_ilocked(ref->proc);binder_inner_proc_unlock(ref->proc);}binder_debug(BINDER_DEBUG_DEAD_BINDER,"node %d now dead, refs %d, death %d\n",node->debug_id, refs, death);binder_node_unlock(node);binder_put_node(node);return refs;
}

该方法会遍历依赖该 binder_node 的所有 binder_ref, 并检查对应的 binder_ref 是否注册过死亡通知,如果注册过,这里表现为 binder_ref 的 death 不为空,则向相应的 binder_ref 所在进程的 todo 队列添加 BINDER_WORK_DEAD_BINDER 事务并唤醒代理端进程执行这个事务。

这个就是死亡通知的触发过程。

四 死亡通知的处理

在前面发送死亡通知后,数据来到了 binder 代理端驱动层的 read 线程中

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;int ret = 0;int wait_for_proc_work;if (*consumed == 0) {if (put_user(BR_NOOP, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);}......case BINDER_WORK_DEAD_BINDER: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;// 根据 work 找到对应的 binder_ref_deathdeath = container_of(w, struct binder_ref_death, work);if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;elsecmd = BR_DEAD_BINDER; // 添加死亡命令cookie = death->cookie;......if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {binder_inner_proc_unlock(proc);kfree(death);binder_stats_deleted(BINDER_STAT_DEATH);} else {
// 把 work 添加到 proc 中的 delivered_death 中binder_enqueue_work_ilocked(w, &proc->delivered_death);binder_inner_proc_unlock(proc);}
// 命令返回到用户空间if (put_user(cmd, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);
// 代理对象的地址返回到用户空间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; } break;}

数据传递到用户空间处理如下:

status_t IPCThreadState::executeCommand(int32_t cmd)
{BBinder* obj;RefBase::weakref_type* refs;status_t result = NO_ERROR;switch ((uint32_t)cmd) {case BR_ERROR:result = mIn.readInt32();break;case BR_OK:break;......case BR_DEAD_BINDER:{BpBinder *proxy = (BpBinder*)mIn.readPointer();proxy->sendObituary();mOut.writeInt32(BC_DEAD_BINDER_DONE);mOut.writePointer((uintptr_t)proxy);} break;}

从以上代码中可以看到获取 binder 代理对象 proxy 后,然后调用 binder 代理对象的 sendObituary 方法

void BpBinder::sendObituary()
{ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",this, mHandle, mObitsSent ? "true" : "false");mAlive = 0;if (mObitsSent) return; // 驱动已经发送过死亡通知,直接返回mLock.lock();Vector<Obituary>* obits = mObituaries;if(obits != NULL) {IPCThreadState* self = IPCThreadState::self();self->clearDeathNotification(mHandle, this); // 注销死亡通知self->flushCommands();mObituaries = NULL;}mObitsSent = 1; // 标记已经发送过死亡通知mLock.unlock();ALOGV("Reporting death of proxy %p for %zu recipients\n",this, obits ? obits->size() : 0U);if (obits != NULL) {const size_t N = obits->size();for (size_t i=0; i<N; i++) {
// 遍历 mObituaries 中的每个死亡接收通知对象,
// 然后回调该对象的 binderDied 方法reportOneDeath(obits->itemAt(i));}delete obits;}
}

以上 sendObituary 方法,先检查 mObituaries 是否为空,如果不为空那么注销死亡通知,这个流程在第二部分死亡通知的注销流程一样,然后把 mObitsSent 设置为1,标记驱动已经发送过死亡通知了。最后遍历 mObituaries,对其中的每个对象 Obituary 的 recipient 回调 binderDied 函数,这个函数最终会在代理端实现,作出一些操作,避免发生异常错误

void BpBinder::reportOneDeath(const Obituary& obit)
{sp<DeathRecipient> recipient = obit.recipient.promote();ALOGV("Reporting death to recipient: %p\n", recipient.get());if (recipient == NULL) return;recipient->binderDied(this);
}

以上就是死亡通知注册,注销,触发和处理的流程

下面讨论下 java 端如何注册使用死亡通知,以及数据是如何传递到 navie 端的。

先看 java 端对应的 Binder 和 BinderProxy 中对死亡通知的注册和注销接口,如下:

public class Binder implements IBinder {public void linkToDeath(DeathRecipient recipient, int flags) {}public boolean unlinkToDeath(DeathRecipient recipient, int flags) {return true;}
}final class BinderProxy implements IBinder {public native void linkToDeath(DeathRecipient recipient, int flags)throws RemoteException;public native boolean unlinkToDeath(DeathRecipient recipient,int flags);
}

当作为 Binder 服务端,则相应的两个方法实现为空,没有实现具体功能

当作为 BinderProxy 代理端,则调用 native 方法来实现相应功能,这里真正实现了注册和注销的操作。

原因也很好理解,因为注册死亡通知就是 binder 代理端的事情,和 binder 服务端没有关系。

接着看位于 ActivityManagerService 中的 AppDeathRecipient 类,这个类实现了 IBinder 的 DeathRecipient 接口,实现了其中最重要的 binderDied 方法,这个方法最终会被回调

private final class AppDeathRecipient implements IBinder.DeathRecipient {final ProcessRecord mApp;final int mPid;final IApplicationThread mAppThread;AppDeathRecipient(ProcessRecord app, int pid,IApplicationThread thread) {if (DEBUG_ALL) Slog.v(TAG, "New death recipient " + this+ " for thread " + thread.asBinder());mApp = app;mPid = pid;mAppThread = thread;}@Overridepublic void binderDied() {if (DEBUG_ALL) Slog.v(TAG, "Death received in " + this+ " for thread " + mAppThread.asBinder());synchronized(ActivityManagerService.this) {appDiedLocked(mApp, mPid, mAppThread, true);}}}

再看 AppDeathRecipient 的注册

    try {AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);thread.asBinder().linkToDeath(adr, 0);app.deathRecipient = adr;} catch (RemoteException e) {app.resetPackageList(mProcessStats);startProcessLocked(app, "link fail", processName);return false;}

可以看到 new 了一个 AppDeathRecipient,然后通过 binder 代理的 linkToDeath 方法实现对 DeathRecipient 的注册。

这个最终会调用到 jni 层

static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,jobject recipient, jint flags) // throws RemoteException
{if (recipient == NULL) {jniThrowNullPointerException(env, NULL);return;}IBinder* target = (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);if (target == NULL) {......assert(false);}LOGDEATH("linkToDeath: binder=%p recipient=%p\n", target, recipient);if (!target->localBinder()) {DeathRecipientList* list = (DeathRecipientList*)env->GetLongField(obj, gBinderProxyOffsets.mOrgue);sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient, list);
// 这个 target 就是 BpBinder 对象status_t err = target->linkToDeath(jdr, NULL, flags);if (err != NO_ERROR) {// Failure adding the death recipient, so clear its reference// now.jdr->clearReference();signalExceptionForError(env,obj, err, true /*canThrowRemoteException*/);}}
}

以上代码中有个 JavaDeathRecipient 对象被注册到 BpBinder 中,从我们之前了解到的,这个应该是一个 DeathRecipient 对象,下面看定义:

class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:JavaDeathRecipient(JNIEnv* env, jobject object,const sp<DeathRecipientList>& list): mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),mObjectWeak(NULL), mList(list){// These objects manage their own lifetimes so are responsible// for final bookkeeping.// The list holds a strong reference to this object.LOGDEATH("Adding JDR %p to DRL %p", this, list.get());list->add(this);// 将当前对象 sp 添加到列表 DeathRecipientListandroid_atomic_inc(&gNumDeathRefs);incRefsCreated(env);}void binderDied(const wp<IBinder>& who){LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this);if (mObject != NULL) {JNIEnv* env = javavm_to_jnienv(mVM);// 调用 BinderProxy 的 sendDeathNotice 方法env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,gBinderProxyOffsets.mSendDeathNotice, mObject);if (env->ExceptionCheck()) {jthrowable excep = env->ExceptionOccurred();report_exception(
env, excep,
"*** Uncaught exception returned from death notification!");}// Serialize with our containing DeathRecipientList so that we can't// delete the global ref on mObject while the list is being iterated.sp<DeathRecipientList> list = mList.promote();if (list != NULL) {AutoMutex _l(list->lock());// Demote from strong ref to weak after binderDied()// has been delivered, to allow the DeathRecipient and// BinderProxy to be GC'd if no longer needed.mObjectWeak = env->NewWeakGlobalRef(mObject);env->DeleteGlobalRef(mObject);mObject = NULL;}}}
}

再看 DeathRecipientList

class DeathRecipientList : public RefBase {List< sp<JavaDeathRecipient> > mList;Mutex mLock;public:DeathRecipientList();~DeathRecipientList();void add(const sp<JavaDeathRecipient>& recipient);void remove(const sp<JavaDeathRecipient>& recipient);sp<JavaDeathRecipient> find(jobject recipient);Mutex& lock();
// Use with care; specifically for mutual exclusion during binder death
};

DeathRecipientList 中存储的是 JavaDeathRecipient 对象。

再回到 android_os_BinderProxy_linkToDeath 函数可以看到,每调用一次 linkToDeath 函数,都会生成一个新的 JavaDeathRecipient 对象,并且保存到 DeathRecipientList 列表中,然后调用 BpBinder 代理对象的 linkToDeath 函数注册这个 JavaDeathRecipient,这样当对应服务端进程死亡的情况下,最终会调用到 JavaDeathRecipient 的 bindeDied方法,在这个方法中会回调 BinderProxy 的 sendDeathNotice 方法,如下:

private static final void sendDeathNotice(DeathRecipient recipient) {if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);try {recipient.binderDied();}catch (RuntimeException exc) {Log.w("BinderNative",
"Uncaught exception from death notification", exc);}}

最终调用到 recipient 的 binderDied 方法,这个 recipient 就是前面的 AppDeathRecipient。

至此 binder 的死亡通知机制全部阐述完毕,各位读者如有不同意见望不吝指出,感谢感谢。

Binder系列11 死亡通知机制相关推荐

  1. Binder对象死亡通知机制

    本文参考<Android系统源代码情景分析>,作者罗升阳. 一.Binder库(libbinder)代码: ~/Android/frameworks/base/libs/binder -- ...

  2. 1.11 等待通知机制wait和notify的使用,简单的生产者消费者

    能够运行的代码,简单的生产者和消费者代码 备注:我自己写的时候,总是把在不同的对象上面调用,所以导致一直报错,下面会有报错代码 1)通过synchronized获取对象的锁,一定要有synchroni ...

  3. Binder系列1 Binder总体设计思想

    Binder 是 Android 系统进程间通信(IPC)最主要的一种方式.Linux 已经拥有管道,system V IPC,socket 等 IPC 手段,Android 却还要使用专门的 Bin ...

  4. 使用匿名binder实现client向server端的死亡通知

    一.引言 因为binder是跨进程通信,难免会遇到服务端出现异常挂死的情况,这个时候需要通知到客户端进行相应的处理,在网络通信中是非常常见的机制,当然,在binder中,Android也为我们写好了相 ...

  5. Java并发编程系列18:多线程之生产者和消费者模式_信号灯法(wait/notify通知机制)

    1.生产者消费者模式 生产者消费者问题(Producer-consumer problem),也称为有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题 ...

  6. 【Binder系列课】二、Binder通信服务应知应会

    Binder问答 概括Binder机制 1.整体业务层CS架构,BpBinder/BnBinder 2.通信层Binder驱动,writeStrongBinder/readStrongBinder完成 ...

  7. 超强图文|并发编程【等待/通知机制】就是这个feel~

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If ...

  8. spring事件通知机制详解

    优势 解耦 对同一种事件有多种处理方式 不干扰主线(main line) 起源 要讲spring的事件通知机制,就要先了解一下spring中的这些接口和抽象类: ApplicationEventPub ...

  9. PHP观察者通知机制,观察者模式-通知详解

    观察者模式也叫发布/订阅模式,是软件设计模式中的一种.在这种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知.这通常透过呼叫各观察者所提供的方法来实现.此种模式通 ...

最新文章

  1. torch.Tensor和torch.tensor的区别
  2. java 代码性能优化_Java代码性能优化(四)
  3. I Hate It (HDU 1754)
  4. 十分钟学会制作一个漂亮的在线文档
  5. linux挂载时间3秒,linux基础学习(十一) 时间的同步 设备的挂载
  6. 计算机基础思维导图_超级简单的实操示范,教你零基础带孩子玩转风靡全球的思维导图...
  7. 调整单元格宽度无法生效的问题
  8. selenium之时间日期控件的处理
  9. Feign如何针对单个服务屏蔽Hystrix熔断功能
  10. SQL语句:查询语句及多表查询典型例子
  11. 中国省市县地区代码一览表
  12. 网站刷IP?活不过三秒
  13. 计算机的磁盘管理在哪,磁盘管理器在哪
  14. AI-人工智能 easyAi开发技术
  15. Android插件化方式实现View动态更新
  16. PLC无线通讯方案,支持西门子,三菱,欧姆龙,台达等各品牌PLC
  17. 我奋斗了10年才能和你坐在一起喝咖啡
  18. Python几种主流框架,知道三种你就是大神,干货建议收藏
  19. 计算机怎么删除证书,win7电脑如何删除过期IE证书
  20. C++中virtual(虚函数)的用法

热门文章

  1. 音视频常见的问题,绿屏,灰屏,部分花屏,黑屏
  2. Linux gizp、bzip2、tar详解
  3. SQL注入防御之二——注入关键词过滤(PHP)
  4. iOS xib 点击事件未响应
  5. ORACLE的工作机制
  6. Canal监听阿里云RDS Mysql踩坑
  7. excel文件的数据筛选和数据匹配
  8. 输入任意一个三位数字,将其各位数字反序输出(例如,输入123,输出321)。
  9. 九州云腾双因素认证系统_“等保2.0”新标准落地 双因子认证(2FA)成标配...
  10. 不懂的各类名词,以及学到的方法