codec2 hal: Codec2Client AIDL implementation

- Implement Codec2Client API on top of AIDL implementation
- TODO: input surface implementation is missing
- Fix libmediaplayerservice Codec2Client dependency

Bug: 251850069
Test: presubmit
Change-Id: I30c3cf24b408d20e4cae1c7e3d98bad8a7301e74
diff --git a/media/codec2/hal/aidl/ParamTypes.cpp b/media/codec2/hal/aidl/ParamTypes.cpp
index 0a430f9..7026f4c 100644
--- a/media/codec2/hal/aidl/ParamTypes.cpp
+++ b/media/codec2/hal/aidl/ParamTypes.cpp
@@ -157,14 +157,13 @@
 namespace c2 {
 namespace utils {
 
+// TODO: read it from aconfig flags
+bool IsEnabled() { return false; }
+
 const char* asString(Status status, const char* def) {
     return asString(static_cast<c2_status_t>(status.status), def);
 }
 
-namespace /* unnamed */ {
-
-} // unnamed namespace
-
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
 bool ToAidl(
         FieldSupportedValuesQuery* d,
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
index ff69039..3f82ee3 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
@@ -37,11 +37,14 @@
 namespace c2 {
 namespace utils {
 
+// Returns true iff AIDL c2 HAL is enabled
+bool IsEnabled();
+
 // Make asString() and operator<< work with Status as well as c2_status_t.
 C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(Status);
 
 /**
- * All objcpy() functions will return a boolean value indicating whether the
+ * All To/FromAidl() functions will return a boolean value indicating whether the
  * conversion succeeds or not.
  */
 
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 61ec10e..22aa35e 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -42,6 +42,7 @@
         "android.hardware.media.c2@1.0",
         "android.hardware.media.c2@1.1",
         "android.hardware.media.c2@1.2",
+        "android.hardware.media.bufferpool2-V1-ndk",
         "android.hardware.media.c2-V1-ndk",
         "libbase",
         "libbinder",
@@ -56,11 +57,16 @@
         "libhidlbase",
         "liblog",
         "libnativewindow",
+        "libstagefright_aidl_bufferpool2",
         "libstagefright_bufferpool@2.0.1",
         "libui",
         "libutils",
     ],
 
+    static_libs: [
+        "libaidlcommonsupport",
+    ],
+
     export_include_dirs: [
         "include",
     ],
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 00820eb..accb9fd 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -24,7 +24,6 @@
 #include <C2Config.h> // for C2StreamUsageTuning
 #include <C2PlatformSupport.h>
 
-#include <android/binder_auto_utils.h>
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
 #include <android/hardware/media/c2/1.0/IComponent.h>
 #include <android/hardware/media/c2/1.0/IComponentInterface.h>
@@ -33,6 +32,8 @@
 #include <android/hardware/media/c2/1.0/IConfigurable.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
 
+#include <aidl/android/hardware/media/bufferpool2/IClientManager.h>
+#include <aidl/android/hardware/media/c2/BnComponentListener.h>
 #include <aidl/android/hardware/media/c2/FieldSupportedValues.h>
 #include <aidl/android/hardware/media/c2/FieldSupportedValuesQuery.h>
 #include <aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.h>
@@ -41,9 +42,17 @@
 #include <aidl/android/hardware/media/c2/IComponentStore.h>
 #include <aidl/android/hardware/media/c2/IConfigurable.h>
 #include <aidl/android/hardware/media/c2/ParamDescriptor.h>
+#include <aidl/android/hardware/media/c2/StructDescriptor.h>
 
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <bufferpool/ClientManager.h>
+#include <bufferpool2/ClientManager.h>
+#include <codec2/aidl/BufferTypes.h>
 #include <codec2/aidl/ParamTypes.h>
 #include <codec2/hidl/1.0/types.h>
 #include <codec2/hidl/1.1/types.h>
@@ -85,6 +94,7 @@
         V2_0::utils::H2BGraphicBufferProducer;
 using ::android::hardware::media::c2::V1_2::SurfaceSyncObj;
 
+namespace bufferpool2_aidl = ::aidl::android::hardware::media::bufferpool2;
 namespace bufferpool_hidl = ::android::hardware::media::bufferpool::V2_0;
 namespace c2_aidl = ::aidl::android::hardware::media::c2;
 namespace c2_hidl_base = ::android::hardware::media::c2;
@@ -178,6 +188,20 @@
     }
 };
 
+c2_status_t GetC2Status(const ::ndk::ScopedAStatus &transStatus, const char *method) {
+    if (!transStatus.isOk()) {
+        if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+            c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
+            LOG(DEBUG) << method << " -- call failed: " << status << ".";
+            return status;
+        } else {
+            LOG(ERROR) << method << " -- transaction failed.";
+            return C2_TRANSACTION_FAILED;
+        }
+    }
+    return C2_OK;
+}
+
 }  // unnamed namespace
 
 // This class caches a Codec2Client object and its component traits. The client
@@ -605,18 +629,11 @@
     }
     c2_aidl::Params result;
     ndk::ScopedAStatus transStatus = mBase->query(indices, (mayBlock == C2_MAY_BLOCK), &result);
