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的这个讣告是不是很有人情味呢?想知道它是怎么做到的吗?还是先去看看驱动的实现吧。