Android binder死亡通知机制

发布于:2024-05-02 ⋅ 阅读:(26) ⋅ 点赞:(0)

在Andorid 的binder系统中,当Bn端由于种种原因死亡时,需要通知Bp端,Bp端感知Bn端死亡后,做相应的处理。

使用
Bp需要先注册一个死亡通知,当Bn端死亡时,回调到Bp端。

1,java代码注册死亡通知

try {
	binder.asBinder().linkToDeath(new IBinder.DeathRecipient() {
	@Override
		public void binderDied() {
			//处理
		}
	},0);
} catch (RemoteException e) {
	e.printStackTrace();
}

2,c++代码注册死亡通知

	// Create the death listener.
	class DeathObserver : public IBinder::DeathRecipient {
		 void binderDied(const wp<IBinder>& who) {
		 	//处理
			ALOGD("service is died\n");
		}
	};
	sp<IBinder::DeathRecipient> mDeathObserver = new DeathObserver();
	sp<IBinder> binder = sm->getService(String16("xxx"));//获取一个BpBinder对象
	if(binder->linkToDeath(mDeathObserver) != NO_ERROR){
		ALOGE("link to death failed");
	}else{
		ALOGE("link to death sucess");
	}

当Bn端死亡时,回调binderDied方法

注册死亡通知分析
从上面可以看出来,Bp端通过linkToDeath方法注册死亡通知。我们从java端的linkToDeath开始分析。
binder.asBinder返回的是一个BinderProxy对象

//frameworks\base\core\java\android\os\Binder.java
public native void linkToDeath(DeathRecipient recipient, int flags)
            throws RemoteException;

这是一个native方法,对应android_os_BinderProxy_linkToDeath方法

//frameworks\base\core\jni\android_util_Binder.cpp
static const JNINativeMethod gBinderProxyMethods[] = {
     /* name, signature, funcPtr */
   	//省略
    {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
  	//省略
};

继续来看一下android_os_BinderProxy_linkToDeath方法

//frameworks\base\core\jni\android_util_Binder.cpp
static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
        jobject recipient, jint flags) // throws RemoteException
{
    //省略
    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);//取出native层的 BpBinder对象
    
	//省略

    if (!target->localBinder()) {//只有Bp端才可以注册死亡通知
        DeathRecipientList* list = (DeathRecipientList*)
                env->GetLongField(obj, gBinderProxyOffsets.mOrgue);//1
        sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient, list);//2
        status_t err = target->linkToDeath(jdr, NULL, flags);//3
        //省略
    }
}

注释1处取出DeathRecipientList对象,DeathRecipientList对象中有一个集合

//frameworks\base\core\jni\android_util_Binder.cpp
class DeathRecipientList : public RefBase {
    List< sp<JavaDeathRecipient> > mList;
    Mutex mLock;

注释2处新建一个JavaDeathRecipient对象,并将其加入到上面的集合中

//frameworks\base\core\jni\android_util_Binder.cpp
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);//加到集合中

        android_atomic_inc(&gNumDeathRefs);
        incRefsCreated(env);
    }

注释3处target为BpBinder对象,继续来看BpBinder的linkToDeath方法

//frameworks\native\libs\binder\BpBinder.cpp
status_t BpBinder::linkToDeath(
    const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
	/*构造Obituary 对象*/
    Obituary ob;
    ob.recipient = recipient;
    ob.cookie = cookie;
    ob.flags = flags;

    LOG_ALWAYS_FATAL_IF(recipient == NULL,
                        "linkToDeath(): recipient must be non-NULL");

    {
        AutoMutex _l(mLock);

        if (!mObitsSent) {//mObitsSent默认为0,可以看出只会发送一次死亡通知
            if (!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();
                self->requestDeathNotification(mHandle, this);//1
                self->flushCommands();//2
            }
            ssize_t res = mObituaries->add(ob);//3
            return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
        }
    }

    return DEAD_OBJECT;
}

注释1处封装数据

//frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
    mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);//注意:cmd为BC_REQUEST_DEATH_NOTIFICATION
    mOut.writeInt32((int32_t)handle);
    mOut.writePointer((uintptr_t)proxy);//这个proxy是前面的BpBinder对象
    return NO_ERROR;
}

注释2处将数据写给binder驱动

//frameworks\native\libs\binder\IPCThreadState.cpp
void IPCThreadState::flushCommands()
{
    if (mProcess->mDriverFD <= 0)
        return;
    talkWithDriver(false);//通过ioctl写给驱动
}

