Binder对象死亡通知机制

本文参考《Android系统源代码情景分析》,作者罗升阳。

一、Binder库(libbinder)代码:

       ~/Android/frameworks/base/libs/binder

       ----BpBinder.cpp

       ----Parcel.cpp

       ----ProcessState.cpp

       ----Binder.cpp

       ----IInterface.cpp

       ----IPCThreadState.cpp

       ----IServiceManager.cpp

       ----Static.cpp

       ~/Android/frameworks/base/include/binder

       ----Binder.h

       ----BpBinder.h

       ----IInterface.h

       ----IPCThreadState.h

       ----IServiceManager.h

       ----IBinder.h

       ----Parcel.h

       ----ProcessState.h


        驱动层代码:

       ~/Android//kernel/goldfish/drivers/staging/android

       ----binder.c

       ----binder.h


二、总体概述

     如果Binder本地对象意外死亡,会导致依赖于它的Binder代理对象变得无效。

     我们将分析Binder对象死亡通知机制,它可以监控到Binder本地对象的死亡事件,然后通知那些引用了它的Binder代理对象,从而在一定程度上解决无效Binder代理对象的问题。

     在这种死亡机制中,首先是Binder代理对象将一个死亡接收通知注册到Binder驱动程序中,然后当Binder驱动程序监控到它所引用的Binder本地对象死亡时,Binder驱动程序就会向它发送一个死亡通知。

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


三、注册死亡通知

     Binder代理对象在注册它所引用的Binder本地对象的死亡接受通知之前,首先要定义好死亡通知接受者。Binder库定义了死亡通知接受者必须要继承的基类DeathRecipient,它的实现如下所示:

     ~/Android/frameworks/base/include/binder

     ----IBinder.h

class IBinder : public virtual RefBase
{
public:
   
    class DeathRecipient : public virtual RefBase
    {
    public:
        virtual void binderDied(const wp<IBinder>& who) = 0;//重写父类DeathRecipient的成员函数binderDied
    };

    ......
};
     自定义的死亡通知接受者必须要重写父类DeathRecipient的成员函数binderDied。当Binder驱动程序通知一个Binder代理对象它所引用的Binder本地对象已经死亡时,就会调用它所指定的死亡通知接受者的成员函数binderDied。

     

     定义好死亡通知接受者之后,我们就可以调用Binder代理对象的成员函数linkToDeath来注册一个死亡接受通知了。实现如下:

     ~/Android/frameworks/base/libs/binder

      ----BpBinder.cpp

status_t BpBinder::linkToDeath(
    const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
    Obituary ob;
    ob.recipient = recipient;
    ob.cookie = cookie;//用来标识死亡接受者
    ob.flags = flags;//用来标识死亡接受者

    ......

    {
        AutoMutex _l(mLock);

        if (!mObitsSent) {//mObitsSent用来表示Binder驱动程序是否已经向它发送过死亡通知,如果是,直接返回DEAD_OBJECT
            if (!mObituaries) {//第一次注册
                mObituaries = new Vector<Obituary>;//初始化卟告列表
                if (!mObituaries) {
                    return NO_MEMORY;
                }
                LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
                getWeakRefs()->incWeak(this);//增加了弱引用计数
                IPCThreadState* self = IPCThreadState::self();
                self->requestDeathNotification(mHandle, this);//调用requestDeathNotification
                self->flushCommands();//促使当前线程马上通过IO控制命令BINDER_WRITE_READ进入到Binder驱动程序中,以便可以执行注册死亡接受通知的操作
            }
            ssize_t res = mObituaries->add(ob);//非第一个注册,直接加入到卟告列表中
            return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
        }
    }

    return DEAD_OBJECT;
}
     该函数第一个参数为自定义的死亡通知接受者,第二个参数cookie和第三个参数flags也是用来标志一个死亡通知接受者的,在注销死亡接受通知时会用到。

     我们可以为一个Binder代理对象同时注册多个死亡通知接受者,它们保存在Binder代理对象内部的一个卟告列表mObituaries中。

     Binder代理对象内部的成员变量mObitsSent用来表示Binder驱动程序是否已经向它发送过死亡通知,如果是,这个成员变量的值就等于1,在这种情况下,Binder代理对象的成员函数linkToDeath就会直接返回一个DEAD_OBJECT值,表示对应的Binder本地对象已经死亡了。

     如果mObitsSent的值等于0,那么成员函数linkToDeath首先将死亡通知接受者封装成一个Obituary对象,接着将它添加到内部的卟告列表mObituaries中。如果是第一次注册,那么函数会调用当前线程中的IPCThreadState对象的成员函数requestDeathNotification,它的实现如下:
     ~/Android/frameworks/base/libs/binder
     ----IPCThreadState.cpp

