6.5.2 有人情味的讣告

在socket编程中,如果一个socket关闭了,我们会无比希望另一端的select/poll/epoll/WaitForXXX有相应的返回,以示通知。

说明 在广域网中,我们常常会因为收不到或延时收到socket的close消息而烦恼。

在Binder系统中,要是明确表示了你对BnXXX的生死非常关心,那么在它“离世”后你会收到一份讣告。你可以嚎啕大哭,或者什么也不做。

关于这个问题,请直接看源码中的例子吧。

1.表达你的关心

要想收到讣告,必须先表达你的关心,做下面两件事:

从IBinder:DeathRecipient派生一个类,并实现其中的通知函数binderDied。这个函数一旦被调用,就相当于你收到了讣告。

把这个类注册到系统中,告诉它你关心哪一个BnXXX的生死。

看示例代码,它在MediaMetadataRetriever.cpp中,如下所示:


[—>MediaMetadataRetriever.cpp]

const sp<IMediaPlayerService>&MediaMetadataRetriever:getService()

{

Mutex:Autolock lock(sServiceLock);

if(sService.get()==0){

sp<IServiceManager>sm=defaultServiceManager();

sp<IBinder>binder;

do{

binder=sm->getService(String16(“media.player”));

if(binder!=0){

break;

}

usleep(500000);//0.5 s

}while(true);

if(sDeathNotifier==NULL){

sDeathNotifier=new DeathNotifier();

}

//调用下面这个函数,告诉系统我们对这个binder的生死有兴趣。

//这个binder是一个BpBinder,它关心的是对端BBinder,也即BnXXX的父类。

binder->linkToDeath(sDeathNotifier);

sService=interface_cast<IMediaPlayerService>(binder);

}

return sService;

}


2.讣告是怎么收到的

那么,这份讣告是怎么收到的呢?答案也在executeCommand中,代码如下所示:


[—>IPCThreadState.cpp]

status_t IPCThreadState:executeCommand(int32_t cmd)

{

BBinder*obj;

RefBase:weakref_type*refs;

status_t result=NO_ERROR;

switch(cmd){

case BR_ERROR:

result=mIn.readInt32();

break;

……

case BR_DEAD_BINDER:

{

//Binder驱动会通知死亡消息。下面的proxy对应着已经死亡的远端BBinder。

BpBinderproxy=(BpBinder)mIn.readInt32();

//发送讣告,Obituary是讣告的意思。最终会传递到你的DeathNotifier中。

proxy->sendObituary();

mOut.writeInt32(BC_DEAD_BINDER_DONE);

mOut.writeInt32((int32_t)proxy);

}break;

default:

result=UNKNOWN_ERROR;

break;

}


3.你“死”了,我怎么办

收到讣告后该怎么办呢?有一些代码看起来非常“薄情寡义”,如下所示:


[—>MediaMetadataRetriever.cpp]

/*

DeathNotifier是MediaMetadataRetriever的内部类,前面在getService函数中

我们注册了它对BnMediaPlayerService的关心。

*/

void MediaMetadataRetriever:DeathNotifier:binderDied(const wp<IBinder>&who){

Mutex:Autolock lock(MediaMetadataRetriever:sServiceLock);

//把自己保存的BpMediaPlayerService对象干掉!

MediaMetadataRetriever:sService.clear();

LOGW("MediaMetadataRetriever server died!");//打印一下LOG,这样就完事大吉了。

}


4.承受不住的诺言

虽然我答应收到讣告后给你送终,可是如果我死在你前面或中途我不想接收讣告,又该怎么办呢?来看下面的代码:


[—>MediaMetadataRetriever.cpp]

MediaMetadataRetriever:DeathNotifier:~DeathNotifier()

{

Mutex:Autolock lock(sServiceLock);

//DeathNotifier对象不想活了,但是BnMediaPlayerService还活着,

//或者DeathNotifier中途变卦。怎么办?

//unlinkToDeath调用可以取消对BnMediaPlayerService的关心。

if(sService!=0){

sService->asBinder()->unlinkToDeath(this);

}

}


Binder的这个讣告是不是很有人情味呢?想知道它是怎么做到的吗?还是先去看看驱动的实现吧。