Binder结点死亡通知过程

BpBinder类代表一个远程Binder对象(继承自BpRefBase)的通信功能部分。它提供了linkToDeath方法,供其他对象监听自己所关联的本地结点的死亡通知,本质上是通过调用IPCThreadState类的requestDeathNotification接口。unlinkToDeath方法则是取消接收Binder结点的死亡通知。而sendObituary则是向监听者发送结点的死亡通知。这两个接口都会通过IPCThreadState类的clearDeathNotification向消息处理发送到Binder驱动去处理。

一般BpBinder对象是包含于从BpRefBase继承过来的类中,也即BpINTERFACE类的一个私有成员,代表IPC通信的一方与另一方进行通信。在Binder驱动,要支持死亡通知机制,是通过binder_ref来实现的。binder_ref有一个成员是指向struct binder_ref_death结构的指针。它的结构定义如下:

struct binder_ref_death {

         structbinder_work work;

         binder_uintptr_tcookie;

};

其中,work是指提交给当前线程或进程处理的工作类型,一般为如下三种:             BINDER_WORK_DEAD_BINDER,//dead binder

         BINDER_WORK_DEAD_BINDER_AND_CLEAR,//clear dead binder

         BINDER_WORK_CLEAR_DEATH_NOTIFICATION,//clear death notification

cookie则一般保存的是BpBinder对象的内存地址,主要用于标识当前的通信会话。

 

linkToDeath(…)接口代码分析

该接口的原型如下:

   virtual status_t   linkToDeath(const sp& recipient,

                                    void*cookie = NULL,

                                    uint32_t flags = 0);

使用示例如下,SurfaceFlinger将监听window manager进程的死亡消息:

void SurfaceFlinger::bootFinished()

         。。。

   // wait patiently for the window manager death

   const String16 name("window");

   sp window(defaultServiceManager()->getService(name));

   if (window != 0) {

       window->linkToDeath(static_cast(this));

    }

         。。。

 

下面看下linkToDeath方法调用的流程:

BpBinder::linkToDeath(…) --> IPCThreadState::requestDeathNotification(…) --> “BC_REQUEST_DEATH_NOTIFICATION”

 

下面看下处理BC_REQUEST_DEATH_NOTIFICATION的代码逻辑:

由于requestDeathNotification方法传入的两个参数一个是远程Binder结点的句柄以及对象本身的内存地址(BpBinder对象),所以驱动依次拿到这两个参数:

 

int binder_thread_write(struct binder_proc*proc, struct binder_thread *thread,

                            binder_uintptr_tbinder_buffer, size_t size,

                            binder_size_t*consumed)

{

         …

         caseBC_REQUEST_DEATH_NOTIFICATION:

                   caseBC_CLEAR_DEATH_NOTIFICATION: {

                            uint32_ttarget;

                            binder_uintptr_tcookie;

                            structbinder_ref *ref;

                            structbinder_ref_death *death;

 

                            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_ref实例,

ref = binder_get_ref(proc, target);

 

下面是处理BC_REQUEST_DEATH_NOTIFICATION的代码:

 

         if(cmd == BC_REQUEST_DEATH_NOTIFICATION) {

                                     如果ref->death不为空,则说明之前已经调用过requestDeathNotification,直接忽略这次调用。

if (ref->death) {

                                               binder_user_error("%d:%dBC_REQUEST_DEATH_NOTIFICATION death notification already set\n",

                                                        proc->pid,thread->pid);

                                               break;

                                     }

                                     否则,则创建一个binder_ref_death实例,并绑定给上述的binder_ref实例。

                                     death= kzalloc(sizeof(*death), GFP_KERNEL);

                                     if(death == NULL) {

                                               thread->return_error= BR_ERROR;

                                               binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,

                                                             "%d:%d BC_REQUEST_DEATH_NOTIFICATIONfailed\n",

                                                             proc->pid, thread->pid);

                                               break;

                                     }

                                     binder_stats_created(BINDER_STAT_DEATH);

                                     INIT_LIST_HEAD(&death->work.entry);

                                     death->cookie= cookie;

                                     ref->death= death;

                                     如果远程Binder结点所在的进程已经退出,则说明远程Binder结点已经死亡,应该发送死亡通知,是通过与之关联的binder_ref的死亡列表发送通知的。

                                     if(ref->node->proc == NULL) {

                                               ref->death->work.type= BINDER_WORK_DEAD_BINDER;

                                               如果当前线程没有退出,就发送到线程的事件处理链表中,否则发送到进程的事件处理链表中。

                                               if(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |BINDER_LOOPER_STATE_ENTERED)) {

                                                        list_add_tail(&ref->death->work.entry,&thread->todo);

                                               }else {

                                                        list_add_tail(&ref->death->work.entry,&proc->todo);

                                                        wake_up_interruptible(&proc->wait);

                                               }

                                     }

                            }