status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
    mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
    mOut.writeInt32((int32_t)handle);//Binder代理对象的句柄值
    mOut.writeInt32((int32_t)proxy);//Binder代理对象的地址值
    return NO_ERROR;
}
     传递了三个参数,第一个是命令,第二个是Binder代理对象的句柄值,第三个参数是Binder代理对象的地址值。

 

      回到Binder代理对象的成员函数linkToDeath中,接下来就会调用当前线程的IPCThreadState对象的成员函数flushCommands促使当前线程马上通过IO控制命令BINDER_WRITE_READ进入到Binder驱动程序中,以便可以执行注册死亡接受通知的操作。
     ~/Android/frameworks/base/libs/binder
     ----IPCThreadState.cpp

void IPCThreadState::flushCommands()
{
    if (mProcess->mDriverFD <= 0)
        return;
    talkWithDriver(false);
}
     进入到Binder驱动程序之后,函数binder_thread_write就会被调用来处理BC_REQUEST_DEATH_NOTIFICATION协议,如下:

     ~/Android//kernel/goldfish/drivers/staging/android

      ---binder.c

int
binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
		    void __user *buffer, int size, signed long *consumed)
{
	uint32_t cmd;
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;

	while (ptr < end && thread->return_error == BR_OK) {
		if (get_user(cmd, (uint32_t __user *)ptr))
			return -EFAULT;
		ptr += sizeof(uint32_t);
		.......
		switch (cmd) {//BC_REQUEST_DEATH_NOTIFICATION
		.......

		case BC_REQUEST_DEATH_NOTIFICATION:
		case BC_CLEAR_DEATH_NOTIFICATION: {
			uint32_t target;
			void __user *cookie;
			struct binder_ref *ref;
			struct binder_ref_death *death;

			if (get_user(target, (uint32_t __user *)ptr))//Binder代理对象的句柄值
				return -EFAULT;
			ptr += sizeof(uint32_t);
			if (get_user(cookie, (void __user * __user *)ptr))//Binder代理对象的地址值
				return -EFAULT;
			ptr += sizeof(void *);
			ref = binder_get_ref(proc, target);//根据句柄值target得到一个Binder引用对象ref
			if (ref == NULL) {
				.....
				break;
			}

			......

			if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
				if (ref->death) {//为NULL
					binder_user_error("binder: %d:%"
						"d BC_REQUEST_DEATH_NOTI"
						"FICATION death notific"
						"ation already set\n",
						proc->pid, thread->pid);
					break;
				}
				death = kzalloc(sizeof(*death), GFP_KERNEL);//分配一个binder_ref_death结构体
				if (death == NULL) {
					......
				}
				.......
				INIT_LIST_HEAD(&death->work.entry);//初始化成员变量work
				death->cookie = cookie;//Binder代理对象的地址值
				ref->death = death;//将它保存在Binder引用对象ref的成员变量death中
				if (ref->node->proc == NULL) {//正在注册的Binder引用对象所引用的Binder本地对象已经死亡了
					ref->death->work.type = BINDER_WORK_DEAD_BINDER;//将一个类型为BINDER_WORK_DEAD_BINDER的工作项添加到当前线程或者当前线程所在的Client进程的todo队列中,以便可以向Client进程发送一个死亡接受通知
					if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
						list_add_tail(&ref->death->work.entry, &thread->todo);//Binder线程
					} else {
						list_add_tail(&ref->death->work.entry, &proc->todo);//不是一个Binder线程
						wake_up_interruptible(&proc->wait);
					}
				}
			} else {
				.......
			}
		} break;
		......
		*consumed = ptr - buffer;
	}
	return 0;
}
     分别将Client进程传进来的Binder代理独象的句柄值和地址值保存在变量target和cookie中,然后根据句柄值target得到一个Binder引用对象ref。如果ref的成员变量death为NULL,那么创建一个binder_ref_death结构体,接着将用户空间传过来的参数cookie保存在它的成员变量cookie中,最后再将它保存在Binder引用对象ref的成员变量death中。

      死亡接受通知的注册操作就完成了。但是可能会出现这样一种情况,即正在注册的Binder引用对象所引用的Binder本地对象已经死亡了。这时候驱动程序就需要马上向Client进程发送一个死亡接受通知;否则,以后就没有机会发送这个通知了。现在的问题是,如何判断一个Binder引用对象所引用的Binder本地对象已经死亡了呢?一个Binder引用对象所引用的Binder实体对象保存在它的成员变量node中,而一个Binder实体对象的宿主进程结构体为NULL,那么就说明它所引用的Binder本地对象已经死亡了,因为它所在的进程已经不存在了。

      在正在注册的Binder引用对象所引用的Binder本地对象已经死亡了这种情况下(一般出现在第一次注册,如果第二次注册,如果本地对象死亡,会直接返回DEAD_OBJECT),将一个类型为BINDER_WORK_DEAD_BINDER的工作项添加到当前线程或者当前线程所在的Client进程的todo队列中,以便可以向Client进程发送一个死亡接受通知。

      如果当前线程是Binder线程,这时候就可以将一个死亡接受通知就近发送给它处理了。如果当前线程不是一个Binder线程,那么Binder驱动程序就会将发送死亡接受通知的工作项添加到Client进程的todo队列中,等待其他的Binder线程来处理。
    

