codec2 hal: add the AIDL adaptation layer [step 2]

Implement AIDL interfaces. Graphic buffer passing and input surface
are not complete yet.

Bug: 251850069
Test: m libcodec2_aidl && m
Change-Id: I71608e2528794106239ebb487d327eb19b062ee1
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index 7994d32..fa18c3e 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -15,40 +15,42 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "Codec2-Component@1.2"
+#define LOG_TAG "Codec2-Component-Aidl"
 #include <android-base/logging.h>
 
-#include <codec2/hidl/1.2/Component.h>
-#include <codec2/hidl/1.2/ComponentStore.h>
-#include <codec2/hidl/1.2/InputBufferManager.h>
+#include <codec2/aidl/Component.h>
+#include <codec2/aidl/ComponentStore.h>
+#include <codec2/aidl/InputBufferManager.h>
 
 #ifndef __ANDROID_APEX__
 #include <FilterWrapper.h>
 #endif
 
-#include <hidl/HidlBinderSupport.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
 #include <utils/Timers.h>
 
-#include <C2BqBufferPriv.h>
 #include <C2Debug.h>
 #include <C2PlatformSupport.h>
 
 #include <chrono>
 #include <thread>
 
+namespace aidl {
 namespace android {
 namespace hardware {
 namespace media {
 namespace c2 {
-namespace V1_2 {
 namespace utils {
 
-using namespace ::android;
+using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::media::bufferpool2::IClientManager;
+using ::ndk::ScopedAStatus;
 
 // ComponentListener wrapper
 struct Component::Listener : public C2Component::Listener {
 
-    Listener(const sp<Component>& component) :
+    Listener(const std::shared_ptr<Component>& component) :
         mComponent(component),
         mListener(component->mListener) {
     }
@@ -56,9 +58,9 @@
     virtual void onError_nb(
             std::weak_ptr<C2Component> /* c2component */,
             uint32_t errorCode) override {
-        sp<IComponentListener> listener = mListener.promote();
+        std::shared_ptr<IComponentListener> listener = mListener.lock();
         if (listener) {
-            Return<void> transStatus = listener->onError(Status::OK, errorCode);
+            ScopedAStatus transStatus = listener->onError(Status{Status::OK}, errorCode);
             if (!transStatus.isOk()) {
                 LOG(ERROR) << "Component::Listener::onError_nb -- "
                            << "transaction failed.";
@@ -70,20 +72,20 @@
             std::weak_ptr<C2Component> /* c2component */,
             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
             ) override {
-        sp<IComponentListener> listener = mListener.promote();
+      std::shared_ptr<IComponentListener> listener = mListener.lock();
         if (listener) {
-            hidl_vec<SettingResult> settingResults(c2settingResult.size());
+            std::vector<SettingResult> settingResults(c2settingResult.size());
             size_t ix = 0;
             for (const std::shared_ptr<C2SettingResult> &c2result :
                     c2settingResult) {
                 if (c2result) {
-                    if (!objcpy(&settingResults[ix++], *c2result)) {
+                    if (!ToAidl(&settingResults[ix++], *c2result)) {
                         break;
                     }
                 }
             }
             settingResults.resize(ix);
-            Return<void> transStatus = listener->onTripped(settingResults);
+            ScopedAStatus transStatus = listener->onTripped(settingResults);
             if (!transStatus.isOk()) {
                 LOG(ERROR) << "Component::Listener::onTripped_nb -- "
                            << "transaction failed.";
@@ -106,113 +108,57 @@
             }
         }
 
-        sp<IComponentListener> listener = mListener.promote();
+        std::shared_ptr<IComponentListener> listener = mListener.lock();
         if (listener) {
             WorkBundle workBundle;
 
-            sp<Component> strongComponent = mComponent.promote();
-            beginTransferBufferQueueBlocks(c2workItems, true);
-            if (!objcpy(&workBundle, c2workItems, strongComponent ?
+            std::shared_ptr<Component> strongComponent = mComponent.lock();
+            // TODO
+            // beginTransferBufferQueueBlocks(c2workItems, true);
+            if (!ToAidl(&workBundle, c2workItems, strongComponent ?
                     &strongComponent->mBufferPoolSender : nullptr)) {
                 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
                            << "received corrupted work items.";
-                endTransferBufferQueueBlocks(c2workItems, false, true);
+                // TODO
+                // endTransferBufferQueueBlocks(c2workItems, false, true);
                 return;
             }
-            Return<void> transStatus = listener->onWorkDone(workBundle);
+            ScopedAStatus transStatus = listener->onWorkDone(workBundle);
             if (!transStatus.isOk()) {
                 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
                            << "transaction failed.";
-                endTransferBufferQueueBlocks(c2workItems, false, true);
+                // TODO
+                // endTransferBufferQueueBlocks(c2workItems, false, true);
                 return;
             }
-            endTransferBufferQueueBlocks(c2workItems, true, true);
+            // TODO
+            // endTransferBufferQueueBlocks(c2workItems, true, true);
         }
     }
 
 protected:
-    wp<Component> mComponent;
-    wp<IComponentListener> mListener;
+    std::weak_ptr<Component> mComponent;
+    std::weak_ptr<IComponentListener> mListener;
 };
 
-// Component::Sink
-struct Component::Sink : public IInputSink {
-    std::shared_ptr<Component> mComponent;
-    sp<IConfigurable> mConfigurable;
-
-    virtual Return<Status> queue(const WorkBundle& workBundle) override {
-        return mComponent->queue(workBundle);
-    }
-
-    virtual Return<sp<IConfigurable>> getConfigurable() override {
-        return mConfigurable;
-    }
-
-    Sink(const std::shared_ptr<Component>& component);
-    virtual ~Sink() override;
-
-    // Process-wide map: Component::Sink -> C2Component.
-    static std::mutex sSink2ComponentMutex;
-    static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
-
-    static std::shared_ptr<C2Component> findLocalComponent(
-            const sp<IInputSink>& sink);
+// Component::DeathContext
+struct Component::DeathContext {
+    std::weak_ptr<Component> mWeakComp;
 };
 
-std::mutex
-        Component::Sink::sSink2ComponentMutex{};
-std::map<IInputSink*, std::weak_ptr<C2Component>>
-        Component::Sink::sSink2Component{};
-
-Component::Sink::Sink(const std::shared_ptr<Component>& component)
-        : mComponent{component},
-          mConfigurable{[&component]() -> sp<IConfigurable> {
-              Return<sp<IComponentInterface>> ret1 = component->getInterface();
-              if (!ret1.isOk()) {
-                  LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
-                  return nullptr;
-              }
-              Return<sp<IConfigurable>> ret2 =
-                      static_cast<sp<IComponentInterface>>(ret1)->
-                      getConfigurable();
-              if (!ret2.isOk()) {
-                  LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
-                  return nullptr;
-              }
-              return static_cast<sp<IConfigurable>>(ret2);
-          }()} {
-    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
-    sSink2Component.emplace(this, component->mComponent);
-}
-
-Component::Sink::~Sink() {
-    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
-    sSink2Component.erase(this);
-}
-
-std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
-        const sp<IInputSink>& sink) {
-    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
-    auto i = sSink2Component.find(sink.get());
-    if (i == sSink2Component.end()) {
-        return nullptr;
-    }
-    return i->second.lock();
-}
-
 // Component
 Component::Component(
         const std::shared_ptr<C2Component>& component,
-        const sp<IComponentListener>& listener,
-        const sp<ComponentStore>& store,
-        const sp<::android::hardware::media::bufferpool::V2_0::
-        IClientManager>& clientPoolManager)
+        const std::shared_ptr<IComponentListener>& listener,
+        const std::shared_ptr<ComponentStore>& store,
+        const std::shared_ptr<IClientManager>& clientPoolManager)
       : mComponent{component},
-        mInterface{new ComponentInterface(component->intf(),
-                                          store->getParameterCache())},
+        mInterface{SharedRefBase::make<ComponentInterface>(
+                component->intf(), store->getParameterCache())},
         mListener{listener},
         mStore{store},
-        mBufferPoolSender{clientPoolManager} {
+        mBufferPoolSender{clientPoolManager},
+        mDeathContext(nullptr) {
     // Retrieve supported parameters from store
     // TODO: We could cache this per component/interface type
     mInit = mInterface->status();
@@ -223,11 +169,11 @@
 }
 
 // Methods from ::android::hardware::media::c2::V1_1::IComponent
-Return<Status> Component::queue(const WorkBundle& workBundle) {
+ScopedAStatus Component::queue(const WorkBundle& workBundle) {
     std::list<std::unique_ptr<C2Work>> c2works;
 
-    if (!objcpy(&c2works, workBundle)) {
-        return Status::CORRUPTED;
+    if (!FromAidl(&c2works, workBundle)) {
+        return ScopedAStatus::fromServiceSpecificError(Status::CORRUPTED);
     }
 
     // Register input buffers.
@@ -238,10 +184,14 @@
         }
     }
 
-    return static_cast<Status>(mComponent->queue_nb(&c2works));
+    c2_status_t err = mComponent->queue_nb(&c2works);
+    if (err == C2_OK) {
+        return ScopedAStatus::ok();
+    }
+    return ScopedAStatus::fromServiceSpecificError(err);
 }
 
-Return<void> Component::flush(flush_cb _hidl_cb) {
+ScopedAStatus Component::flush(WorkBundle *flushedWorkBundle) {
     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
     c2_status_t c2res = mComponent->flush_sm(
             C2Component::FLUSH_COMPONENT,
@@ -260,80 +210,29 @@
         }
     }
 
-    WorkBundle flushedWorkBundle;
-    Status res = static_cast<Status>(c2res);
-    beginTransferBufferQueueBlocks(c2flushedWorks, true);
+    // TODO
+    // beginTransferBufferQueueBlocks(c2flushedWorks, true);
     if (c2res == C2_OK) {
-        if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
-            res = Status::CORRUPTED;
+        if (!ToAidl(flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+            c2res = C2_CORRUPTED;
         }
     }
-    _hidl_cb(res, flushedWorkBundle);
-    endTransferBufferQueueBlocks(c2flushedWorks, true, true);
-    return Void();
+    // TODO
+    // endTransferBufferQueueBlocks(c2flushedWorks, true, true);
+    if (c2res == C2_OK) {
+        return ScopedAStatus::ok();
+    }
+    return ScopedAStatus::fromServiceSpecificError(c2res);
 }
 
-Return<Status> Component::drain(bool withEos) {
-    return static_cast<Status>(mComponent->drain_nb(withEos ?
+ScopedAStatus Component::drain(bool withEos) {
+    c2_status_t res = mComponent->drain_nb(withEos ?
             C2Component::DRAIN_COMPONENT_WITH_EOS :
-            C2Component::DRAIN_COMPONENT_NO_EOS));
-}
-
-Return<Status> Component::setOutputSurface(
-        uint64_t blockPoolId,
-        const sp<HGraphicBufferProducer2>& surface) {
-    std::shared_ptr<C2BlockPool> pool;
-    GetCodec2BlockPool(blockPoolId, mComponent, &pool);
-    if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
-        std::shared_ptr<C2BufferQueueBlockPool> bqPool =
-                std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
-        C2BufferQueueBlockPool::OnRenderCallback cb =
-            [this](uint64_t producer, int32_t slot, int64_t nsecs) {
-                // TODO: batch this
-                hidl_vec<IComponentListener::RenderedFrame> rendered;
-                rendered.resize(1);
-                rendered[0] = { producer, slot, nsecs };
-                (void)mListener->onFramesRendered(rendered).isOk();
-        };
-        if (bqPool) {
-            bqPool->setRenderCallback(cb);
-            bqPool->configureProducer(surface);
-        }
+            C2Component::DRAIN_COMPONENT_NO_EOS);
+    if (res == C2_OK) {
+        return ScopedAStatus::ok();
     }
-    return Status::OK;
-}
-
-Return<void> Component::connectToInputSurface(
-        const sp<IInputSurface>& inputSurface,
-        connectToInputSurface_cb _hidl_cb) {
-    Status status;
-    sp<IInputSurfaceConnection> connection;
-    auto transStatus = inputSurface->connect(
-            asInputSink(),
-            [&status, &connection](
-                    Status s, const sp<IInputSurfaceConnection>& c) {
-                status = s;
-                connection = c;
-            }
-        );
-    _hidl_cb(status, connection);
-    return Void();
-}
-
-Return<void> Component::connectToOmxInputSurface(
-        const sp<HGraphicBufferProducer1>& producer,
-        const sp<::android::hardware::media::omx::V1_0::
-        IGraphicBufferSource>& source,
-        connectToOmxInputSurface_cb _hidl_cb) {
-    (void)producer;
-    (void)source;
-    (void)_hidl_cb;
-    return Void();
-}
-
-Return<Status> Component::disconnectFromInputSurface() {
-    // TODO implement
-    return Status::OK;
+    return ScopedAStatus::fromServiceSpecificError(res);
 }
 
 namespace /* unnamed */ {
@@ -390,130 +289,122 @@
 
 } // unnamed namespace
 
-Return<void> Component::createBlockPool(
-        uint32_t allocatorId,
-        createBlockPool_cb _hidl_cb) {
-    std::shared_ptr<C2BlockPool> blockPool;
+ScopedAStatus Component::createBlockPool(
+        const IComponent::BlockPoolAllocator &allocator,
+        IComponent::BlockPool *blockPool) {
+    std::shared_ptr<C2BlockPool> c2BlockPool;
+    static constexpr IComponent::BlockPoolAllocator::Tag ALLOCATOR_ID =
+        IComponent::BlockPoolAllocator::allocatorId;
+    static constexpr IComponent::BlockPoolAllocator::Tag IGBA =
+        IComponent::BlockPoolAllocator::igba;
+    c2_status_t status = C2_OK;
+    switch (allocator.getTag()) {
+        case ALLOCATOR_ID:
 #ifdef __ANDROID_APEX__
-    c2_status_t status = CreateCodec2BlockPool(
-            static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
-            mComponent,
-            &blockPool);
+            status = CreateCodec2BlockPool(
+                    static_cast<::android::C2PlatformAllocatorStore::id_t>(
+                            allocator.get<ALLOCATOR_ID>()),
+                    mComponent,
+                    &c2BlockPool);
 #else
-    c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool(
-            static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
-            mComponent,
-            &blockPool);
+            status = ComponentStore::GetFilterWrapper()->createBlockPool(
+                    static_cast<::android::C2PlatformAllocatorStore::id_t>(
+                            allocator.get<ALLOCATOR_ID>()),
+                    mComponent,
+                    &c2BlockPool);
 #endif
-    if (status != C2_OK) {
-        blockPool = nullptr;
+            if (status != C2_OK) {
+                blockPool = nullptr;
+            }
+            break;
+        case IGBA:
+            // FIXME
+            break;
+        default:
+            break;
     }
     if (blockPool) {
         mBlockPoolsMutex.lock();
-        mBlockPools.emplace(blockPool->getLocalId(), blockPool);
+        mBlockPools.emplace(c2BlockPool->getLocalId(), c2BlockPool);
         mBlockPoolsMutex.unlock();
     } else if (status == C2_OK) {
         status = C2_CORRUPTED;
     }
 
-    _hidl_cb(static_cast<Status>(status),
-            blockPool ? blockPool->getLocalId() : 0,
-            new CachedConfigurable(
-            std::make_unique<BlockPoolIntf>(blockPool)));
-    return Void();
+    blockPool->blockPoolId = c2BlockPool ? c2BlockPool->getLocalId() : 0;
+    blockPool->configurable = SharedRefBase::make<CachedConfigurable>(
+            std::make_unique<BlockPoolIntf>(c2BlockPool));
+    if (status == C2_OK) {
+        return ScopedAStatus::ok();
+    }
+    return ScopedAStatus::fromServiceSpecificError(status);
 }
 
-Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
+ScopedAStatus Component::destroyBlockPool(int64_t blockPoolId) {
     std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
-    return mBlockPools.erase(blockPoolId) == 1 ?
-            Status::OK : Status::CORRUPTED;
+    if (mBlockPools.erase(blockPoolId) == 1) {
+        return ScopedAStatus::ok();
+    }
+    return ScopedAStatus::fromServiceSpecificError(Status::CORRUPTED);
 }
 
-Return<Status> Component::start() {
-    return static_cast<Status>(mComponent->start());
+ScopedAStatus Component::start() {
+    c2_status_t status = mComponent->start();
+    if (status == C2_OK) {
+        return ScopedAStatus::ok();
+    }
+    return ScopedAStatus::fromServiceSpecificError(status);
 }
 
-Return<Status> Component::stop() {
+ScopedAStatus Component::stop() {
     InputBufferManager::unregisterFrameData(mListener);
-    return static_cast<Status>(mComponent->stop());
+    c2_status_t status = mComponent->stop();
+    if (status == C2_OK) {
+        return ScopedAStatus::ok();
+    }
+    return ScopedAStatus::fromServiceSpecificError(status);
 }
 
-Return<Status> Component::reset() {
-    Status status = static_cast<Status>(mComponent->reset());
+ScopedAStatus Component::reset() {
+    c2_status_t status = mComponent->reset();
     {
         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
         mBlockPools.clear();
     }
     InputBufferManager::unregisterFrameData(mListener);
-    return status;
+    if (status == C2_OK) {
+        return ScopedAStatus::ok();
+    }
+    return ScopedAStatus::fromServiceSpecificError(status);
 }
 
-Return<Status> Component::release() {
-    Status status = static_cast<Status>(mComponent->release());
+ScopedAStatus Component::release() {
+    c2_status_t status = mComponent->release();
     {
         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
         mBlockPools.clear();
     }
     InputBufferManager::unregisterFrameData(mListener);
-    return status;
-}
-
-Return<sp<IComponentInterface>> Component::getInterface() {
-    return sp<IComponentInterface>(mInterface);
-}
-
-Return<sp<IInputSink>> Component::asInputSink() {
-    std::lock_guard<std::mutex> lock(mSinkMutex);
-    if (!mSink) {
-        mSink = new Sink(shared_from_this());
+    if (status == C2_OK) {
+        return ScopedAStatus::ok();
     }
-    return {mSink};
+    return ScopedAStatus::fromServiceSpecificError(status);
 }
 
-Return<void> Component::configureVideoTunnel(
-        uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
+ScopedAStatus Component::getInterface(
+        std::shared_ptr<IComponentInterface> *intf) {
+    *intf = mInterface;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Component::configureVideoTunnel(
+        int32_t avSyncHwId, NativeHandle *handle) {
     (void)avSyncHwId;
-    _hidl_cb(Status::OMITTED, hidl_handle{});
-    return Void();
+    (void)handle;
+    return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
 }
 
-Return<Status> Component::setOutputSurfaceWithSyncObj(
-        uint64_t blockPoolId, const sp<HGraphicBufferProducer2>& surface,
-        const SurfaceSyncObj& syncObject) {
-    std::shared_ptr<C2BlockPool> pool;
-    GetCodec2BlockPool(blockPoolId, mComponent, &pool);
-    if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
-        std::shared_ptr<C2BufferQueueBlockPool> bqPool =
-                std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
-        C2BufferQueueBlockPool::OnRenderCallback cb =
-            [this](uint64_t producer, int32_t slot, int64_t nsecs) {
-                // TODO: batch this
-                hidl_vec<IComponentListener::RenderedFrame> rendered;
-                rendered.resize(1);
-                rendered[0] = { producer, slot, nsecs };
-                (void)mListener->onFramesRendered(rendered).isOk();
-        };
-        if (bqPool) {
-            const native_handle_t *h = syncObject.syncMemory;
-            native_handle_t *syncMemory = h ? native_handle_clone(h) : nullptr;
-            uint64_t bqId = syncObject.bqId;
-            uint32_t generationId = syncObject.generationId;
-            uint64_t consumerUsage = syncObject.consumerUsage;
-
-            bqPool->setRenderCallback(cb);
-            bqPool->configureProducer(surface, syncMemory, bqId,
-                                      generationId, consumerUsage);
-        }
-    }
-    return Status::OK;
-}
-
-std::shared_ptr<C2Component> Component::findLocalComponent(
-        const sp<IInputSink>& sink) {
-    return Component::Sink::findLocalComponent(sink);
-}
-
-void Component::initListener(const sp<Component>& self) {
+void Component::initListener(const std::shared_ptr<Component>& self) {
     std::shared_ptr<C2Component::Listener> c2listener =
             std::make_shared<Listener>(self);
     c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
@@ -521,46 +412,38 @@
         mInit = res;
     }
 
-    struct ListenerDeathRecipient : public HwDeathRecipient {
-        ListenerDeathRecipient(const wp<Component>& comp)
-            : component{comp} {
-        }
+    mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(OnBinderDied));
+    mDeathContext = new DeathContext{weak_from_this()};
+    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), OnBinderUnlinked);
+    AIBinder_linkToDeath(mListener->asBinder().get(), mDeathRecipient.get(), mDeathContext);
+}
 
-        virtual void serviceDied(
-                uint64_t /* cookie */,
-                const wp<::android::hidl::base::V1_0::IBase>& /* who */
-                ) override {
-            auto strongComponent = component.promote();
-            if (strongComponent) {
-                LOG(INFO) << "Client died ! release the component !!";
-                strongComponent->release();
-            } else {
-                LOG(ERROR) << "Client died ! no component to release !!";
-            }
-        }
-
-        wp<Component> component;
-    };
-
-    mDeathRecipient = new ListenerDeathRecipient(self);
-    Return<bool> transStatus = mListener->linkToDeath(
-            mDeathRecipient, 0);
-    if (!transStatus.isOk()) {
-        LOG(ERROR) << "Listener linkToDeath() transaction failed.";
+// static
+void Component::OnBinderDied(void *cookie) {
+    DeathContext *context = (DeathContext *)cookie;
+    std::shared_ptr<Component> comp = context->mWeakComp.lock();
+    if (comp) {
+        comp->release();
     }
-    if (!static_cast<bool>(transStatus)) {
-        LOG(DEBUG) << "Listener linkToDeath() call failed.";
-    }
+}
+
+// static
+void Component::OnBinderUnlinked(void *cookie) {
+    delete (DeathContext *)cookie;
 }
 
 Component::~Component() {
     InputBufferManager::unregisterFrameData(mListener);
     mStore->reportComponentDeath(this);
+    if (mDeathRecipient.get()) {
+        AIBinder_unlinkToDeath(mListener->asBinder().get(), mDeathRecipient.get(), mDeathContext);
+    }
 }
 
 } // namespace utils
-} // namespace V1_2
 } // namespace c2
 } // namespace media
 } // namespace hardware
 } // namespace android
+} // namespace aidl