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对象死亡通知机制的更多相关文章
- Android应用程序组件Content Provider的共享数据更新通知机制分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6985171 在Android系统中,应用程序组 ...
- 图文详解 Android Binder跨进程通信机制 原理
图文详解 Android Binder跨进程通信机制 原理 目录 目录 1. Binder到底是什么? 中文即 粘合剂,意思为粘合了两个不同的进程 网上有很多对Binder的定义,但都说不清楚:Bin ...
- Android Binder 进程间通讯机制梳理
什么是 Binder ? Binder是Android系统中进程间通讯(IPC)的一种方式,也是Android系统中最重要的特性之一.Binder的设计采用了面向对象的思想,在Binder通信模型的四 ...
- 二 Java利用等待/通知机制实现一个线程池
接着上一篇博客的 一Java线程的等待/通知模型 ,没有看过的建议先看一下.下面我们用等待通知机制来实现一个线程池 线程的任务就以打印一行文本来模拟耗时的任务.主要代码如下: 1 定义一个任务的接口 ...
- inotify--内核中文件系统的通知机制
转载:http://www.ibm.com/developerworks/cn/linux/l-inotifynew/index.html 一. 引言 众所周知,Linux 桌面系统与 MAC 或 W ...
- 浅析SQL Server 2005中的主动式通知机制
一.引言 在开发多人同时访问的Web应用程序(其实不只这类程序)时,开发人员往往会在缓存策略的设计上狠下功夫.这是因为,如果将这种环境下不常变更的数据临时存放在应用程序服务器或是用户机器上的话,可以避 ...
- Java Concurrency - wait & notify, 等待通知机制
生产者消费者问题是一个常见的多线程同步案例:一组生产者线程和一组消费者线程共享一个初始状态为空.大小为 N 的缓冲区.只有当缓冲区没满的时候,生产者才能把消息放入缓冲区,否则必须等待:只有缓冲区不空的 ...
- Cocos中的观察者设计模式与通知机制
观察者(Observer)模式也叫发布/订阅(Publish/Subscribe)模式,是 MVC( 模型-视图-控制器)模式的重要组成部分.天气一直是英国人喜欢讨论的话题,而最近几年天气的变化也成为 ...
- java线程的等待、通知机制【读书笔记】
代码示例: package com.baidu.nuomi.concurrent; import java.text.SimpleDateFormat; import java.util.Date; ...
随机推荐
- python 继承中的__init__
如果子类不重写__init__, 实例化子类时,会自动调用父类定义的__init__ 如果子类要重写__init__,实例化子类,就不会调用父类已经定义的__init__ 所以如果想要扩充父类,需要显 ...
- js 验证图片
var selectedImg = e.target.files[0]; //获取图片 var isPic = /^(image\/bmp|image\/gif|image\/jpeg|image\/ ...
- kafka集群搭建文档
kafka集群搭建文档 一. 下载解压 从官网下载Kafka,下载地址http://kafka.apache.org/downloads.html 注意这里最好下载scala2.10版本的kafka, ...
- JspServlet
初始化servlet时,选用的配置类: config.getInitParameter("engineOptionsClass")?(System.getSecurityManag ...
- PAT甲级——A1073 Scientific Notation
Scientific notation is the way that scientists easily handle very large numbers or very small number ...
- 服务器IP配置功能实现小结
1. 服务器网卡配置文件 /etc/sysconfig/network/ifcfg-***(eth0) linux-f1s9:/etc/sysconfig/network # cat ifcfg-et ...
- Dmarc指定外域邮箱接收报告
场景说明: 如果要将DMARC报告发送到记录所在的域以外,则接收域需要配置DNS记录,以便电子邮件服务提供商知道收件人指定报告授权. ================================= ...
- springmvc-环境配置-架构-配合mybatis-参数绑定
1.1. Spring入门 1.1.1. Springmvc是什么 Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得 ...
- 利用jQuery获取jsonp
前端js代码: $.ajax({ url: 'http://localhost:8080/webApp/somejsonp', dataType: "jsonp", jsonp: ...
- elasticsearch 过滤器的种类
elasticsearch之查询过滤 elasticsearch elastic-search xixicat 2月13日发布 推荐 1 推荐 收藏 2 收藏,289 浏览 序 本文主要记录es的查询 ...