Android native层 DeathRecipient 死亡通知监听实现
本系列文章分析的安卓源码版本:【Android 10.0 版本】
此部分是在分析multimedia整体架构时由于该内容是常用实现内容,因此被抽出来单独进行分析。
死亡通知是为了让Bp端能知道Bn端的生死状态
定义:DeathRecipient继承IBinder::DeathRecipient类,主要实现其binderDied()方法来处理死亡通知事件。
注册:binder->linkToDeath(mDeathRecipient)是为了将mDeathRecipient死亡通知注册到Binder上,并发送【BC_CLEAR_DEATH_NOTIFICATION】Binder任务命令给IPCThreadState去监听binder驱动的死亡通知。
Bp端只需覆写binderDied()方法,实现一些清除工作,则在Bn端Binder进程死亡后,会回调binderDied()方法进行相应处理。
1、根据该章节(【三】Android MediaPlayer整体架构源码分析 -【设置数据源】【Part 2】)第1小节的分析,可知其实现监听功能非常简单,在sp MediaPlayerService::Client::setDataSource_pre()方法中,关键实现代码如下:
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
// 收集Binder对端进程(如相关Service服务进程)异常关闭通知事件集合
std::vector<DeathNotifier> deathNotifiers;
// 此处为监听媒体数据提取(即数据解析)解复用模块服务进程的异常关闭断开通知
// Listen to death of media.extractor service
// 从【multimedia整体架构】系列章节的类似代码处理分析可知,
// 此处功能即为:从服务注册管理中心获取名为【media.extractor】服务的Binder通信服务
sp<IServiceManager> sm = defaultServiceManager();
// 注意此处获取到的是Bp对象
sp<IBinder> binder = sm->getService(String16("media.extractor"));
if (binder == NULL) {
ALOGE("extractor service not available");
return NULL;
}
// 向该集合对象中添加监听的Binder进程
// 注意:此处是创建了DeathNotifier类的匿名对象加入到该集合中的处理,
// 调用的构造函数为:DeathNotifier(sp<IBinder> const& service, Notify const& notify),
// 第一个参数为binder,binder后面的全部是第二个参数,其实际上就是一个匿名方法的实现,
// 因为Notify就是一个方法引用【using Notify = std::function<void()>;】,
// 并且该匿名方法带有一个参数为【l = wp<MediaPlayerBase>(p)】即指针弱引用
// 【弱引用的原因是,不能影响其强引用对象指针的回收】
// 因此在监听到对端进程异常关闭后将会执行该匿名方法。
// 其具体实现原理,见第2小节分析
deathNotifiers.emplace_back(
binder, [l = wp<MediaPlayerBase>(p)]() {
// 被监听的进程异常关闭时,执行此匿名方法实现
// 将弱引用对象尝试进行提升为强引用对象
sp<MediaPlayerBase> listener = l.promote();
if (listener) {
ALOGI("media.extractor died. Sending death notification.");
listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
MEDIAEXTRACTOR_PROCESS_DEATH);
} else {
ALOGW("media.extractor died without a death handler.");
}
});
2、监听对端进程实现流程分析
DeathNotifier,对对端进程(如相关Service服务进程)异常关闭通知事件的监听实现处理:
DeathNotifier类声明:
// [/frameworks/av/media/libmediaplayerservice/DeathNotifier.h]
class DeathNotifier {
public:
using HBase = hidl::base::V1_0::IBase;
// 使用方法声明定义
using Notify = std::function<void()>;
DeathNotifier(sp<IBinder> const& service, Notify const& notify);
DeathNotifier(sp<HBase> const& service, Notify const& notify);
DeathNotifier(DeathNotifier&& other);
~DeathNotifier();
private:
// 注意该变量的声明,类模板 std::variant 表示一个类型安全的共享体(union)。
// 即行为和union大致相同,每次只可存在一种类型,该对象通过下标访问
std::variant<std::monostate, sp<IBinder>, sp<HBase>> mService;
// 声明一个内部类:进程死亡通知接收类
class DeathRecipient;
sp<DeathRecipient> mDeathRecipient;
};
DeathNotifier构造函数:
可看出,将binder对象放入了mService的第2个数据中缓存,并构造一个DeathRecipient对象进行接收进程死亡事件监听对象
// [/frameworks/av/media/libmediaplayerservice/DeathNotifier.cpp]
DeathNotifier::DeathNotifier(sp<IBinder> const& service, Notify const& notify)
: mService{std::in_place_index<1>, service},
mDeathRecipient{new DeathRecipient(notify)} {
// DeathRecipient类声明和构造函数实现,见2.1小节分析
// 将进程死亡监听对象和远程(对端)被监听进程进行链接
// linkToDeath该方法是IBinder中声明的
// 见2.2小节分析
service->linkToDeath(mDeathRecipient);
}
2.1、DeathRecipient类声明和构造函数实现:
DeathRecipient类声明就是上面DeathNotifier类内部声明的。
DeathRecipient构造函数及其所有实现:
其继承了 IBinder::DeathRecipient 和 hardware::hidl_death_recipient 这两个类,即该类相当于这两个类的一个代理类,使用了代理设计模式
// [/frameworks/av/media/libmediaplayerservice/DeathNotifier.cpp]
class DeathNotifier::DeathRecipient :
public IBinder::DeathRecipient,
public hardware::hidl_death_recipient {
public:
using Notify = DeathNotifier::Notify;
DeathRecipient(Notify const& notify): mNotify{notify} {
// 构造方法
}
virtual void binderDied(wp<IBinder> const&) override {
// Binder死亡通知函数
// 重要处理:由于Notify被声明为了一个函数的引用调用,
// 因此此处即为该方法的调用
mNotify();
}
virtual void serviceDied(uint64_t, wp<HBase> const&) override {
// 服务死亡通知函数,其实该方法应该是对应的hidl层的死亡通知实现时调用的,暂不展开分析
mNotify();
}
private:
Notify mNotify;
};
2.2、service->linkToDeath(mDeathRecipient)实现分析:
linkToDeath该方法是IBinder中声明的纯虚函数,第一个参数不能为空,后面两参数可不传入即使用默认值。
// [frameworks/native/libs/binder/include/binder/IBinder.h]
/**
* Register the @a recipient for a notification if this binder
* goes away. If this binder object unexpectedly goes away
* (typically because its hosting process has been killed),
* then DeathRecipient::binderDied() will be called with a reference
* to this.
*
* The @a cookie is optional -- if non-NULL, it should be a
* memory address that you own (that is, you know it is unique).
*
* @note You will only receive death notifications for remote binders,
* as local binders by definition can't die without you dying as well.
* Trying to use this function on a local binder will result in an
* INVALID_OPERATION code being returned and nothing happening.
*
* @note This link always holds a weak reference to its recipient.
*
* @note You will only receive a weak reference to the dead
* binder. You should not try to promote this to a strong reference.
* (Nor should you need to, as there is nothing useful you can
* directly do with it now that it has passed on.)
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0) = 0;
其实现肯定是每个IBinder子类进行实现的,因此我们在任何实现了IBinder接口进行Binder机制进程间通信的模块都可以看到此实现,其实实际上实现了该接口的子类就是Binder机制中的Bn端和Bp端。
在Binder机制实现中,IBinder两个子类BBinder和BpBinder,而在Bn实现端其实是不需要实现该方法的,因此Bn只在BBinder.cpp中默认空实现。
因此可以看到BpBinder.cpp中进行了统一实现:
注意此处的参数DeathRecipient为IBinder::DeathRecipient
// [frameworks/native/libs/binder/BpBinder.cpp]
// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
// 将死亡接收对象等参数打包
Obituary ob;
ob.recipient = recipient;
ob.cookie = cookie;
ob.flags = flags;
LOG_ALWAYS_FATAL_IF(recipient == nullptr,
"linkToDeath(): recipient must be non-NULL");
{
AutoMutex _l(mLock);
// mObitsSent 该值为一个类全局变量的死亡通告已发送标志位,
// 即若为1则表示已发送了进程死亡通知事件,因此不再需要重复通知
if (!mObitsSent) {
// 未发送时,判断该死亡通告事件集合是否存在,不存在则创建
if (!mObituaries) {
mObituaries = new Vector<Obituary>;
if (!mObituaries) {
return NO_MEMORY;
}
ALOGV("Requesting death notification: %p handle %d\n", this, mHandle);
// Bp端实现对象弱引用指针计数增加
getWeakRefs()->incWeak(this);
IPCThreadState* self = IPCThreadState::self();
// 在IPCThreadState类请求该死亡通知事件
// 主要就是向Binder驱动发送 BC_REQUEST_DEATH_NOTIFICATION 请求命令事件,见下面的分析
self->requestDeathNotification(mHandle, this);
self->flushCommands();
}
// 添加本次死亡通知事件到通知列表中,返回值小于0则表示添加错误
ssize_t res = mObituaries->add(ob);
return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
}
}
return DEAD_OBJECT;
}
self->requestDeathNotification(mHandle, this)实现分析:
// [frameworks/native/libs/binder/IPCThreadState.cpp]
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{// 向Binder驱动注册发送 BC_REQUEST_DEATH_NOTIFICATION 请求死亡通知命令
// 主要用于后续当前线程IPCThreadState收到Binder死亡消息时能够执行proxy即BpBinder的回调方法【BpBinder::sendObituary()】
mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writePointer((uintptr_t)proxy);
return NO_ERROR;
}
3、发送死亡通知流程分析
在BpBinder实现中可以看到另一个实现方法【BpBinder::sendObituary()】,即如下发送死亡通知事件实现,其被调用是在IPCThreadState收到Binder死亡通知时进行调用,如下的处理流程:
// [frameworks/native/libs/binder/IPCThreadState.cpp]
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
// 当系统Binder驱动检查到Binder进程异常关闭时,
// 将会向注册了 BC_REQUEST_DEATH_NOTIFICATION 请求死亡通知命令的进程端发送Binder死亡通知事件,
// 并调用【BpBinder::sendObituary()】
case BR_DEAD_BINDER:
{
BpBinder *proxy = (BpBinder*)mIn.readPointer();
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writePointer((uintptr_t)proxy);
} break;
// ... 省略其他代码
}
}
// [frameworks/native/libs/binder/BpBinder.cpp]
void BpBinder::sendObituary()
{
ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
this, mHandle, mObitsSent ? "true" : "false");
mAlive = 0;
if (mObitsSent) return;
mLock.lock();
Vector<Obituary>* obits = mObituaries;
if(obits != nullptr) {
// 存在死亡通知事件集合,则发送【BC_CLEAR_DEATH_NOTIFICATION】命令
// 告诉IPCThreadState执行清除发送死亡通知任务
ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
IPCThreadState* self = IPCThreadState::self();
self->clearDeathNotification(mHandle, this);
self->flushCommands();
mObituaries = nullptr;
}
// 并标记当前已发送处理了
mObitsSent = 1;
mLock.unlock();
ALOGV("Reporting death of proxy %p for %zu recipients\n",
this, obits ? obits->size() : 0U);
if (obits != nullptr) {
const size_t N = obits->size();
for (size_t i=0; i<N; i++) {
// 循环执行每一个死亡通知事件监听
// 见下面的分析
reportOneDeath(obits->itemAt(i));
}
delete obits;
}
}
reportOneDeath(obits->itemAt(i))实现分析:
// [frameworks/native/libs/binder/BpBinder.cpp]
void BpBinder::reportOneDeath(const Obituary& obit)
{
// 由上面的linkToDeath注册方法可知,obit.recipient即为调用端传入的死亡通知监听对象,
// 并且缓存为wp弱引用指针对象,此处进行尝试提升,若没有被释放内存,
// 则调用该监听对象的binderDied方法,即监听端收到了该通知
sp<DeathRecipient> recipient = obit.recipient.promote();
ALOGV("Reporting death to recipient: %p\n", recipient.get());
if (recipient == nullptr) return;
// 调用该监听对象的binderDied方法
recipient->binderDied(this);
}
4、取消监听流程
提前取消该监听是在DeathNotifier析构函数实现的:
// [frameworks/av/media/libmediaplayerservice/DeathNotifier.cpp]
DeathNotifier::~DeathNotifier() {
// index()就是该变量当前哪个索引位置有值就返回它的索引,
// 因此对应上面分析,我们分析1的位置
switch (mService.index()) {
case 0:
break;
case 1:
// 由此可知调用的IBinder即BpBinder的unlinkToDeath断开监听链接处理流程,如下分析
std::get<1>(mService)->unlinkToDeath(mDeathRecipient);
break;
case 2:
std::get<2>(mService)->unlinkToDeath(mDeathRecipient);
break;
default:
CHECK(false) << "Corrupted service type during destruction.";
}
}
BpBinder的unlinkToDeath断开监听链接处理流程:
// [frameworks/native/libs/binder/BpBinder.cpp]
// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::unlinkToDeath(
const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
wp<DeathRecipient>* outRecipient)
{
AutoMutex _l(mLock);
if (mObitsSent) {
return DEAD_OBJECT;
}
// 处理原理就是:
// For循环来查找需要被取消监听的死亡监听对象,或cookie相同的一组对象,
// 找到后remove调用,即可完成
const size_t N = mObituaries ? mObituaries->size() : 0;
for (size_t i=0; i<N; i++) {
const Obituary& obit = mObituaries->itemAt(i);
if ((obit.recipient == recipient
|| (recipient == nullptr && obit.cookie == cookie))
&& obit.flags == flags) {
if (outRecipient != nullptr) {
*outRecipient = mObituaries->itemAt(i).recipient;
}
mObituaries->removeAt(i);
if (mObituaries->size() == 0) {
ALOGV("Clearing death notification: %p handle %d\n", this, mHandle);
IPCThreadState* self = IPCThreadState::self();
self->clearDeathNotification(mHandle, this);
self->flushCommands();
delete mObituaries;
mObituaries = nullptr;
}
return NO_ERROR;
}
}
return NAME_NOT_FOUND;
}
关于该Binder进程异常关闭时的触发时机,即Binder死亡通知事件是如何触发的呢?对于Binder IPC进程都会打开/dev/binder文件,当进程异常退出时,Binder驱动会保证释放将要退出的进程中没有正常关闭的/dev/binder文件,实现机制是binder驱动通过调用/dev/binder文件所对应的release回调函数,执行清理工作,并且检查对应的BBinder是否有注册死亡通知,当发现存在死亡通知时,那么就向其对应的BpBinder端发送死亡通知消息。