赞
踩
如果在 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; // 这个参数一般为 null
- ob.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_ref
- uint32_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_ref
- ref = 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 的 work
- INIT_LIST_HEAD(&death->work.entry);
- // 把代理对象地址赋值给 death 的 cookie
- death->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 查找匹配的已经注册过的 DeathRecipient
- for (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) {
- // 匹配成功,找到之前已经注册过的 DeathRecipient
- if (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_ref
- ref = 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_death
- death = 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 中存储的代理端的代理对象地址,赋值给 cookie
- cookie = death->cookie;
-
- ......
- if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
- binder_inner_proc_unlock(proc);
- kfree(death);// 在驱动端 free 掉 death
- binder_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 置为null
- context->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; // 进程标记为 dead
- threads = 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);
-
- // 释放进程的等待队列 todo
- binder_release_work(proc, &proc->todo);
- // 释放进程的 delivered_death
- binder_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 的引用链表 refs
- 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_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_death
- death = container_of(w, struct binder_ref_death, work);
- if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
- cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
- else
- cmd = 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;
- }
-
- @Override
- public 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 添加到列表 DeathRecipientList
-
- android_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 的死亡通知机制全部阐述完毕,各位读者如有不同意见望不吝指出,感谢感谢。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。