这里说明下,当ref->death->work.entry链表为空,说明binder_ref关联的远程Binder结点还处于活跃状态,无需发送死亡通知。

 

unlinkToDeath(…)

BpBinder::unlinkToDeath(…) -->IPCThreadState:: clearDeathNotification(…) -->BC_CLEAR_DEATH_NOTIFICATION

下面来看处理BC_CLEAR_DEATH_NOTIFICATION的逻辑。

         发出这个命令的情形有两种:

1. 结点没有死亡,此时提交的工作类型为BINDER_WORK_CLEAR_DEATH_NOTIFICATION,只是取消监听结点的死亡通知,不影响其他对象对该结点的监听。

2.结点已经死亡,此时提交的工作类型为BINDER_WORK_DEAD_BINDER_AND_CLEAR,这时要做进一步处理后,再将工作类型提交为BINDER_WORK_CLEAR_DEATH_NOTIFICATION。

int binder_thread_write(struct binder_proc*proc, struct binder_thread *thread,

                            binder_uintptr_tbinder_buffer, size_t size,

                            binder_size_t*consumed)

{

         …

         case BC_REQUEST_DEATH_NOTIFICATION:

                   caseBC_CLEAR_DEATH_NOTIFICATION: {

         …

         if(cmd == BC_REQUEST_DEATH_NOTIFICATION) {

         …

         }else {

                                     if(ref->death == NULL) {

                                               binder_user_error("%d:%dBC_CLEAR_DEATH_NOTIFICATION death notification not active\n",

                                                        proc->pid,thread->pid);

                                               break;

                                     }

                                     death= ref->death;

                                     通过cookie来标识当前通信会话

                                     if(death->cookie != cookie) {

                                               binder_user_error("%d:%dBC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx !=%016llx\n",

                                                        proc->pid,thread->pid,

                                                        (u64)death->cookie,(u64)cookie);

                                               break;

                                     }

                                     ref->death= NULL;

                                     如果death->work.entry为空,说明被监听的Binder结点还处于活跃状态,这时只是取消对该结点的死亡监听

                                     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)) {

                                                        list_add_tail(&death->work.entry,&thread->todo);

                                               } else {

                                                        list_add_tail(&death->work.entry,&proc->todo);

                                                        wake_up_interruptible(&proc->wait);

                                               }

                                     }else {

                                               否则,该结点已经死亡,将当前工作类型修改为BINDER_WORK_DEAD_BINDER_AND_CLEAR

                                               BUG_ON(death->work.type!= BINDER_WORK_DEAD_BINDER);

                                               death->work.type= BINDER_WORK_DEAD_BINDER_AND_CLEAR;

                                     }

                            }

 

}

 

如下是处于当前线程或进程上的binder_work的处理过程:

static int binder_thread_read(structbinder_proc *proc,

                                  struct binder_thread *thread,

                                  binder_uintptr_t binder_buffer, size_tsize,

                                  binder_size_t *consumed, int non_block)

