如果在 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& 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;
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& recipient, void* cookie, uint32_t flags,
wp* outRecipient)
{
AutoMutex _l(mLock);
if (mObitsSent) { // 已经发送过死亡通知了直接返回
return DEAD_OBJECT;
}
const size_t N = mObituaries ? mObituaries->size() : 0;
// 遍历 mObituaries 查找匹配的已经注册过的 DeathRecipient
for (size_t i=0; iitemAt(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* 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; iitemAt(i));
}
delete obits;
}
}
以上 sendObituary 方法,先检查 mObituaries 是否为空,如果不为空那么注销死亡通知,这个流程在第二部分死亡通知的注销流程一样,然后把 mObitsSent 设置为1,标记驱动已经发送过死亡通知了。最后遍历 mObituaries,对其中的每个对象 Obituary 的 recipient 回调 binderDied 函数,这个函数最终会在代理端实现,作出一些操作,避免发生异常错误
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp 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 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& 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& 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 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 > mList;
Mutex mLock;
public:
DeathRecipientList();
~DeathRecipientList();
void add(const sp& recipient);
void remove(const sp& recipient);
sp 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 的死亡通知机制全部阐述完毕,各位读者如有不同意见望不吝指出,感谢感谢。