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
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
if (window != 0) {
window->linkToDeath(static_cast
}
。。。
}
下面看下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(驱动层的工作已经处理结束)