{

         …

         while(1) {

                   …

                   从当前线程或进程中取出提交上来的工作类型

                   if(!list_empty(&thread->todo))

                            w= list_first_entry(&thread->todo, struct binder_work, entry);

                   elseif (!list_empty(&proc->todo) && wait_for_proc_work)

                            w= list_first_entry(&proc->todo, struct binder_work, entry);

                   else{

                   }

                   …

                   switch(w->type) {

                   …

                   caseBINDER_WORK_DEAD_BINDER:

                   caseBINDER_WORK_DEAD_BINDER_AND_CLEAR:

                   caseBINDER_WORK_CLEAR_DEATH_NOTIFICATION: {

                            structbinder_ref_death *death;

                            uint32_t cmd;

 

                            death= container_of(w, struct binder_ref_death, work);

                            if(w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)

                                     被监听的结点没有死亡,通知用户空间减少对该结点的弱引用计数

                                     cmd= BR_CLEAR_DEATH_NOTIFICATION_DONE;

                            else

                                     被监听的结点已经死亡,发送BR_DEAD_BINDER通知用户空间处理

                                     cmd= BR_DEAD_BINDER;

                            if(put_user(cmd, (uint32_t __user *)ptr))

                                     return-EFAULT;

                            ptr+= sizeof(uint32_t);

                            if(put_user(death->cookie,

                                          (binder_uintptr_t __user *)ptr))

                                     return-EFAULT;

                            ptr+= sizeof(binder_uintptr_t);

                            binder_stat_br(proc,thread, cmd);

                            binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,

                                          "%d:%d %s %016llx\n",

                                           proc->pid, thread->pid,

                                           cmd == BR_DEAD_BINDER ?

                                           "BR_DEAD_BINDER" :

                                          "BR_CLEAR_DEATH_NOTIFICATION_DONE",

                                           (u64)death->cookie);

 

                            if(w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {

                                     这种情况是要删除death实例

list_del(&w->entry);

                                     kfree(death);

                                     binder_stats_deleted(BINDER_STAT_DEATH);

                            }else

                                     death实例的清理工作,提交到进程中延后处理(在收到BC_DEAD_BINDER_DONE时处理)

                                     list_move(&w->entry,&proc->delivered_death);

                            由于BR_DEAD_BINDER还要触发用户空间向Binder驱动发送后续命令BC_CLEAR_DEATH_NOTIFICATION BC_DEAD_BINDER_DONE所以应当退出当前循环,以便当前线程能够处理上述命令。

                            if(cmd == BR_DEAD_BINDER)

                                     gotodone; /* DEAD_BINDER notifications can cause transactions */

                   }break;

                   }

         …

}

如果在requestDeathNotification的时候结点已经退出,或Binder通信结束,Binder结点被释放,调用了binder_node_release,驱动会返回BR_DEAD_BINDER命令,通知上层处理。

status_tIPCThreadState::executeCommand(int32_t cmd)

         。。。

   case BR_DEAD_BINDER:

       {

           BpBinder *proxy = (BpBinder*)mIn.readInt32();

           proxy->sendObituary();

           mOut.writeInt32(BC_DEAD_BINDER_DONE);

           mOut.writeInt32((int32_t)proxy);

       } break;

         。。。

首先,代表远程结点通信的BpBinder会调用sendObituary命令,清除对它的死亡通知列表(会向驱动发送BC_CLEAR_DEATH_NOTIFICATION命令),并调用监听者的回调函数通知监听者。之后,会向驱动发送BC_DEAD_BINDER_DONE,通知驱动善后处理。

下面看下BC_DEAD_BINDER_DONE的处理过程:

                   caseBC_DEAD_BINDER_DONE: {

                            structbinder_work *w;

                            binder_uintptr_tcookie;

                            structbinder_ref_death *death = NULL;

                            if(get_user(cookie, (binder_uintptr_t __user *)ptr))

                                     return-EFAULT;

 

                            ptr+= sizeof(void *);

                            从当前进程的延迟处理列表中,取出要处理的工作类型

                            list_for_each_entry(w,&proc->delivered_death, entry) {

                                     structbinder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);

                                     通过cookie来新知识对应的binder_ref_death实例

                                     if(tmp_death->cookie == cookie) {

                                               death= tmp_death;

                                               break;

                                     }

                            }

                            binder_debug(BINDER_DEBUG_DEAD_BINDER,

                                          "%d:%d BC_DEAD_BINDER_DONE %016llxfound %p\n",

                                          proc->pid, thread->pid, (u64)cookie,death);

                            如果相关信息无法找到,则直接退出,无需后续处理

                            if(death == NULL) {

                                     binder_user_error("%d:%dBC_DEAD_BINDER_DONE %016llx not found\n",

                                               proc->pid,thread->pid, (u64)cookie);

                                     break;

                            }

                           

                            list_del_init(&death->work.entry);

                            结点已经死亡,需要清理消息通知相关信息

                            if(death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) {

                                     death->work.type= BINDER_WORK_CLEAR_DEATH_NOTIFICATION;

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

                                     }

                            }

                   }break;

 

IPC通信过程示例

BC_DEAD_BINDER(binder_node_release或BC_REQUEST_DEATH_NOTIFICATION)

->BR_DEAD_BINDER(binder_thread_read)

-> BC_CLEAR_DEATH_NOTIFICATION(如果结点已经死亡,则工作类型修改为BINDER_WORK_DEAD_BINDER_AND_CLEAR)

-> BC_DEAD_BINDER_DONE(将工作类型修改为BINDER_WORK_CLEAR_DEATH_NOTIFICATION,提交到当前线程或进程进一步处理)

-> BR_CLEAR_DEATH_NOTIFICATION_DONE(驱动层的工作已经处理结束)

你可能感兴趣的:(Android研究)