标签:des android c style class blog
本文参考《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本地对象已经死亡了这种情况下,将一个类型为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))
return -EFAULT;
ptr += sizeof(uint32_t);
if (put_user(death->cookie, (void * __user *)ptr))
return -EFAULT;
ptr += sizeof(void *);
.....
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
......
} else
list_move(&w->entry, &proc->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_NOTIFICATION和BINDER_WORK_DEAD_BINDER_AND_CLEAR。其中BINDER_WORK_CLEAR_NOTIFICATION类型的死亡接受
Andorid Binder进程间通信---Binder对象死亡通知机制,布布扣,bubuko.com
Andorid Binder进程间通信---Binder对象死亡通知机制
标签:des android c style class blog
原文地址:http://blog.csdn.net/jltxgcy/article/details/27791513