四、发送死亡接收通知

     Server进程本来是应该常驻在系统中为Client进程提供服务的,但是可能会出现意外情况,导致它异常退出,Server进程一旦异常退出之后,运行在它里面的Binder本地对象就意外死亡了。这时候Binder驱动程序就应该向那些引用了它的Binder代理对象发送死亡接受通知,以便它们可以知道自己引用了一个无效的Binder本地对象。

     现在的关键问题是,Binder驱动程序是如何知道一个Server进程退出运行了呢?Binder驱动程序将设备文件/dev/binder的释放操作方法设置为函数binder_release。Server进程在启动时,会调用函数open来打开设备文件/dev/binder。一方面,在正常情况下,它退出时会调用函数close来关闭设备文件/dev/binder,这时候就会触发函数binder_releasse被调用;另一方面,如果Server进程异常退出,即它没有正常关闭设备文件/dev/binder,那么内核就会负责关闭它,这个时候也会触发函数binder_release被调用。因此,Binder驱动程序就可以在函数binder_release中检查进程退出时,是否有Binder本地对象在里面运行。如果有,就说明它们是死亡了的Binder本地对象了。


    binder_release实现如下:

    ~/Android//kernel/goldfish/drivers/staging/android

     ---binder.c

static int binder_release(struct inode *nodp, struct file *filp)
{
	struct binder_proc *proc = filp->private_data;
	if (binder_proc_dir_entry_proc) {
		char strbuf[11];
		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		remove_proc_entry(strbuf, binder_proc_dir_entry_proc);
	}

	binder_defer_work(proc, BINDER_DEFERRED_RELEASE);
	
	return 0;
}
      首先将之前为进程在/proc/binder/proc目录中创建的文件删除。由于检查进程中是否有Binder本地对象,以及资源释放操作都比较耗时,因此调用函数binder_defer_work将一个BINDER_DEFERRED_RELEASE类型的延迟操作添加到一个全局的hash列表中。

      BINDER_DEFERRED_RELEASE类型的延迟操作最终是由函数binder_deferred_release来执行的。

     ~/Android//kernel/goldfish/drivers/staging/android

      ---binder.c