注释3处将前面构造好的Obituary 添加到集合中,该Obituary对象的recipient 成员指向我们前面传入的JavaDeathRecipient对象。
binder驱动开始处理,注意cmd为BC_REQUEST_DEATH_NOTIFICATION

//kernel\drivers\android\binder.c
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
	uint32_t target;
	binder_uintptr_t cookie;
	struct binder_ref *ref;
	struct binder_ref_death *death = NULL;
	if (get_user(target, (uint32_t __user *)ptr))//从用户空间取出handle
				return -EFAULT;
	ptr += sizeof(uint32_t);
	if (get_user(cookie, (binder_uintptr_t __user *)ptr))//从用户空间取出BpBinder对象地址
				return -EFAULT;
	ptr += sizeof(binder_uintptr_t);
	if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
		death = kzalloc(sizeof(*death), GFP_KERNEL);//申请binder_ref_death空间
		//省略			
	}
	binder_proc_lock(proc);
	ref = binder_get_ref_olocked(proc, target, false);//根据handle,找到binder_ref
	//省略
	if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
		binder_stats_created(BINDER_STAT_DEATH);
		INIT_LIST_HEAD(&death->work.entry);
		death->cookie = cookie;//将BpBinder对象地址保存在death的cookie 中
		ref->death = death;//将death保存在binder_ref的death 成员中
		if (ref->node->proc == NULL) {//注册的时候,Bn端刚好死亡,一般不太可能
			ref->death->work.type = BINDER_WORK_DEAD_BINDER;

			binder_inner_proc_lock(proc);
			binder_enqueue_work_ilocked(&ref->death->work, &proc->todo);
					binder_wakeup_proc_ilocked(proc);
					binder_inner_proc_unlock(proc);
		}
	}
	//省略

对于注册死亡通知时驱动的处理上面的注释已经说的很清楚。主要是将BpBinder对象地址保存在binder_ref的binder_ref_death 结构体中,这里只是做了保存,我们还没有看到死亡通知到底是如何触发的呢,即binderDied是如何被调用到的?接下来我们就来看一下死亡通知的触发
死亡通知触发分析
当Bn端死亡时,就要开始释放资源,调用binder_release,从这个方法开始分析

//kernel\drivers\android\binder.c
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,注意这个proc还是当前进程即Bn端所处的进程,第二个参数为BINDER_DEFERRED_RELEASE

//kernel\drivers\android\binder.c
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);
		queue_work(binder_deferred_workqueue, &binder_deferred_work);//1
	}
	mutex_unlock(&binder_deferred_lock);
}

注释1处开始执行工作队列,对于binder_deferred_work,则是执行binder_deferred_func函数

//kernel\drivers\android\binder.c
static void binder_deferred_func(struct work_struct *work)
{
	struct binder_proc *proc;
	struct files_struct *files;

	int defer;

	do {
		
		//省略

		if (defer & BINDER_DEFERRED_RELEASE)
			binder_deferred_release(proc); /* frees proc */

		if (files)
			put_files_struct(files);
	} while (proc);
}

对于BINDER_DEFERRED_RELEASE,调用binder_deferred_release继续处理

//kernel\drivers\android\binder.c
static void binder_deferred_release(struct binder_proc *proc)
{
	struct binder_context *context = proc->context;
	struct rb_node *n;
	int threads, nodes, incoming_refs, outgoing_refs, active_transactions;

	BUG_ON(proc->files);

	mutex_lock(&binder_procs_lock);
	hlist_del(&proc->proc_node);//删除proc_node节点
	mutex_unlock(&binder_procs_lock);

	mutex_lock(&context->context_mgr_node_lock);
	/*如果是servicemanager死亡,则删除context->binder_context_mgr_node*/
	if (context->binder_context_mgr_node &&
	    context->binder_context_mgr_node->proc == proc) {
		//省略
	}
	mutex_unlock(&context->context_mgr_node_lock);
	binder_inner_proc_lock(proc);

	proc->tmp_ref++;

	proc->is_dead = true;
	threads = 0;
	active_transactions = 0;
	/*删除binder_thread*/
	while ((n = rb_first(&proc->threads))) {
		//省略
	}

	nodes = 0;
	incoming_refs = 0;
	/*删除binder_node*/
	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);//1
		binder_inner_proc_lock(proc);
	}
	binder_inner_proc_unlock(proc);

	outgoing_refs = 0;
	binder_proc_lock(proc);
	/*删除binder_ref*/
	while ((n = rb_first(&proc->refs_by_desc))) {
		//省略
	}
	binder_proc_unlock(proc);

	binder_release_work(proc, &proc->todo);
	binder_release_work(proc, &proc->delivered_death);

	binder_debug(BINDER_DEBUG_OPEN_CLOSE,
		     "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n",
		     __func__, proc->pid, threads, nodes, incoming_refs,
		     outgoing_refs, active_transactions);

	binder_proc_dec_tmpref(proc);

