6.5.2 有人情味的讣告
最后更新于:2022-04-02 05:50:55
在socket编程中,当一个socket 关闭后,我们无比希望另一端的select/poll/epoll/WaitForXXX有相应返回,以示通知。
说明:在广域网中,我们常常会因为收不到或者延时收到socket的close消息而烦恼。
在Binder系统中,要是明确表示对BnXXX的生死非常关心,那么在它离世后你会收到一份讣告。你可以嚎啕大哭,或者什么也不做。
关于这个问题,请直接看源码中的例子吧。
1. 表达你的关心
要想收到讣告,必须先要表达你的关心:做下面两件事:
- 从IBinder::DeathRecipient派生一个类,并实现其中的通知函数binderDied。这个函数一旦被调用,就相当于你收到了讣告。
- 把这个类注册到系统,告诉你关心哪一个BnXXX的生死。
看示例代码,它在MediaMetadataRetriever.cpp中,如下所示:
**MediaMetadataRetriever.cpp**
~~~
const sp&MediaMetadataRetriever::getService()
{
Mutex::Autolock lock(sServiceLock);
if(sService.get() == 0) {
sp sm = defaultServiceManager();
sp 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(binder);
}
returnsService;
}
~~~
2. 讣告是怎么收到的?
那么,这份讣告是怎么收到的呢?答案也在executeCommand中,代码如下所示:
**IPCThreadState.cpp**
~~~
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder*obj;
RefBase::weakref_type* refs;
status_tresult = NO_ERROR;
switch(cmd) {
caseBR_ERROR:
result = mIn.readInt32();
break;
......
caseBR_DEAD_BINDER:
{
//Binder驱动会通知死亡消息。下面的proxy对应着已经死亡的远端BBinder。
BpBinder *proxy =(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的关心。
*/
voidMediaMetadataRetriever::DeathNotifier::binderDied(const wp&who) {
Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
//把自己保存的BpMediaPlayerService对象干掉!
MediaMetadataRetriever::sService.clear();
LOGW("MediaMetadataRetriever serverdied!");//打印一下LOG,这样就完事大吉了。
}
~~~
4. 承受不住的诺言
我答应收到讣告后给你送终,可是如果我要是死在你前面或者中途我不想接收讣告,又该怎么办呢?先来看下面的代码:
**MediaMetadataRetriever.cpp**
~~~
MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
{
Mutex::Autolocklock(sServiceLock);
// DeathNotifier对象不想活了,但是BnMediaPlayerService还活着,
// 或者DeathNotifier中途变卦。怎么办?
//unlinkToDeath调用可以取消对BnMediaPlayerService的关心。
if(sService != 0) {
sService->asBinder()->unlinkToDeath(this);
}
}
~~~
Binder的这个讣告是不是很有人情味呢?想知道它是怎么做到的吗?还是先去看看驱动的实现吧。
';