static void binder_deferred_release(struct binder_proc *proc)
{
	struct hlist_node *pos;
	......
	nodes = 0;
	incoming_refs = 0;
	while ((n = rb_first(&proc->nodes))) {
		struct binder_node *node = rb_entry(n, struct binder_node, rb_node);//检查目标进程proc的Binder实体对象列表nodes的每一个Binder实体对象

		......
		if (hlist_empty(&node->refs)) {
			.....
		} else {
			struct binder_ref *ref;
			.....

			hlist_for_each_entry(ref, pos, &node->refs, node_entry) {//得到这些Binder实体对象的Binder引用对象列表refs
				........
				if (ref->death) {//如果注册过死亡接受通知
					......
					if (list_empty(&ref->death->work.entry)) {
						ref->death->work.type = BINDER_WORK_DEAD_BINDER;//将一个BINDER_WORK_DEAD_BINDER类型的工作项添加到对应的Client进程的todo队列中
						list_add_tail(&ref->death->work.entry, &ref->proc->todo);
						wake_up_interruptible(&ref->proc->wait);//来唤醒这些Client进程来处理这些死亡接受通知
					} else
						BUG();
				}
			}
			.....
		}
	}
	......
    while循环检查目标进程proc的Binder实体对象列表nodes的每一个Binder实体对象,如果这些Binder实体对象的Binder引用对象列表refs不为空,就检查这些Binder引用对象对应的Binder代理对象注册过死亡接受通知。如果注册过死亡接受通知,那么就将一个BINDER_WORK_DEAD_BINDER类型的工作项添加到对应的Client进程的todo队列中,并调用函数wake_up_interruptible来唤醒这些Client进程来处理这些死亡接受通知。


    Client进程中的Binder线程在空闲时,会睡眠在Binder驱动程序的函数binder_thread_read中,因此,当它们被唤醒之后,就会继续执行函数binder_thread_read,并且检查自己以及宿主进程的todo队列,看看有没有工作项要处理。

     ~/Android//kernel/goldfish/drivers/staging/android

      ---binder.c

static int
binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,
	void  __user *buffer, int size, signed long *consumed, int non_block)
{
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;
        .........

	while (1) {
		uint32_t cmd;
		..... 
		struct binder_work *w;
		.....

		if (!list_empty(&thread->todo))
			w = list_first_entry(&thread->todo, struct binder_work, entry);
		else if (!list_empty(&proc->todo) && wait_for_proc_work)
			w = list_first_entry(&proc->todo, struct binder_work, entry);
		else {
			..........
		}

		......

		switch (w->type) {
		......
		case BINDER_WORK_DEAD_BINDER:
		case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
		case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
			struct binder_ref_death *death = container_of(w, struct binder_ref_death, work);
			uint32_t cmd;
			if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
				cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
			else
				cmd = BR_DEAD_BINDER;
			if (put_user(cmd, (uint32_t __user *)ptr))//协议代码cmd
				return -EFAULT;
			ptr += sizeof(uint32_t);
			if (put_user(death->cookie, (void * __user *)ptr))//Binder本地对象的地址值
				return -EFAULT;
			ptr += sizeof(void *);
			.....
			if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
				......
			} else
				list_move(&w->entry, &proc->delivered_death);//将这个工作项从Client进程的delivered_death队列中移除
			if (cmd == BR_DEAD_BINDER)
				goto done; /* DEAD_BINDER notifications can cause transactions */
		} break;
		}

		......
