Android native层DeathRecipient对关联进程(如相关Service服务进程)异常关闭通知事件的监听实现源码分析

Android native层 DeathRecipient 死亡通知监听实现
本系列文章分析的安卓源码版本:【Android 10.0 版本】
此部分是在分析multimedia整体架构时由于该内容是常用实现内容,因此被抽出来单独进行分析。

要阅读本章节需有Binder机制实现原理的大致掌握,推荐可先补充另一章节内容:Android C++底层Binder通信机制原理分析总结【通俗易懂】

死亡通知是为了让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中默认空实现。
【关于Binder机制实现原理可参考另一章节:Android C++底层Binder通信机制原理分析总结【通俗易懂】

因此可以看到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端发送死亡通知消息。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 应用程序的 Java 中捕获 Native 异常可以通过以下两种方式来实现: 1. 使用 try-catch 块捕获异常 在调用 Native 方法时,放置 try-catch 块来捕获异常。用于抓住 Native 异常,然后通过 logcat 输出日志信息。 例如: ``` try { // 调用 Native 方法 } catch (Throwable e) { Log.e(TAG, "Native method threw an exception: " + e.getMessage()); e.printStackTrace(); } ``` 在 catch 块中,使用 Log.e 输出一个错误日志,并使用 printStackTrace() 打印堆栈跟踪信息。 2. 通过设置 UncaughtExceptionHandler 在应用程序的 Application 类中设置 UncaughtExceptionHandler,从而捕获 Native 异常。这个方法将捕获所有未经捕获和处理的异常。 例如: ``` public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, Throwable ex) { Log.e(TAG, "Uncaught Exception: " + ex.getMessage()); ex.printStackTrace(); // 在这里执行你的处理逻辑 // 例如重启应用程序等等 } }); } } ``` 在 UncaughtExceptionHandler 的 uncaughtException() 方法中,使用 Log.e 输出一个错误日志,并使用 printStackTrace() 打印堆栈跟踪信息。在这个方法中,还可以执行一些处理逻辑,例如重启应用程序等等。 这两种方式可以结合使用,以便完全捕获和处理 Native 异常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值