-    if (!transStatus.isOk()) {
-        if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
-            c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
-            LOG(DEBUG) << "query -- call failed: " << status << ".";
-            return status;
-        } else {
-            LOG(ERROR) << "query -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
+    c2_status_t status = GetC2Status(transStatus, "query");
+    if (status != C2_OK) {
+        return status;
     }
 
-    c2_status_t status = C2_OK;
     std::vector<C2Param*> paramPointers;
     if (!c2_aidl::utils::ParseParamsBlob(&paramPointers, result)) {
         LOG(ERROR) << "query -- error while parsing params.";
@@ -685,17 +702,10 @@
     }
     c2_aidl::IConfigurable::ConfigResult result;
     ndk::ScopedAStatus transStatus = mBase->config(aidlParams, (mayBlock == C2_MAY_BLOCK), &result);
-    if (!transStatus.isOk()) {
-        if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
-            c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
-            LOG(DEBUG) << "config -- call failed: " << status << ".";
-            return status;
-        } else {
-            LOG(ERROR) << "config -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
+    c2_status_t status = GetC2Status(transStatus, "config");
+    if (status != C2_OK) {
+        return status;
     }
-    c2_status_t status = C2_OK;
     size_t i = failures->size();
     failures->resize(i + result.failures.size());
     for (const c2_aidl::SettingResult& sf : result.failures) {
@@ -720,17 +730,10 @@
             std::numeric_limits<uint32_t>::min(),
             std::numeric_limits<uint32_t>::max(),
             &result);
-    if (!transStatus.isOk()) {
-        if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
-            c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
-            LOG(DEBUG) << "querySupportedParams -- call failed: " << status << ".";
-            return status;
-        } else {
-            LOG(ERROR) << "querySupportedParams -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
+    c2_status_t status = GetC2Status(transStatus, "querySupportedParams");
+    if (status != C2_OK) {
+        return status;
     }
-    c2_status_t status = C2_OK;
     size_t i = params->size();
     params->resize(i + result.size());
     for (const c2_aidl::ParamDescriptor& sp : result) {
@@ -756,17 +759,10 @@
     std::vector<c2_aidl::FieldSupportedValuesQueryResult> result;
     ndk::ScopedAStatus transStatus = mBase->querySupportedValues(
             inFields, (mayBlock == C2_MAY_BLOCK), &result);
-    if (!transStatus.isOk()) {
-        if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
-            c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
-            LOG(DEBUG) << "querySupportedValues -- call failed: " << status << ".";
-            return status;
-        } else {
-            LOG(ERROR) << "querySupportedValues -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
+    c2_status_t status = GetC2Status(transStatus, "querySupportedValues");
+    if (status != C2_OK) {
+        return status;
     }
-    c2_status_t status = C2_OK;
     if (result.size() != fields.size()) {
         LOG(ERROR) << "querySupportedValues -- "
                       "input and output lists "
@@ -922,14 +918,119 @@
 
 };
 
-// Codec2Client::Component::BufferPoolSender
-struct Codec2Client::Component::BufferPoolSender :
+// Codec2Client::Component::AidlListener
+struct Codec2Client::Component::AidlListener : public c2_aidl::BnComponentListener {
+    std::weak_ptr<Component> component;
+    std::weak_ptr<Listener> base;
+
+    virtual ::ndk::ScopedAStatus onWorkDone(const c2_aidl::WorkBundle& workBundle) override {
+        std::list<std::unique_ptr<C2Work>> workItems;
+        if (!c2_aidl::utils::FromAidl(&workItems, workBundle)) {
+            LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
+            return ::ndk::ScopedAStatus::ok();
+        }
+        // release input buffers potentially held by the component from queue
+        std::shared_ptr<Codec2Client::Component> strongComponent =
+                component.lock();
+        if (strongComponent) {
+            strongComponent->handleOnWorkDone(workItems);
+        }
+        if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
+            listener->onWorkDone(component, workItems);
+        } else {
+            LOG(DEBUG) << "onWorkDone -- listener died.";
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    virtual ::ndk::ScopedAStatus onTripped(
+            const std::vector<c2_aidl::SettingResult>& settingResults) override {
+        std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
+                settingResults.size());
+        for (size_t i = 0; i < settingResults.size(); ++i) {
+            std::unique_ptr<C2SettingResult> c2SettingResult;
+            if (!c2_aidl::utils::FromAidl(&c2SettingResult, settingResults[i])) {
+                LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
+                return ::ndk::ScopedAStatus::ok();
+            }
+            c2SettingResults[i] = std::move(c2SettingResult);
+        }
+        if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
+            listener->onTripped(component, c2SettingResults);
+        } else {
+            LOG(DEBUG) << "onTripped -- listener died.";
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    virtual ::ndk::ScopedAStatus onError(const c2_aidl::Status &s, int32_t errorCode) override {
+        LOG(DEBUG) << "onError --"
+                   << " status = " << s.status
+                   << ", errorCode = " << errorCode
+                   << ".";
+        if (std::shared_ptr<Listener> listener = base.lock()) {
+            listener->onError(component, s.status == c2_aidl::Status::OK ?
+                    errorCode : static_cast<c2_status_t>(s.status));
+        } else {
+            LOG(DEBUG) << "onError -- listener died.";
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    virtual ::ndk::ScopedAStatus onFramesRendered(
+            const std::vector<RenderedFrame>& renderedFrames) override {
+        std::shared_ptr<Listener> listener = base.lock();
+        if (!listener) {
+            LOG(DEBUG) << "onFramesRendered -- listener died.";
+            return ::ndk::ScopedAStatus::ok();
+        }
+        for (const RenderedFrame& renderedFrame : renderedFrames) {
+            listener->onFrameRendered(
+                    renderedFrame.bufferQueueId,
+                    renderedFrame.slotId,
+                    renderedFrame.timestampNs);
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    virtual ::ndk::ScopedAStatus onInputBuffersReleased(
+            const std::vector<InputBuffer>& inputBuffers) override {
+        std::shared_ptr<Listener> listener = base.lock();
+        if (!listener) {
+            LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
+            return ::ndk::ScopedAStatus::ok();
+        }
+        for (const InputBuffer& inputBuffer : inputBuffers) {
+            LOG(VERBOSE) << "onInputBuffersReleased --"
+                            " received death notification of"
+                            " input buffer:"
+                            " frameIndex = " << inputBuffer.frameIndex
+                         << ", bufferIndex = " << inputBuffer.arrayIndex
+                         << ".";
+            listener->onInputBufferDone(
+                    inputBuffer.frameIndex, inputBuffer.arrayIndex);
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+};
+
+// Codec2Client::Component::HidlBufferPoolSender
+struct Codec2Client::Component::HidlBufferPoolSender :
         hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
-    BufferPoolSender()
+    HidlBufferPoolSender()
           : hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
     }
 };
 
+// Codec2Client::Component::AidlBufferPoolSender
+struct Codec2Client::Component::AidlBufferPoolSender :
+        c2_aidl::utils::DefaultBufferPoolSender {
+    AidlBufferPoolSender()
+          : c2_aidl::utils::DefaultBufferPoolSender() {
+    }
+};
+
 // Codec2Client::Component::OutputBufferQueue
 struct Codec2Client::Component::OutputBufferQueue :
         hardware::media::c2::OutputBufferQueue {
@@ -939,36 +1040,53 @@
 };
 
 // Codec2Client
-Codec2Client::Codec2Client(sp<Base> const& base,
+Codec2Client::Codec2Client(sp<HidlBase> const& base,
                            sp<c2_hidl::IConfigurable> const& configurable,
                            size_t serviceIndex)
       : Configurable{configurable},
-        mBase1_0{base},
-        mBase1_1{Base1_1::castFrom(base)},
-        mBase1_2{Base1_2::castFrom(base)},
+        mHidlBase1_0{base},
+        mHidlBase1_1{HidlBase1_1::castFrom(base)},
+        mHidlBase1_2{HidlBase1_2::castFrom(base)},
         mServiceIndex{serviceIndex} {
     Return<sp<bufferpool_hidl::IClientManager>> transResult = base->getPoolClientManager();
     if (!transResult.isOk()) {
         LOG(ERROR) << "getPoolClientManager -- transaction failed.";
     } else {
-        mHostPoolManager = static_cast<sp<bufferpool_hidl::IClientManager>>(transResult);
+        mHidlHostPoolManager = static_cast<sp<bufferpool_hidl::IClientManager>>(transResult);
     }
 }
 
-sp<Codec2Client::Base> const& Codec2Client::getBase() const {
-    return mBase1_0;
+Codec2Client::Codec2Client(std::shared_ptr<AidlBase> const& base,
+                           std::shared_ptr<c2_aidl::IConfigurable> const& configurable,
+                           size_t serviceIndex)
+      : Configurable{configurable},
+        mAidlBase{base},
+        mServiceIndex{serviceIndex} {
+    ::ndk::ScopedAStatus transStatus = base->getPoolClientManager(&mAidlHostPoolManager);
+    if (!transStatus.isOk()) {
+        LOG(ERROR) << "getPoolClientManager -- transaction failed.";
+        mAidlHostPoolManager.reset();
+    }
 }
 
-sp<Codec2Client::Base1_0> const& Codec2Client::getBase1_0() const {
-    return mBase1_0;
+sp<Codec2Client::HidlBase> const& Codec2Client::getHidlBase() const {
+    return mHidlBase1_0;
 }
 
-sp<Codec2Client::Base1_1> const& Codec2Client::getBase1_1() const {
-    return mBase1_1;
+sp<Codec2Client::HidlBase1_0> const& Codec2Client::getHidlBase1_0() const {
+    return mHidlBase1_0;
 }
 
-sp<Codec2Client::Base1_2> const& Codec2Client::getBase1_2() const {
-    return mBase1_2;
+sp<Codec2Client::HidlBase1_1> const& Codec2Client::getHidlBase1_1() const {
+    return mHidlBase1_1;
+}
+
+sp<Codec2Client::HidlBase1_2> const& Codec2Client::getHidlBase1_2() const {
+    return mHidlBase1_2;
+}
+
+::ndk::SpAIBinder Codec2Client::getAidlBase() const {
+    return mAidlBase ? mAidlBase->asBinder() : nullptr;
 }
 
 std::string const& Codec2Client::getServiceName() const {
@@ -979,13 +1097,41 @@
         const C2String& name,
         const std::shared_ptr<Codec2Client::Listener>& listener,
         std::shared_ptr<Codec2Client::Component>* const component) {
+    if (mAidlBase) {
+        std::shared_ptr<Component::AidlListener> aidlListener =
+                Component::AidlListener::make<Component::AidlListener>();
+        aidlListener->base = listener;
+        std::shared_ptr<c2_aidl::IComponent> aidlComponent;
+        ::ndk::ScopedAStatus transStatus = mAidlBase->createComponent(
+                name,
+                aidlListener,
+                bufferpool2_aidl::implementation::ClientManager::getInstance(),
+                &aidlComponent);
+        c2_status_t status = GetC2Status(transStatus, "createComponent");
+        if (status != C2_OK) {
+            return status;
+        } else if (!aidlComponent) {
+            LOG(ERROR) << "createComponent(" << name.c_str()
+                       << ") -- null component.";
+            return C2_CORRUPTED;
+        }
+        *component = std::make_shared<Codec2Client::Component>(aidlComponent);
+        status = (*component)->setDeathListener((*component), listener);
+        if (status != C2_OK) {
+            LOG(ERROR) << "createComponent(" << name.c_str()
+                       << ") -- failed to set up death listener: "
+                       << status << ".";
+        }
+        (*component)->mAidlBufferPoolSender->setReceiver(mAidlHostPoolManager);
+        return status;
+    }
 
     c2_status_t status;
     sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
     hidlListener->base = listener;
     Return<void> transStatus;
-    if (mBase1_2) {
-        transStatus = mBase1_2->createComponent_1_2(
+    if (mHidlBase1_2) {
+        transStatus = mHidlBase1_2->createComponent_1_2(
             name,
             hidlListener,
             bufferpool_hidl::implementation::ClientManager::getInstance(),
@@ -1000,8 +1146,8 @@
                 hidlListener->component = *component;
             });
     }
-    else if (mBase1_1) {
-        transStatus = mBase1_1->createComponent_1_1(
+    else if (mHidlBase1_1) {
+        transStatus = mHidlBase1_1->createComponent_1_1(
             name,
             hidlListener,
             bufferpool_hidl::implementation::ClientManager::getInstance(),
@@ -1015,8 +1161,8 @@
                 *component = std::make_shared<Codec2Client::Component>(c);
                 hidlListener->component = *component;
             });
-    } else if (mBase1_0) { // ver1_0
-        transStatus = mBase1_0->createComponent(
+    } else if (mHidlBase1_0) { // ver1_0
+        transStatus = mHidlBase1_0->createComponent(
             name,
             hidlListener,
             bufferpool_hidl::implementation::ClientManager::getInstance(),
@@ -1059,15 +1205,32 @@
                    << status << ".";
     }
 
-    (*component)->mBufferPoolSender->setReceiver(mHostPoolManager);
+    (*component)->mHidlBufferPoolSender->setReceiver(mHidlHostPoolManager);
     return status;
 }
 
 c2_status_t Codec2Client::createInterface(
         const C2String& name,
         std::shared_ptr<Codec2Client::Interface>* const interface) {
+    if (mAidlBase) {
+        std::shared_ptr<c2_aidl::IComponentInterface> aidlInterface;
+        ::ndk::ScopedAStatus transStatus = mAidlBase->createInterface(
+                name,
+                &aidlInterface);
+        c2_status_t status = GetC2Status(transStatus, "createInterface");
+        if (status != C2_OK) {
+            return status;
+        } else if (!aidlInterface) {
+            LOG(ERROR) << "createInterface(" << name.c_str()
+                       << ") -- null interface.";
+            return C2_CORRUPTED;
+        }
+        interface->reset(new Codec2Client::Interface(aidlInterface));
+        return C2_OK;
+    }
+
     c2_status_t status;
-    Return<void> transStatus = mBase1_0->createInterface(
+    Return<void> transStatus = mHidlBase1_0->createInterface(
             name,
             [&status, interface](
                     c2_hidl::Status s,
@@ -1098,8 +1261,13 @@
 
 c2_status_t Codec2Client::createInputSurface(
         std::shared_ptr<InputSurface>* const inputSurface) {
+    if (mAidlBase) {
+        // FIXME
+        return C2_OMITTED;
+    }
+
     c2_status_t status;
-    Return<void> transStatus = mBase1_0->createInputSurface(
+    Return<void> transStatus = mHidlBase1_0->createInputSurface(
             [&status, inputSurface](
                     c2_hidl::Status s,
                     const sp<c2_hidl::IInputSurface>& i) {
@@ -1127,7 +1295,29 @@
         bool* success) const {
     std::vector<C2Component::Traits> traits;
     std::string const& serviceName = getServiceName();
-    Return<void> transStatus = mBase1_0->listComponents(
+
+    if (mAidlBase) {
+        std::vector<c2_aidl::IComponentStore::ComponentTraits> aidlTraits;
+        ::ndk::ScopedAStatus transStatus = mAidlBase->listComponents(&aidlTraits);
+        if (!transStatus.isOk()) {
+            LOG(ERROR) << "_listComponents -- transaction failed.";
+            *success = false;
+        } else {
+            traits.resize(aidlTraits.size());
+            *success = true;
+            for (size_t i = 0; i < aidlTraits.size(); ++i) {
+                if (!c2_aidl::utils::FromAidl(&traits[i], aidlTraits[i])) {
+                    LOG(ERROR) << "_listComponents -- corrupted output.";
+                    *success = false;
+                    traits.clear();
+                    break;
+                }
+                traits[i].owner = serviceName;
+            }
+        }
+        return traits;
+    }
+    Return<void> transStatus = mHidlBase1_0->listComponents(
             [&traits, &serviceName](c2_hidl::Status s,
                    const hidl_vec<c2_hidl::IComponentStore::ComponentTraits>& t) {
                 if (s != c2_hidl::Status::OK) {
@@ -1163,12 +1353,12 @@
     return C2_OMITTED;
 }
 
-std::shared_ptr<C2ParamReflector>
-        Codec2Client::getParamReflector() {
+std::shared_ptr<C2ParamReflector> Codec2Client::getParamReflector() {
     // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
     // should reflect the HAL API.
-    struct SimpleParamReflector : public C2ParamReflector {
-        virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const {
+    struct HidlSimpleParamReflector : public C2ParamReflector {
+        std::unique_ptr<C2StructDescriptor> describe(
+                C2Param::CoreIndex coreIndex) const override {
             hidl_vec<c2_hidl::ParamIndex> indices(1);
             indices[0] = static_cast<c2_hidl::ParamIndex>(coreIndex.coreIndex());
             std::unique_ptr<C2StructDescriptor> descriptor;
@@ -1210,80 +1400,112 @@
             return descriptor;
         }
 
-        SimpleParamReflector(sp<Base> base)
+        HidlSimpleParamReflector(sp<HidlBase> base)
             : mBase(base) { }
 
-        sp<Base> mBase;
+        sp<HidlBase> mBase;
+    };
+    struct AidlSimpleParamReflector : public C2ParamReflector {
+        std::unique_ptr<C2StructDescriptor> describe(
+                C2Param::CoreIndex coreIndex) const override {
+            std::vector<c2_aidl::StructDescriptor> aidlDesc;
+            std::unique_ptr<C2StructDescriptor> descriptor;
+            ::ndk::ScopedAStatus transStatus = mBase->getStructDescriptors(
+                    {int32_t(coreIndex.coreIndex())},
+                    &aidlDesc);
+            c2_status_t status = GetC2Status(transStatus, "describe");
+            if (status != C2_OK) {
+                descriptor.reset();
+            } else if (!c2_aidl::utils::FromAidl(&descriptor, aidlDesc[0])) {
+                LOG(ERROR) << "describe -- conversion failed.";
+                descriptor.reset();
+            }
+            return descriptor;
+        }
+
+        AidlSimpleParamReflector(const std::shared_ptr<AidlBase> &base)
+            : mBase(base) { }
+
+        std::shared_ptr<AidlBase> mBase;
     };
 
-    return std::make_shared<SimpleParamReflector>(mBase1_0);
+    if (mAidlBase) {
+        return std::make_shared<AidlSimpleParamReflector>(mAidlBase);
+    }
+    return std::make_shared<HidlSimpleParamReflector>(mHidlBase1_0);
 };
 
-std::vector<std::string> const& Codec2Client::GetServiceNames() {
-    static std::vector<std::string> sServiceNames{[]() {
-        using ::android::hardware::media::c2::V1_0::IComponentStore;
-        using ::android::hidl::manager::V1_2::IServiceManager;
+std::vector<std::string> Codec2Client::CacheServiceNames() {
+    std::vector<std::string> names;
 
-        while (true) {
-            sp<IServiceManager> serviceManager = IServiceManager::getService();
-            CHECK(serviceManager) << "Hardware service manager is not running.";
+    if (c2_aidl::utils::IsEnabled()) {
+        // Get AIDL service names
+        AServiceManager_forEachDeclaredInstance(
+                AidlBase::descriptor, &names, [](const char *name, void *context) {
+                    std::vector<std::string> *names = (std::vector<std::string> *)context;
+                    names->emplace_back(name);
+                });
+    }
 
-            // There are three categories of services based on names.
-            std::vector<std::string> defaultNames; // Prefixed with "default"
-            std::vector<std::string> vendorNames;  // Prefixed with "vendor"
-            std::vector<std::string> otherNames;   // Others
-            Return<void> transResult;
-            transResult = serviceManager->listManifestByInterface(
-                    IComponentStore::descriptor,
-                    [&defaultNames, &vendorNames, &otherNames](
-                            hidl_vec<hidl_string> const& instanceNames) {
-                        for (hidl_string const& instanceName : instanceNames) {
-                            char const* name = instanceName.c_str();
-                            if (strncmp(name, "default", 7) == 0) {
-                                defaultNames.emplace_back(name);
-                            } else if (strncmp(name, "vendor", 6) == 0) {
-                                vendorNames.emplace_back(name);
-                            } else {
-                                otherNames.emplace_back(name);
-                            }
-                        }
-                    });
-            if (transResult.isOk()) {
-                // Sort service names in each category.
-                std::sort(defaultNames.begin(), defaultNames.end());
-                std::sort(vendorNames.begin(), vendorNames.end());
-                std::sort(otherNames.begin(), otherNames.end());
+    // Get HIDL service names
+    using ::android::hardware::media::c2::V1_0::IComponentStore;
+    using ::android::hidl::manager::V1_2::IServiceManager;
+    while (true) {
+        sp<IServiceManager> serviceManager = IServiceManager::getService();
+        CHECK(serviceManager) << "Hardware service manager is not running.";
 
-                // Concatenate the three lists in this order: default, vendor,
-                // other.
-                std::vector<std::string>& names = defaultNames;
-                names.reserve(names.size() + vendorNames.size() + otherNames.size());
-                names.insert(names.end(),
-                             std::make_move_iterator(vendorNames.begin()),
-                             std::make_move_iterator(vendorNames.end()));
-                names.insert(names.end(),
-                             std::make_move_iterator(otherNames.begin()),
-                             std::make_move_iterator(otherNames.end()));
-
-                // Summarize to logcat.
-                if (names.empty()) {
-                    LOG(INFO) << "No Codec2 services declared in the manifest.";
-                } else {
-                    std::stringstream stringOutput;
-                    stringOutput << "Available Codec2 services:";
-                    for (std::string const& name : names) {
-                        stringOutput << " \"" << name << "\"";
-                    }
-                    LOG(INFO) << stringOutput.str();
-                }
-
-                return names;
-            }
-            LOG(ERROR) << "Could not retrieve the list of service instances of "
-                       << IComponentStore::descriptor
-                       << ". Retrying...";
+        Return<void> transResult;
+        transResult = serviceManager->listManifestByInterface(
+                IComponentStore::descriptor,
+                [&names](
+                        hidl_vec<hidl_string> const& instanceNames) {
+                    names.insert(names.end(), instanceNames.begin(), instanceNames.end());
+                });
+        if (transResult.isOk()) {
+            break;
         }
-    }()};
+        LOG(ERROR) << "Could not retrieve the list of service instances of "
+                   << IComponentStore::descriptor
+                   << ". Retrying...";
+    }
+    // Sort service names in each category.
+    std::stable_sort(
+        names.begin(), names.end(),
+        [](const std::string &a, const std::string &b) {
+            // First compare by prefix: default -> vendor -> {everything else}
+            constexpr int DEFAULT = 1;
+            constexpr int VENDOR = 2;
+            constexpr int OTHER = 3;
+            int aPrefix = ((a.compare(0, 7, "default") == 0) ? DEFAULT :
+                           (a.compare(0, 6, "vendor") == 0) ? VENDOR :
+                           OTHER);
+            int bPrefix = ((b.compare(0, 7, "default") == 0) ? DEFAULT :
+                           (b.compare(0, 6, "vendor") == 0) ? VENDOR :
+                           OTHER);
+            if (aPrefix != bPrefix) {
+                return aPrefix < bPrefix;
+            }
+            // If the prefix is the same, compare alphabetically
+            return a < b;
+        });
+
+    // Summarize to logcat.
+    if (names.empty()) {
+        LOG(INFO) << "No Codec2 services declared in the manifest.";
+    } else {
+        std::stringstream stringOutput;
+        stringOutput << "Available Codec2 services:";
+        for (std::string const& name : names) {
+            stringOutput << " \"" << name << "\"";
+        }
+        LOG(INFO) << stringOutput.str();
+    }
+
+    return names;
+}
+
+std::vector<std::string> const& Codec2Client::GetServiceNames() {
+    static std::vector<std::string> sServiceNames = CacheServiceNames();
     return sServiceNames;
 }
 
@@ -1322,14 +1544,34 @@
 std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
     std::string const& name = GetServiceNames()[index];
     LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
-    sp<Base> baseStore = Base::getService(name);
+
+    if (c2_aidl::utils::IsEnabled()) {
+        std::string instanceName =
+            ::android::base::StringPrintf("%s/%s", AidlBase::descriptor, name.c_str());
+        if (AServiceManager_isDeclared(instanceName.c_str())) {
+            std::shared_ptr<AidlBase> baseStore = AidlBase::fromBinder(
+                    ::ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str())));
+            CHECK(baseStore) << "Codec2 AIDL service \"" << name << "\""
+                                " inaccessible for unknown reasons.";
+            LOG(VERBOSE) << "Client to Codec2 AIDL service \"" << name << "\" created";
+            std::shared_ptr<c2_aidl::IConfigurable> configurable;
+            ::ndk::ScopedAStatus transStatus = baseStore->getConfigurable(&configurable);
+            CHECK(transStatus.isOk()) << "Codec2 AIDL service \"" << name << "\""
+                                        "does not have IConfigurable.";
+            return std::make_shared<Codec2Client>(baseStore, configurable, index);
+        }
+    }
+
+    std::string instanceName = "android.hardware.media.c2/" + name;
+    sp<HidlBase> baseStore = HidlBase::getService(name);
     CHECK(baseStore) << "Codec2 service \"" << name << "\""
                         " inaccessible for unknown reasons.";
     LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
-    Return<sp<IConfigurable>> transResult = baseStore->getConfigurable();
+    Return<sp<c2_hidl::IConfigurable>> transResult = baseStore->getConfigurable();
     CHECK(transResult.isOk()) << "Codec2 service \"" << name << "\""
                                 "does not have IConfigurable.";
-    sp<IConfigurable> configurable = static_cast<sp<IConfigurable>>(transResult);
+    sp<c2_hidl::IConfigurable> configurable =
+        static_cast<sp<c2_hidl::IConfigurable>>(transResult);
     return std::make_shared<Codec2Client>(baseStore, configurable, index);
 }
 
@@ -1431,8 +1673,7 @@
     return status;
 }
 
-std::shared_ptr<Codec2Client::Interface>
-        Codec2Client::CreateInterfaceByName(
+std::shared_ptr<Codec2Client::Interface> Codec2Client::CreateInterfaceByName(
         const char* interfaceName,
         std::shared_ptr<Codec2Client>* owner,
         size_t numberOfAttempts) {
@@ -1518,13 +1759,8 @@
     return nullptr;
 }
 
-// Codec2Client::Listener
-
-Codec2Client::Listener::~Listener() {
-}
-
 // Codec2Client::Interface
-Codec2Client::Interface::Interface(const sp<Base>& base)
+Codec2Client::Interface::Interface(const sp<HidlBase>& base)
       : Configurable{
             [base]() -> sp<c2_hidl::IConfigurable> {
                 Return<sp<c2_hidl::IConfigurable>> transResult =
@@ -1534,11 +1770,91 @@
                         nullptr;
             }()
         },
-        mBase{base} {
+        mHidlBase{base} {
+}
+
+Codec2Client::Interface::Interface(const std::shared_ptr<AidlBase>& base)
+      : Configurable{
+            [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
+                std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
+                ::ndk::ScopedAStatus transStatus =
+                    base->getConfigurable(&aidlConfigurable);
+                return transStatus.isOk() ? aidlConfigurable : nullptr;
+            }()
+        },
+        mAidlBase{base} {
 }
 
 // Codec2Client::Component
-Codec2Client::Component::Component(const sp<Base>& base)
+
+class Codec2Client::Component::AidlDeathManager {
+public:
+    AidlDeathManager()
+        : mSeq(0),
+          mDeathRecipient(AIBinder_DeathRecipient_new(OnBinderDied)) {
+    }
+
+    ~AidlDeathManager() = default;
+
+    bool linkToDeath(
+            const std::shared_ptr<Component> &comp,
+            const std::shared_ptr<Listener> &listener,
+            size_t *seqPtr) {
+        std::unique_lock lock(mMutex);
+        size_t seq = mSeq++;
+        if (!mMap.try_emplace(seq, comp, listener).second) {
+            return false;
+        }
+        if (STATUS_OK != AIBinder_linkToDeath(
+                comp->mAidlBase->asBinder().get(), mDeathRecipient.get(), (void *)seq)) {
+            mMap.erase(seq);
+            return false;
+        }
+        *seqPtr = seq;
+        return true;
+    }
+
+    void unlinkToDeath(size_t seq, const std::shared_ptr<AidlBase> &base) {
+        std::unique_lock lock(mMutex);
+        AIBinder_unlinkToDeath(base->asBinder().get(), mDeathRecipient.get(), (void *)seq);
+        mMap.erase(seq);
+    }
+
+private:
+    std::mutex mMutex;
+    size_t mSeq;
+    typedef std::tuple<std::weak_ptr<Component>, std::weak_ptr<Listener>> Context;
+    std::map<size_t, Context> mMap;
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+    bool extractContext(size_t seq, Context *context) {
+        std::unique_lock lock(mMutex);
+        auto node = mMap.extract(seq);
+        if (!node) {
+            return false;
+        }
+        *context = node.mapped();
+        return true;
+    }
+
+    static void OnBinderDied(void *cookie) {
+        size_t seq = size_t(cookie);
+        Context context;
+        if (!Component::GetAidlDeathManager()->extractContext(seq, &context)) {
+            return;
+        }
+        std::weak_ptr<Component> weakComponent;
+        std::weak_ptr<Listener> weakListener;
+        std::tie(weakComponent, weakListener) = context;
+        if (std::shared_ptr<Listener> listener = weakListener.lock()) {
+            listener->onDeath(weakComponent);
+        } else {
+            LOG(DEBUG) << "onDeath -- listener died.";
+        }
+    }
+};
+
+Codec2Client::Component::Component(const sp<HidlBase>& base)
       : Configurable{
             [base]() -> sp<c2_hidl::IConfigurable> {
                 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
@@ -1554,14 +1870,14 @@
                         nullptr;
             }()
         },
-        mBase1_0{base},
-        mBase1_1{Base1_1::castFrom(base)},
-        mBase1_2{Base1_2::castFrom(base)},
-        mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+        mHidlBase1_0{base},
+        mHidlBase1_1{HidlBase1_1::castFrom(base)},
+        mHidlBase1_2{HidlBase1_2::castFrom(base)},
+        mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
         mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
 }
 
-Codec2Client::Component::Component(const sp<Base1_1>& base)
+Codec2Client::Component::Component(const sp<HidlBase1_1>& base)
       : Configurable{
             [base]() -> sp<c2_hidl::IConfigurable> {
                 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
@@ -1577,14 +1893,14 @@
                         nullptr;
             }()
         },
-        mBase1_0{base},
-        mBase1_1{base},
-        mBase1_2{Base1_2::castFrom(base)},
-        mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+        mHidlBase1_0{base},
+        mHidlBase1_1{base},
+        mHidlBase1_2{HidlBase1_2::castFrom(base)},
+        mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
         mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
 }
 
-Codec2Client::Component::Component(const sp<Base1_2>& base)
+Codec2Client::Component::Component(const sp<HidlBase1_2>& base)
       : Configurable{
             [base]() -> sp<c2_hidl::IConfigurable> {
                 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
@@ -1600,22 +1916,54 @@
                         nullptr;
             }()
         },
-        mBase1_0{base},
-        mBase1_1{base},
-        mBase1_2{base},
-        mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+        mHidlBase1_0{base},
+        mHidlBase1_1{base},
+        mHidlBase1_2{base},
+        mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
+        mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
+}
+
+Codec2Client::Component::Component(const std::shared_ptr<AidlBase> &base)
+      : Configurable{
+            [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
+                std::shared_ptr<c2_aidl::IComponentInterface> aidlIntf;
+                ::ndk::ScopedAStatus transStatus = base->getInterface(&aidlIntf);
+                if (!transStatus.isOk()) {
+                    return nullptr;
+                }
+                std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
+                transStatus = aidlIntf->getConfigurable(&aidlConfigurable);
+                return transStatus.isOk() ? aidlConfigurable : nullptr;
+            }()
+        },
+        mAidlBase{base},
+        mAidlBufferPoolSender{std::make_unique<AidlBufferPoolSender>()},
         mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
 }
 
 Codec2Client::Component::~Component() {
+    if (mAidlDeathSeq) {
+        GetAidlDeathManager()->unlinkToDeath(*mAidlDeathSeq, mAidlBase);
+    }
 }
 
 c2_status_t Codec2Client::Component::createBlockPool(
         C2Allocator::id_t id,
         C2BlockPool::local_id_t* blockPoolId,
         std::shared_ptr<Codec2Client::Configurable>* configurable) {
+    if (mAidlBase) {
+        c2_aidl::IComponent::BlockPool aidlBlockPool;
+        ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(id, &aidlBlockPool);
+        c2_status_t status = GetC2Status(transStatus, "createBlockPool");
+        if (status != C2_OK) {
+            return status;
+        }
+        *blockPoolId = aidlBlockPool.blockPoolId;
+        *configurable = std::make_shared<Configurable>(aidlBlockPool.configurable);
+        return C2_OK;
+    }
     c2_status_t status;
-    Return<void> transStatus = mBase1_0->createBlockPool(
+    Return<void> transStatus = mHidlBase1_0->createBlockPool(
             static_cast<uint32_t>(id),
             [&status, blockPoolId, configurable](
                     c2_hidl::Status s,
@@ -1640,7 +1988,11 @@
 
 c2_status_t Codec2Client::Component::destroyBlockPool(
         C2BlockPool::local_id_t localId) {
-    Return<c2_hidl::Status> transResult = mBase1_0->destroyBlockPool(
+    if (mAidlBase) {
+        ::ndk::ScopedAStatus transStatus = mAidlBase->destroyBlockPool(localId);
+        return GetC2Status(transStatus, "destroyBlockPool");
+    }
+    Return<c2_hidl::Status> transResult = mHidlBase1_0->destroyBlockPool(
             static_cast<uint64_t>(localId));
     if (!transResult.isOk()) {
         LOG(ERROR) << "destroyBlockPool -- transaction failed.";
@@ -1657,12 +2009,21 @@
 
 c2_status_t Codec2Client::Component::queue(
         std::list<std::unique_ptr<C2Work>>* const items) {
+    if (mAidlBase) {
+        c2_aidl::WorkBundle workBundle;
+        if (!c2_aidl::utils::ToAidl(&workBundle, *items, mAidlBufferPoolSender.get())) {
+            LOG(ERROR) << "queue -- bad input.";
+            return C2_TRANSACTION_FAILED;
+        }
+        ::ndk::ScopedAStatus transStatus = mAidlBase->queue(workBundle);
+        return GetC2Status(transStatus, "queue");
+    }
     c2_hidl::WorkBundle workBundle;
-    if (!objcpy(&workBundle, *items, mBufferPoolSender.get())) {
+    if (!c2_hidl::utils::objcpy(&workBundle, *items, mHidlBufferPoolSender.get())) {
         LOG(ERROR) << "queue -- bad input.";
         return C2_TRANSACTION_FAILED;
     }
-    Return<c2_hidl::Status> transStatus = mBase1_0->queue(workBundle);
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->queue(workBundle);
     if (!transStatus.isOk()) {
         LOG(ERROR) << "queue -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1678,25 +2039,38 @@
 c2_status_t Codec2Client::Component::flush(
         C2Component::flush_mode_t mode,
         std::list<std::unique_ptr<C2Work>>* const flushedWork) {
-    (void)mode; // Flush mode isn't supported in HIDL yet.
-    c2_status_t status;
-    Return<void> transStatus = mBase1_0->flush(
-            [&status, flushedWork](
-                    c2_hidl::Status s, const c2_hidl::WorkBundle& wb) {
-                status = static_cast<c2_status_t>(s);
-                if (status != C2_OK) {
-                    LOG(DEBUG) << "flush -- call failed: " << status << ".";
-                    return;
-                }
-                if (!c2_hidl::utils::objcpy(flushedWork, wb)) {
-                    status = C2_CORRUPTED;
-                } else {
-                    status = C2_OK;
-                }
-            });
-    if (!transStatus.isOk()) {
-        LOG(ERROR) << "flush -- transaction failed.";
-        return C2_TRANSACTION_FAILED;
+    (void)mode; // Flush mode isn't supported in HIDL/AIDL yet.
+    c2_status_t status = C2_OK;
+    if (mAidlBase) {
+        c2_aidl::WorkBundle workBundle;
+        ::ndk::ScopedAStatus transStatus = mAidlBase->flush(&workBundle);
+        c2_status_t status = GetC2Status(transStatus, "flush");
+        if (status != C2_OK) {
+            return status;
+        }
+        if (!c2_aidl::utils::FromAidl(flushedWork, workBundle)) {
+            LOG(DEBUG) << "flush -- flushedWork corrupted.";
+            return C2_CORRUPTED;
+        }
+    } else {
+        Return<void> transStatus = mHidlBase1_0->flush(
+                [&status, flushedWork](
+                        c2_hidl::Status s, const c2_hidl::WorkBundle& wb) {
+                    status = static_cast<c2_status_t>(s);
+                    if (status != C2_OK) {
+                        LOG(DEBUG) << "flush -- call failed: " << status << ".";
+                        return;
+                    }
+                    if (!c2_hidl::utils::objcpy(flushedWork, wb)) {
+                        status = C2_CORRUPTED;
+                    } else {
+                        status = C2_OK;
+                    }
+                });
+        if (!transStatus.isOk()) {
+            LOG(ERROR) << "flush -- transaction failed.";
+            return C2_TRANSACTION_FAILED;
+        }
     }
 
     // Indices of flushed work items.
@@ -1721,7 +2095,12 @@
 }
 
 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
-    Return<c2_hidl::Status> transStatus = mBase1_0->drain(
+    if (mAidlBase) {
+        ::ndk::ScopedAStatus transStatus = mAidlBase->drain(
+                mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
+        return GetC2Status(transStatus, "drain");
+    }
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->drain(
             mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
     if (!transStatus.isOk()) {
         LOG(ERROR) << "drain -- transaction failed.";
@@ -1736,7 +2115,11 @@
 }
 
 c2_status_t Codec2Client::Component::start() {
-    Return<c2_hidl::Status> transStatus = mBase1_0->start();
+    if (mAidlBase) {
+        ::ndk::ScopedAStatus transStatus = mAidlBase->start();
+        return GetC2Status(transStatus, "start");
+    }
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->start();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "start -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1750,7 +2133,11 @@
 }
 
 c2_status_t Codec2Client::Component::stop() {
-    Return<c2_hidl::Status> transStatus = mBase1_0->stop();
+    if (mAidlBase) {
+        ::ndk::ScopedAStatus transStatus = mAidlBase->stop();
+        return GetC2Status(transStatus, "stop");
+    }
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->stop();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "stop -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1764,7 +2151,11 @@
 }
 
 c2_status_t Codec2Client::Component::reset() {
-    Return<c2_hidl::Status> transStatus = mBase1_0->reset();
+    if (mAidlBase) {
+        ::ndk::ScopedAStatus transStatus = mAidlBase->reset();
+        return GetC2Status(transStatus, "reset");
+    }
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->reset();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "reset -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1778,7 +2169,11 @@
 }
 
 c2_status_t Codec2Client::Component::release() {
-    Return<c2_hidl::Status> transStatus = mBase1_0->release();
+    if (mAidlBase) {
+        ::ndk::ScopedAStatus transStatus = mAidlBase->release();
+        return GetC2Status(transStatus, "release");
+    }
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->release();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "release -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1795,11 +2190,25 @@
         uint32_t avSyncHwId,
         native_handle_t** sidebandHandle) {
     *sidebandHandle = nullptr;
-    if (!mBase1_1) {
+    if (mAidlBase) {
+        ::aidl::android::hardware::common::NativeHandle handle;
+        ::ndk::ScopedAStatus transStatus = mAidlBase->configureVideoTunnel(avSyncHwId, &handle);
+        c2_status_t status = GetC2Status(transStatus, "configureVideoTunnel");
+        if (status != C2_OK) {
+            return status;
+        }
+        if (isAidlNativeHandleEmpty(handle)) {
+            LOG(DEBUG) << "configureVideoTunnel -- empty handle returned";
+        } else {
+            *sidebandHandle = dupFromAidl(handle);
+        }
+        return C2_OK;
+    }
+    if (!mHidlBase1_1) {
         return C2_OMITTED;
     }
     c2_status_t status{};
-    Return<void> transStatus = mBase1_1->configureVideoTunnel(avSyncHwId,
+    Return<void> transStatus = mHidlBase1_1->configureVideoTunnel(avSyncHwId,
             [&status, sidebandHandle](
                     c2_hidl::Status s, hardware::hidl_handle const& h) {
                 status = static_cast<c2_status_t>(s);
@@ -1840,8 +2249,8 @@
         bqId = 0;
         mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
     } else {
-        mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount, mBase1_2 ?
-                                      &syncObj : nullptr);
+        mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount,
+                                      mHidlBase1_2 ? &syncObj : nullptr);
     }
 
     // set consumer bits
@@ -1880,11 +2289,15 @@
     ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx%s",
             generation, (long long)consumerUsage, syncObj ? " sync" : "");
 
+    if (mAidlBase) {
+        // FIXME
+        return C2_OMITTED;
+    }
     Return<c2_hidl::Status> transStatus = syncObj ?
-            mBase1_2->setOutputSurfaceWithSyncObj(
+            mHidlBase1_2->setOutputSurfaceWithSyncObj(
                     static_cast<uint64_t>(blockPoolId),
                     bqId == 0 ? nullHgbp : igbp, *syncObj) :
-            mBase1_0->setOutputSurface(
+            mHidlBase1_0->setOutputSurface(
                     static_cast<uint64_t>(blockPoolId),
                     bqId == 0 ? nullHgbp : igbp);
 
@@ -1923,7 +2336,11 @@
         C2BlockPool::local_id_t blockPoolId) {
     std::scoped_lock lock(mOutputMutex);
     mOutputBufferQueue->stop();
-    Return<c2_hidl::Status> transStatus = mBase1_0->setOutputSurface(
+    if (mAidlBase) {
+        // FIXME
+        return;
+    }
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->setOutputSurface(
             static_cast<uint64_t>(blockPoolId), nullptr);
     if (!transStatus.isOk()) {
         LOG(ERROR) << "setOutputSurface(stopUsingOutputSurface) -- transaction failed.";
@@ -1941,8 +2358,12 @@
 c2_status_t Codec2Client::Component::connectToInputSurface(
         const std::shared_ptr<InputSurface>& inputSurface,
         std::shared_ptr<InputSurfaceConnection>* connection) {
+    if (mAidlBase) {
+        // FIXME
+        return C2_OMITTED;
+    }
     c2_status_t status;
-    Return<void> transStatus = mBase1_0->connectToInputSurface(
+    Return<void> transStatus = mHidlBase1_0->connectToInputSurface(
             inputSurface->mBase,
             [&status, connection](
                     c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
@@ -1965,8 +2386,12 @@
         const sp<HGraphicBufferProducer1>& producer,
         const sp<HGraphicBufferSource>& source,
         std::shared_ptr<InputSurfaceConnection>* connection) {
+    if (mAidlBase) {
+        LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
+        return C2_OMITTED;
+    }
     c2_status_t status;
-    Return<void> transStatus = mBase1_0->connectToOmxInputSurface(
+    Return<void> transStatus = mHidlBase1_0->connectToOmxInputSurface(
             producer, source,
             [&status, connection](
                     c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
@@ -1986,7 +2411,11 @@
 }
 
 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
-    Return<c2_hidl::Status> transStatus = mBase1_0->disconnectFromInputSurface();
+    if (mAidlBase) {
+        // FIXME
+        return C2_OMITTED;
+    }
+    Return<c2_hidl::Status> transStatus = mHidlBase1_0->disconnectFromInputSurface();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -2000,6 +2429,12 @@
     return status;
 }
 
+Codec2Client::Component::AidlDeathManager *Codec2Client::Component::GetAidlDeathManager() {
+    // This object never gets destructed
+    static AidlDeathManager *sManager = new AidlDeathManager();
+    return sManager;
+}
+
 c2_status_t Codec2Client::Component::setDeathListener(
         const std::shared_ptr<Component>& component,
         const std::shared_ptr<Listener>& listener) {
@@ -2020,12 +2455,20 @@
         }
     };
 
+    if (component->mAidlBase) {
+        size_t seq;
+        if (GetAidlDeathManager()->linkToDeath(component, listener, &seq)) {
+            component->mAidlDeathSeq = seq;
+        }
+        return C2_OK;
+    }
+
     sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
     deathRecipient->base = listener;
     deathRecipient->component = component;
 
     component->mDeathRecipient = deathRecipient;
-    Return<bool> transResult = component->mBase1_0->linkToDeath(
+    Return<bool> transResult = component->mHidlBase1_0->linkToDeath(
             component->mDeathRecipient, 0);
     if (!transResult.isOk()) {
         LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
diff --git a/media/codec2/hal/client/include/codec2/hidl/client.h b/media/codec2/hal/client/include/codec2/hidl/client.h
index 8a4aa48..beb7883 100644
--- a/media/codec2/hal/client/include/codec2/hidl/client.h
+++ b/media/codec2/hal/client/include/codec2/hidl/client.h
@@ -95,6 +95,11 @@
 struct IClientManager;
 }  // namespace android::hardware::media::bufferpool::V2_0
 
+namespace aidl::android::hardware::media::bufferpool2 {
+class IClientManager;
+}  // namespace aidl::android::hardware::media::c2
+
+
 namespace android::hardware::graphics::bufferqueue::V1_0 {
 struct IGraphicBufferProducer;
 }  // android::hardware::graphics::bufferqueue::V1_0
@@ -173,12 +178,12 @@
 
 struct Codec2Client : public Codec2ConfigurableClient {
 
-    typedef ::android::hardware::media::c2::V1_0::IComponentStore Base1_0;
-    typedef ::android::hardware::media::c2::V1_1::IComponentStore Base1_1;
-    typedef ::android::hardware::media::c2::V1_2::IComponentStore Base1_2;
-    typedef Base1_0 Base;
+    typedef ::android::hardware::media::c2::V1_0::IComponentStore HidlBase1_0;
+    typedef ::android::hardware::media::c2::V1_1::IComponentStore HidlBase1_1;
+    typedef ::android::hardware::media::c2::V1_2::IComponentStore HidlBase1_2;
+    typedef HidlBase1_0 HidlBase;
 
-    typedef ::android::hardware::media::c2::V1_0::IConfigurable IConfigurable;
+    typedef ::aidl::android::hardware::media::c2::IComponentStore AidlBase;
 
     struct Listener;
 
@@ -194,10 +199,11 @@
 
     typedef Codec2Client Store;
 
-    sp<Base> const& getBase() const;
-    sp<Base1_0> const& getBase1_0() const;
-    sp<Base1_1> const& getBase1_1() const;
-    sp<Base1_2> const& getBase1_2() const;
+    sp<HidlBase> const& getHidlBase() const;
+    sp<HidlBase1_0> const& getHidlBase1_0() const;
+    sp<HidlBase1_1> const& getHidlBase1_1() const;
+    sp<HidlBase1_2> const& getHidlBase1_2() const;
+    ::ndk::SpAIBinder getAidlBase() const;
 
     std::string const& getServiceName() const;
 
@@ -266,14 +272,19 @@
 
     // base and/or configurable cannot be null.
     Codec2Client(
-            sp<Base> const& base,
-            sp<IConfigurable> const& configurable,
+            sp<HidlBase> const& base,
+            sp<Codec2ConfigurableClient::HidlBase> const& configurable,
+            size_t serviceIndex);
+    Codec2Client(
+            std::shared_ptr<AidlBase> const& base,
+            std::shared_ptr<Codec2ConfigurableClient::AidlBase> const& configurable,
             size_t serviceIndex);
 
 protected:
-    sp<Base1_0> mBase1_0;
-    sp<Base1_1> mBase1_1;
-    sp<Base1_2> mBase1_2;
+    sp<HidlBase1_0> mHidlBase1_0;
+    sp<HidlBase1_1> mHidlBase1_1;
+    sp<HidlBase1_2> mHidlBase1_2;
+    std::shared_ptr<AidlBase> mAidlBase;
 
     // Finds the first store where the predicate returns C2_OK and returns the
     // last predicate result. The predicate will be tried on all stores. The
@@ -301,8 +312,11 @@
     mutable std::vector<C2Component::Traits> mTraitsList;
 
     sp<::android::hardware::media::bufferpool::V2_0::IClientManager>
-            mHostPoolManager;
+            mHidlHostPoolManager;
+    std::shared_ptr<::aidl::android::hardware::media::bufferpool2::IClientManager>
+            mAidlHostPoolManager;
 
+    static std::vector<std::string> CacheServiceNames();
     static std::shared_ptr<Codec2Client> _CreateFromIndex(size_t index);
 
     std::vector<C2Component::Traits> _listComponents(bool* success) const;
@@ -312,12 +326,15 @@
 
 struct Codec2Client::Interface : public Codec2Client::Configurable {
 
-    typedef ::android::hardware::media::c2::V1_0::IComponentInterface Base;
+    typedef ::android::hardware::media::c2::V1_0::IComponentInterface HidlBase;
+    typedef ::aidl::android::hardware::media::c2::IComponentInterface AidlBase;
 
-    Interface(const sp<Base>& base);
+    Interface(const sp<HidlBase>& base);
+    Interface(const std::shared_ptr<AidlBase>& base);
 
 protected:
-    sp<Base> mBase;
+    sp<HidlBase> mHidlBase;
+    std::shared_ptr<AidlBase> mAidlBase;
 };
 
 struct Codec2Client::Listener {
@@ -356,16 +373,17 @@
             int32_t slotId,
             int64_t timestampNs) = 0;
 
-    virtual ~Listener();
-
+    virtual ~Listener() = default;
 };
 
 struct Codec2Client::Component : public Codec2Client::Configurable {
 
-    typedef ::android::hardware::media::c2::V1_0::IComponent Base1_0;
-    typedef ::android::hardware::media::c2::V1_1::IComponent Base1_1;
-    typedef ::android::hardware::media::c2::V1_2::IComponent Base1_2;
-    typedef Base1_0 Base;
+    typedef ::android::hardware::media::c2::V1_0::IComponent HidlBase1_0;
+    typedef ::android::hardware::media::c2::V1_1::IComponent HidlBase1_1;
+    typedef ::android::hardware::media::c2::V1_2::IComponent HidlBase1_2;
+    typedef HidlBase1_0 HidlBase;
+
+    typedef ::aidl::android::hardware::media::c2::IComponent AidlBase;
 
     c2_status_t createBlockPool(
             C2Allocator::id_t id,
@@ -469,19 +487,23 @@
     c2_status_t disconnectFromInputSurface();
 
     // base cannot be null.
-    Component(const sp<Base>& base);
-    Component(const sp<Base1_1>& base);
-    Component(const sp<Base1_2>& base);
+    Component(const sp<HidlBase>& base);
+    Component(const sp<HidlBase1_1>& base);
+    Component(const sp<HidlBase1_2>& base);
+    Component(const std::shared_ptr<AidlBase>& base);
 
     ~Component();
 
 protected:
-    sp<Base1_0> mBase1_0;
-    sp<Base1_1> mBase1_1;
-    sp<Base1_2> mBase1_2;
+    sp<HidlBase1_0> mHidlBase1_0;
+    sp<HidlBase1_1> mHidlBase1_1;
+    sp<HidlBase1_2> mHidlBase1_2;
+    std::shared_ptr<AidlBase> mAidlBase;
 
-    struct BufferPoolSender;
-    std::unique_ptr<BufferPoolSender> mBufferPoolSender;
+    struct HidlBufferPoolSender;
+    struct AidlBufferPoolSender;
+    std::unique_ptr<HidlBufferPoolSender> mHidlBufferPoolSender;
+    std::unique_ptr<AidlBufferPoolSender> mAidlBufferPoolSender;
 
     struct OutputBufferQueue;
     std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;
@@ -491,6 +513,10 @@
     // In order to prevent the race condition mutex is added.
     std::mutex mOutputMutex;
 
+    class AidlDeathManager;
+    static AidlDeathManager *GetAidlDeathManager();
+    std::optional<size_t> mAidlDeathSeq;
+
     static c2_status_t setDeathListener(
             const std::shared_ptr<Component>& component,
             const std::shared_ptr<Listener>& listener);
@@ -499,16 +525,15 @@
     friend struct Codec2Client;
 
     struct HidlListener;
+    struct AidlListener;
     void handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> &workItems);
-
 };
 
 struct Codec2Client::InputSurface : public Codec2Client::Configurable {
 public:
     typedef ::android::hardware::media::c2::V1_0::IInputSurface Base;
 
-    typedef ::android::hardware::media::c2::V1_0::IInputSurfaceConnection
-            ConnectionBase;
+    typedef ::android::hardware::media::c2::V1_0::IInputSurfaceConnection ConnectionBase;
 
     typedef Codec2Client::InputSurfaceConnection Connection;
 
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 44e78d6..718f782 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -47,6 +47,7 @@
         "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
         "libbase",
+        "libbinder_ndk",
         "libactivitymanager_aidl",
         "libandroid_net",
         "libaudioclient",
diff --git a/media/libmediaplayerservice/DeathNotifier.cpp b/media/libmediaplayerservice/DeathNotifier.cpp
index d13bdf5..ab22f67 100644
--- a/media/libmediaplayerservice/DeathNotifier.cpp
+++ b/media/libmediaplayerservice/DeathNotifier.cpp
@@ -31,6 +31,10 @@
     DeathRecipient(Notify const& notify): mNotify{notify} {
     }
 
+    void initNdk() {
+        mNdkRecipient.set(AIBinder_DeathRecipient_new(OnBinderDied));
+    }
+
     virtual void binderDied(wp<IBinder> const&) override {
         mNotify();
     }
@@ -39,8 +43,18 @@
         mNotify();
     }
 
+    static void OnBinderDied(void *cookie) {
+        DeathRecipient *thiz = (DeathRecipient *)cookie;
+        thiz->mNotify();
+    }
+
+    AIBinder_DeathRecipient *getNdkRecipient() {
+        return mNdkRecipient.get();;
+    }
+
 private:
     Notify mNotify;
+    ::ndk::ScopedAIBinder_DeathRecipient mNdkRecipient;
 };
 
 DeathNotifier::DeathNotifier(sp<IBinder> const& service, Notify const& notify)
@@ -55,6 +69,14 @@
     service->linkToDeath(mDeathRecipient, 0);
 }
 
+DeathNotifier::DeathNotifier(::ndk::SpAIBinder const& service, Notify const& notify)
+      : mService{std::in_place_index<3>, service},
+        mDeathRecipient{new DeathRecipient(notify)} {
+    mDeathRecipient->initNdk();
+    AIBinder_linkToDeath(
+            service.get(), mDeathRecipient->getNdkRecipient(), mDeathRecipient.get());
+}
+
 DeathNotifier::DeathNotifier(DeathNotifier&& other)
       : mService{other.mService}, mDeathRecipient{other.mDeathRecipient} {
     other.mService.emplace<0>();
@@ -71,6 +93,12 @@
     case 2:
         std::get<2>(mService)->unlinkToDeath(mDeathRecipient);
         break;
+    case 3:
+        AIBinder_unlinkToDeath(
+                std::get<3>(mService).get(),
+                mDeathRecipient->getNdkRecipient(),
+                mDeathRecipient.get());
+        break;
     default:
         CHECK(false) << "Corrupted service type during destruction.";
     }
diff --git a/media/libmediaplayerservice/DeathNotifier.h b/media/libmediaplayerservice/DeathNotifier.h
index 7bc2611..24e45a3 100644
--- a/media/libmediaplayerservice/DeathNotifier.h
+++ b/media/libmediaplayerservice/DeathNotifier.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_MEDIASERVICE_DEATHNOTIFIER_H
 #define ANDROID_MEDIASERVICE_DEATHNOTIFIER_H
 
+#include <android/binder_auto_utils.h>
 #include <android/hidl/base/1.0/IBase.h>
 #include <binder/Binder.h>
 #include <hidl/HidlSupport.h>
@@ -32,11 +33,12 @@
 
     DeathNotifier(sp<IBinder> const& service, Notify const& notify);
     DeathNotifier(sp<HBase> const& service, Notify const& notify);
+    DeathNotifier(::ndk::SpAIBinder const& service, Notify const& notify);
     DeathNotifier(DeathNotifier&& other);
     ~DeathNotifier();
 
 private:
-    std::variant<std::monostate, sp<IBinder>, sp<HBase>> mService;
+    std::variant<std::monostate, sp<IBinder>, sp<HBase>, ::ndk::SpAIBinder> mService;
 
     class DeathRecipient;
     sp<DeathRecipient> mDeathRecipient;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index f08c516..4c3b04e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -927,10 +927,10 @@
         {
             for (std::shared_ptr<Codec2Client> const& client :
                     Codec2Client::CreateFromAllServices()) {
-                sp<IBase> base = client->getBase();
-                deathNotifiers.emplace_back(
-                        base, [l = wp<MediaPlayerBase>(p),
-                               name = std::string(client->getServiceName())]() {
+                sp<IBase> hidlBase = client->getHidlBase();
+                ::ndk::SpAIBinder aidlBase = client->getAidlBase();
+                auto onBinderDied = [l = wp<MediaPlayerBase>(p),
+                                     name = std::string(client->getServiceName())]() {
                     sp<MediaPlayerBase> listener = l.promote();
                     if (listener) {
                         ALOGI("Codec2 service \"%s\" died. "
@@ -944,7 +944,12 @@
                               "without a death handler.",
                               name.c_str());
                     }
-                });
+                };
+                if (hidlBase) {
+                    deathNotifiers.emplace_back(hidlBase, onBinderDied);
+                } else if (aidlBase.get() != nullptr) {
+                    deathNotifiers.emplace_back(aidlBase, onBinderDied);
+                }
             }
         }
     }
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index d6b1c90..ed3ec89 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -22,6 +22,7 @@
 #include "MediaPlayerService.h"
 #include "StagefrightRecorder.h"
 
+#include <android/binder_auto_utils.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
 #include <binder/IPCThreadState.h>
@@ -490,9 +491,9 @@
         {
             for (std::shared_ptr<Codec2Client> const& client :
                     Codec2Client::CreateFromAllServices()) {
-                sp<IBase> base = client->getBase();
-                mDeathNotifiers.emplace_back(
-                        base, [l = wp<IMediaRecorderClient>(listener),
+                sp<IBase> hidlBase = client->getHidlBase();
+                ::ndk::SpAIBinder aidlBase = client->getAidlBase();
+                auto onBinderDied = [l = wp<IMediaRecorderClient>(listener),
                                name = std::string(client->getServiceName())]() {
                     sp<IMediaRecorderClient> listener = l.promote();
                     if (listener) {
@@ -507,7 +508,12 @@
                               "without a death handler",
                               name.c_str());
                     }
-                });
+                };
+                if (hidlBase) {
+                    mDeathNotifiers.emplace_back(hidlBase, onBinderDied);
+                } else if (aidlBase.get() != nullptr) {
+                    mDeathNotifiers.emplace_back(aidlBase, onBinderDied);
+                }
             }
         }
     }
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index f564efa..2429057 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -35,6 +35,7 @@
     shared_libs: [
         "framework-permission-aidl-cpp",
         "libbinder",
+        "libbinder_ndk",
         "libcutils",
         "libmedia",
         "libstagefright",