done:
	*consumed = ptr - buffer;
	......
	return 0;
}

     死亡接收通知的类型有三种,除了前面我们遇到的BINDER_WORK_DEAD_BINDER之外,还有BINDER_WORK_CLEAR_DEATH_NOTIFICATION和BINDER_WORK_DEAD_BINDER_AND_CLEAR。

     其中BINDER_WORK_CLEAR_DEATH_NOTIFICATION类型的死亡接收通知其实只是用来告诉Client进程,它成功地注销了一个之前所注册的死亡接收通知;

     而BINDER_WORK_DEAD_BINDER_AND_CLEAR类型的死亡接收通知除了告诉Client进程,它已经成功地注销了一个死亡接受通知之外,还告诉Client进程,与该死亡接受通知所关联的一个Binder本地对象已经死亡了。

     BINDER_WORK_DEAD_BINDER来通知Client进程,它所引用的一个Binder本地对象已经死亡了,后者才是真正的死亡接收通知。

     如果类型为BINDER_WORK_DEAD_BINDER,程序分别将协议代码cmd和binder_ref_death结构体death的成员变量cookie(Binder本地对象的地址值)写入Client进程提供的一个用户空间缓冲区。而且将正在处理的工作项保存在Client进程的一个delivered_death队列中。等到Client进程处理完成这个工作项之后,即处理完成一个死亡接收通知之后,它就会使用协议BC_DEAD_BINDER_DONE来通知Binder驱动程序,这时候Binder驱动程序就会将这个工作项从Client进程的delivered_death队列中移除。从这里看出,如果一个进程的delivered_death队列不为空,那么就说明Binder驱动程序正在向它发送死亡接受通知。


    当前线程返回到用户空间之后,就会在IPCThreadState类的成员函数executeCommand中处理协议BR_DEAD_BINDER。

      ~/Android/frameworks/base/libs/binder
     ----IPCThreadState.cpp

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    ..........
    status_t result = NO_ERROR;
    
    switch (cmd) {
    .......
    case BR_DEAD_BINDER:
        {
            BpBinder *proxy = (BpBinder*)mIn.readInt32();//获得用来接受死亡通知的Binder代理对象
            proxy->sendObituary();//调用它的成员函数sendObituary来处理该死亡通知
            mOut.writeInt32(BC_DEAD_BINDER_DONE);//使用协议BC_DEAD_BINDER_DONE来通知Binder驱动程序,它之前所发送的一个死亡接收通知已经处理完成了
            mOut.writeInt32((int32_t)proxy);
        } break;
        
     ......

    if (result != NO_ERROR) {
        mLastError = result;
    }
    
    return result;
}
     首先获得用来接受死亡通知的Binder代理对象,接着调用它的成员函数sendObituary来处理该死亡通知,最后使用协议BC_DEAD_BINDER_DONE来通知Binder驱动程序,它之前所发送的一个死亡接收通知已经处理完成了。

      sendObituary函数实现如下:

     ~/Android/frameworks/base/libs/binder

      ----BpBinder.cpp

void BpBinder::sendObituary()
{
    LOGV("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) {//说明该Binder代理对象之前向Binder驱动程序注册过死亡接受通知
        ......
        IPCThreadState* self = IPCThreadState::self();
        self->clearDeathNotification(mHandle, this);//调用IPCThreadState对象的成员函数clearDeathNotificaton对象立即执行这个注销操作
        self->flushCommands();
        mObituaries = NULL;
    }
    mObitsSent = 1;//表示它已经接收过Binder驱动程序发送过来的死亡接收通知了
    mLock.unlock();

    ......

    if (obits != NULL) {
        const size_t N = obits->size();
        for (size_t i=0; i<N; i++) {
            reportOneDeath(obits->itemAt(i));//通知保存在卟告列表中每一个死亡接收者
        }

        delete obits;
    }
}
     首先检查该Binder代理对象内部的卟告列表mObituaries是否为NULL,如果不是,那就说明该Binder代理对象之前向Binder驱动程序注册过死亡接受通知。现在既然它所引用的Binder本地对象已经死亡了,接会调用IPCThreadState对象的成员函数clearDeathNotificaton对象立即执行这个注销操作。

     然后将该Binder代理对象内部的成员变量mObitsSent的值设置为1,表示它已经接收过Binder驱动程序发送过来的死亡接收通知了。因此,如果以后再有其他组件调用它的成员函数linkToDeath来向它注册死亡通知接收者,那么它就会直接返回一个DEAD_OBJECT值给调用者,表示它们所关注的Binder本地对象已经死亡了

     最后依次调用成员函数reportOneDeath来通知保存在卟告列表中每一个死亡接收者,它们所关注的Binder本地对象已经死亡了。实现如下:

     ~/Android/frameworks/base/libs/binder

      ----BpBinder.cpp