binder_deferred_release方法里面还是做了很多事情的,上面注释也已经说的很清楚。我们继续来看一下注释1处的binder_node_release方法

//kernel\drivers\android\binder.c
static int binder_node_release(struct binder_node *node, int refs)
{
	//省略
	hlist_for_each_entry(ref, &node->refs, node_entry) {
		refs++;
		binder_inner_proc_lock(ref->proc);
		if (!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;
		binder_enqueue_work_ilocked(&ref->death->work,
					    &ref->proc->todo);
		binder_wakeup_proc_ilocked(ref->proc);
		binder_inner_proc_unlock(ref->proc);
	}
	
	//省略

}

取出node中的binder_ref,如果binder_ref中有注册过死亡通知,则添加到Bp端的进程的todo两边,唤醒Bp端进程。注意work的type为BINDER_WORK_DEAD_BINDER。Bp端进程被唤醒,Bp端进程开始处理BINDER_WORK_DEAD_BINDER这个type。注意现在是运行在Bp端所在的进程

//kernel\drivers\android\binder.c
static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{
	//省略
	case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
			struct binder_ref_death *death;
			uint32_t cmd;
			binder_uintptr_t cookie;

			death = container_of(w, struct binder_ref_death, work);//取出binder_ref中的binder_ref_death
			if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
				cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
			else
				cmd = BR_DEAD_BINDER;//传给用户空间的cmd为BR_DEAD_BINDER
			cookie = death->cookie;//取出cookie,这个cookie就是之前注册时的BpBinder对象

			if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
				//省略
			} else {
				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; /* DEAD_BINDER notifications can cause transactions */
		} break;
}

经过上面的处理,Bp端进程的用户空间就会得到cmd为BR_DEAD_BINDER的命令。Bp端进程是在executeCommand方法中处理命令的

//frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
	//省略
	case BR_DEAD_BINDER:
        {
            BpBinder *proxy = (BpBinder*)mIn.readPointer();//1
            proxy->sendObituary();//2
            mOut.writeInt32(BC_DEAD_BINDER_DONE);
            mOut.writePointer((uintptr_t)proxy);
        } break;
    //省略    

}

注释1处取出驱动传过来的BpBinder对象,注释2处调用BpBinder的sendObituary方法

//frameworks\native\libs\binder\BpBinder.cpp
void BpBinder::sendObituary()
{
    mAlive = 0;
    if (mObitsSent) return;

    mLock.lock();
    Vector<Obituary>* obits = mObituaries;
    /*首先先向驱动发送清楚这个死亡通知的事件*/
    if(obits != NULL) {
        ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
        IPCThreadState* self = IPCThreadState::self();
        self->clearDeathNotification(mHandle, this);
        self->flushCommands();
        mObituaries = NULL;
    }
    mObitsSent = 1;
    mLock.unlock();

    if (obits != NULL) {
        const size_t N = obits->size();
        for (size_t i=0; i<N; i++) {
            reportOneDeath(obits->itemAt(i));//1
        }

        delete obits;
    }
}

注释1处,从mObituaries取出一个个的Obituary对象,然后执行reportOneDeath方法。还记得之前在注册死亡通知时,将我们的recipient封装在了Obituary对象中了。继续来看reportOneDeath方法

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);
}

这里取出我们的recipient对象,调用其binderDied方法。如果是C++注册的死亡通知,那C++层的binderDied就得到执行了。我们接下来看看是如何调用到java端的binderDied方法。对于java端,我们之前传入的是JavaDeathRecipient对象,所以接在看JavaDeathRecipient的binderDied方法

//frameworks\base\core\jni\android_util_Binder.cpp
void binderDied(const wp<IBinder>& who)
    {
        LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this);
        if (mObject != NULL) {
            JNIEnv* env = javavm_to_jnienv(mVM);

            env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
                    gBinderProxyOffsets.mSendDeathNotice, mObject);//调用BinderProxy的sendDeathNotice方法
          //省略
        }
    }

调用BinderProxy的sendDeathNotice方法,传入的mObject为之前我们注册时传入的DeathRecipient对象

//frameworks\base\core\java\android\os\Binder.java
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);
        }
    }

可以看出,调用binderDied,之前注册的死亡通知得以执行。Bp端就感知到了Bn端的死亡

总结
死亡通知机制包含Bp端注册死亡通知以及Bn端死亡时触发死亡通知,用一张图来总结下其流程

在这里插入图片描述