该系列文章总纲链接:专题分纲目录 android 系统核心机制 binder
本章关键点总结 & 说明:
这里主要关注➕其他里的 死亡讣告,关键在于知道如何使用讣告机制来让客户端收到 死亡通知。
本章节主要讲述 Binder挂掉后 客户端是如何收到通知的;要想收到Binder服务端挂掉的消息,一定要先遵守Binder能够接收讣告的2个设计原则:
- 从IBinder::DeathRecipient中派生一个类,实现方法binderDied,(注册后,收到讣告就会调用这个方法)
- 将该类注册到系统中,关联到关心的BnXXX的生死
1 实现设计原则
这里以MeidaMetadataRetriever为例,先看头文件中,即关注如何实现这个设计原则:
class MediaMetadataRetriever: public RefBase
{
public:
MediaMetadataRetriever();
~MediaMetadataRetriever();
...
private:
static const sp<IMediaPlayerService>& getService();
/* 这里通过内部类DeathNotifier来继承IBinder::DeathRecipient,实现binderDied */
class DeathNotifier: public IBinder::DeathRecipient
{
public:
DeathNotifier() {}
virtual ~DeathNotifier();
virtual void binderDied(const wp<IBinder>& who);
};
/* 定义1个DeathNotifier类型的变量 */
static sp<DeathNotifier> sDeathNotifier;
...
};
同时在获取该服务时,代码如下:
const sp<IMediaPlayerService>& MediaMetadataRetriever::getService()
{
Mutex::Autolock lock(sServiceLock);
if (sService == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("MediaPlayerService not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
/* 该binder是BpBinder,它关心的是对端的BBinder,即BnXXX */
/* 这里同时也是将DeathNotifier注册到系统中,将其添加到对应的链表中 */
binder->linkToDeath(sDeathNotifier);
sService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sService == 0, "no MediaPlayerService!?");
return sService;
}
这样,即完成了Binder能够接收讣告的2个设计原则,接下来,收到讣告后会调用binderDied,代码实现如下:
void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
/* 把自己保存的BpMediaPlayerService对象销毁 */
MediaMetadataRetriever::sService.clear();
ALOGW("MediaMetadataRetriever server died!");
}
2 讣告如何收到
这里查看executeCommand中代码的实现,实现如下:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch (cmd) {
...
case BR_DEAD_BINDER:
{ /* 收到binder驱动发来的service死亡的消息,只有Bp端能收到,proxy对应已经死亡的远端BBinder */
BpBinder *proxy = (BpBinder*)mIn.readInt32();
/* 发送讣告,这里最终会传递到对应的DeathNotifier中 */
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writeInt32((int32_t)proxy);
} break;
...
}
...
return result;
}
3 特殊情况
在收到讣告之前,该客户端(MeidaMetadataRetriever)先挂了,会先调用析构方法,代码如下:
MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
{
Mutex::Autolock lock(sServiceLock);
if (sService != 0) {
/* 这里将DeathNotifier从系统中注销,即从对应的链表中删除 */
sService->asBinder()->unlinkToDeath(this);
}
}
这说明,只要客户端挂了,就会自动解锁 讣告机制,不会存在资源泄露的问题。