void BpBinder::reportOneDeath(const Obituary& obit)
{
    sp<DeathRecipient> recipient = obit.recipient.promote();//弱引用升级为强引用
    LOGV("Reporting death to recipient: %p\n", recipient.get());
    if (recipient == NULL) return;//那么就说明该死亡通知接收者还未被销毁

    recipient->binderDied(this);//调用成员函数binderDied来处理这个死亡接收通知
}
     注册到一个Binder代理对象中的死亡通知接收者被封装成一个Obituary对象,其中,指向死亡通知接收者的一个弱指针就保存在该Obituary对象的成员变量recipient中,因此首先将弱引用升级为一个强引用,如果得到强指针不为NULL,那么就说明该死亡通知接收者还未被销毁,因此就调用它的成员函数binderDied来处理这个死亡接收通知。

    

五、注销死亡接收通知

    当Client进程不再需要关注某一个Binder本地对象的死亡事件时,它就可以调用引用了该Binder本地对象的Binder代理对象的成员函数unlinkToDeath来注销前面所注册的一个死亡接收通知了。

     ~/Android/frameworks/base/libs/binder

      ----BpBinder.cpp

status_t BpBinder::unlinkToDeath(
    const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
    wp<DeathRecipient>* outRecipient)
{
    AutoMutex _l(mLock);

    if (mObitsSent) {//如果mObitsSent为1,说明下面的程序已经执行过了
        return DEAD_OBJECT;
    }

    const size_t N = mObituaries ? mObituaries->size() : 0;
    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) {//检查Binder代理对象内部的卟告列表mObituaries是否存在Obituary对象与要注销的死亡通知接收者对应
            const uint32_t allFlags = obit.flags|flags;
            if (outRecipient != NULL) {
                *outRecipient = mObituaries->itemAt(i).recipient;
            }
            mObituaries->removeAt(i);
            if (mObituaries->size() == 0) {
                LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
                IPCThreadState* self = IPCThreadState::self();
                self->clearDeathNotification(mHandle, this);//来通知Binder驱动程序执行一个注销死亡接收通知的操作
                self->flushCommands();//flushCommands触发该操作马上被执行
                delete mObituaries;
                mObituaries = NULL;
            }
            return NO_ERROR;
        }
    }

    return NAME_NOT_FOUND;
}
     第一个参数recipient表示前面注册到Binder代理对象内部的一个死亡通知接收者;第二个参数cookie和第三个参数flags是另外两个用来该死亡通知接收者的数据;
     首先检查Binder代理对象内部的成员变量mObitsSent的值是否等于1,如果等于1,就说明Binder驱动程序已经向该Binder代理对象发送过死亡接收通知了。在这种情况下,Binder代理对象就会主动向Binder驱动程序注销死亡接收通知,并且将它的内部的死亡接收通知接收者列表清空。因此,这时候就不需要再执行注销死亡接收通知的操作了。

     for循环依次检查Binder代理对象内部的卟告列表mObituaries是否存在Obituary对象与要注销的死亡通知接收者对应。如果存在,就将它从卟告列表mObituaries中移除。如果mObituaries的长度为0,那么就调用这个IPCTreadState对象的成员函数clearDeathNotification来通知Binder驱动程序执行一个注销死亡接收通知的操作,最后调用flushCommands触发该操作马上被执行。

   

       IPCThreadState类的成员函数clearDeathNotification和flushCommands的实现如下:

      ~/Android/frameworks/base/libs/binder
     ----IPCThreadState.cpp

status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
{
    mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);//命令协议
    mOut.writeInt32((int32_t)handle);//Binder代理对象的句柄值
    mOut.writeInt32((int32_t)proxy);//Binder代理对象的地址值
    return NO_ERROR;
}
void IPCThreadState::flushCommands()
{
    if (mProcess->mDriverFD <= 0)
        return;
    talkWithDriver(false);
}
     它们使用了协议BC_CLEAR_DEATH_NOTIFICATION来请求Binder驱动程序执行一个注销死亡接收通知的操作。协议BC_CLEAR_DEATH_NOTIFICATION有两个参数,它们分别是要注销死亡接收通知的Binder代理对象的句柄值和地址值。

     协议BC_CLEAR_DEATH_NOTIFICATION是在Binder驱动程序的函数binder_thread_write中处理的,它的实现如下:所示:

     ~/Android//kernel/goldfish/drivers/staging/android

      ---binder.c

