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<DeathRecipient>& 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<IBinder> window(defaultServiceManager()->getService(name));
if (window != 0) {
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(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);