Binder系列11 死亡通知机制

死亡通知机制概述   

如果在 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 的死亡通知机制全部阐述完毕,各位读者如有不同意见望不吝指出,感谢感谢。

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值