int
binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
		    void __user *buffer, int size, signed long *consumed)
{
	uint32_t cmd;
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;

	while (ptr < end && thread->return_error == BR_OK) {
		if (get_user(cmd, (uint32_t __user *)ptr))
			return -EFAULT;
		ptr += sizeof(uint32_t);
		.......
		switch (cmd) {//BC_CLEAR_DEATH_NOTIFICATION
		.....
		case BC_REQUEST_DEATH_NOTIFICATION:
		case BC_CLEAR_DEATH_NOTIFICATION: {
			uint32_t target;
			void __user *cookie;
			struct binder_ref *ref;
			struct binder_ref_death *death;

			if (get_user(target, (uint32_t __user *)ptr))//Binder代理对象的句柄值
				return -EFAULT;
			ptr += sizeof(uint32_t);
			if (get_user(cookie, (void __user * __user *)ptr))//Binder代理对象的地址值
				return -EFAULT;
			ptr += sizeof(void *);
			ref = binder_get_ref(proc, target);//根据句柄值target找到对应的Binder引用对象
			......

			if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
				.....
			} else {
				if (ref->death == NULL) {
					.....
					break;
				}
				death = ref->death;
				if (death->cookie != cookie) {
					.....
					break;
				}
				ref->death = NULL;
				if (list_empty(&death->work.entry)) {//当一个Binder本地对象死亡时,Binder驱动程序会将一个类型为BINDER_WORK_DEAD_BINDER的工作项保存在目标Client进程的todo队列中
					death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;//Binder驱动程序就会将一个类型为BINDER_WORK_CLEAR_DEATH_NOTIFICATION的工作项添加到当前线程或者所属的Client进程的todo队列中
					if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
						list_add_tail(&death->work.entry, &thread->todo);
					} else {
						list_add_tail(&death->work.entry, &proc->todo);
						wake_up_interruptible(&proc->wait);//唤醒相应的当前线程或者所属的Client进程来处理该工作项
					}
				} else {
					BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);
					death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;//会将死亡接收通知的发送操作和该死亡接收通知的注销结果返回操作合成一个类型为BINDER_WORK_DEAD_BINDER_AND_CLEAR的工作项交给目标Client进程来处理
				}
			}
		} break;
		....
		*consumed = ptr - buffer;
	}
	return 0;
}
     首先分别将Client进程传过来的两个参数从用户空间缓冲区中拷贝出来,并且保存在变量target和cookie中,它们分别对应于一个Binder代理对象的句柄值和地址值。根据句柄值target找到对应的Binder引用对象,并保存在变量ref中。将其成员变量death赋值为NULL。
      list_empty(&death->work.entry)判断binder_ref_death结构体death是否保存在某一个队列中。如果是,就表示它所对应的Binder本地对象已经死亡了。当一个Binder本地对象死亡时,Binder驱动程序会将一个类型为BINDER_WORK_DEAD_BINDER的工作项保存在目标Client进程的todo队列中。如果在Binder驱动程序将该工作项发送给目标Client进程处理之前,目标Client进程刚好又请求Binder驱动程序注销与该工作项对应的一个死亡接收通知,那么Binder驱动程序就会将死亡接收通知的发送操作和该死亡接收通知的注销结果返回操作合成一个类型为BINDER_WORK_DEAD_BINDER_AND_CLEAR的工作项交给目标Client进程来处理。这样就可以减少内核空间和用户空间的交互过程了。

     如果binder_ref_death结构体death没有保存在任何一个队列中,那么Binder驱动程序就会将一个类型为BINDER_WORK_CLEAR_DEATH_NOTIFICATION的工作项添加到当前线程或者所属的Client进程的todo队列中。并唤醒相应的当前线程或者所属的Client进程来处理该工作项。

你可能感兴趣的:(Binder对象死亡通知机制)