Merge "AudioFlinger: clean up ctor initialization" into main
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
new file mode 100644
index 0000000..7994d32
--- /dev/null
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-Component@1.2"
+#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>
+
+#ifndef __ANDROID_APEX__
+#include <FilterWrapper.h>
+#endif
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_2 {
+namespace utils {
+
+using namespace ::android;
+
+// ComponentListener wrapper
+struct Component::Listener : public C2Component::Listener {
+
+    Listener(const sp<Component>& component) :
+        mComponent(component),
+        mListener(component->mListener) {
+    }
+
+    virtual void onError_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            uint32_t errorCode) override {
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            Return<void> transStatus = listener->onError(Status::OK, errorCode);
+            if (!transStatus.isOk()) {
+                LOG(ERROR) << "Component::Listener::onError_nb -- "
+                           << "transaction failed.";
+            }
+        }
+    }
+
+    virtual void onTripped_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+            ) override {
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            hidl_vec<SettingResult> settingResults(c2settingResult.size());
+            size_t ix = 0;
+            for (const std::shared_ptr<C2SettingResult> &c2result :
+                    c2settingResult) {
+                if (c2result) {
+                    if (!objcpy(&settingResults[ix++], *c2result)) {
+                        break;
+                    }
+                }
+            }
+            settingResults.resize(ix);
+            Return<void> transStatus = listener->onTripped(settingResults);
+            if (!transStatus.isOk()) {
+                LOG(ERROR) << "Component::Listener::onTripped_nb -- "
+                           << "transaction failed.";
+            }
+        }
+    }
+
+    virtual void onWorkDone_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            std::list<std::unique_ptr<C2Work>> c2workItems) override {
+        for (const std::unique_ptr<C2Work>& work : c2workItems) {
+            if (work) {
+                if (work->worklets.empty()
+                        || !work->worklets.back()
+                        || (work->worklets.back()->output.flags &
+                            C2FrameData::FLAG_INCOMPLETE) == 0) {
+                    InputBufferManager::
+                            unregisterFrameData(mListener, work->input);
+                }
+            }
+        }
+
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            WorkBundle workBundle;
+
+            sp<Component> strongComponent = mComponent.promote();
+            beginTransferBufferQueueBlocks(c2workItems, true);
+            if (!objcpy(&workBundle, c2workItems, strongComponent ?
+                    &strongComponent->mBufferPoolSender : nullptr)) {
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "received corrupted work items.";
+                endTransferBufferQueueBlocks(c2workItems, false, true);
+                return;
+            }
+            Return<void> transStatus = listener->onWorkDone(workBundle);
+            if (!transStatus.isOk()) {
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "transaction failed.";
+                endTransferBufferQueueBlocks(c2workItems, false, true);
+                return;
+            }
+            endTransferBufferQueueBlocks(c2workItems, true, true);
+        }
+    }
+
+protected:
+    wp<Component> mComponent;
+    wp<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);
+};
+
+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)
+      : mComponent{component},
+        mInterface{new ComponentInterface(component->intf(),
+                                          store->getParameterCache())},
+        mListener{listener},
+        mStore{store},
+        mBufferPoolSender{clientPoolManager} {
+    // Retrieve supported parameters from store
+    // TODO: We could cache this per component/interface type
+    mInit = mInterface->status();
+}
+
+c2_status_t Component::status() const {
+    return mInit;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponent
+Return<Status> Component::queue(const WorkBundle& workBundle) {
+    std::list<std::unique_ptr<C2Work>> c2works;
+
+    if (!objcpy(&c2works, workBundle)) {
+        return Status::CORRUPTED;
+    }
+
+    // Register input buffers.
+    for (const std::unique_ptr<C2Work>& work : c2works) {
+        if (work) {
+            InputBufferManager::
+                    registerFrameData(mListener, work->input);
+        }
+    }
+
+    return static_cast<Status>(mComponent->queue_nb(&c2works));
+}
+
+Return<void> Component::flush(flush_cb _hidl_cb) {
+    std::list<std::unique_ptr<C2Work>> c2flushedWorks;
+    c2_status_t c2res = mComponent->flush_sm(
+            C2Component::FLUSH_COMPONENT,
+            &c2flushedWorks);
+
+    // Unregister input buffers.
+    for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
+        if (work) {
+            if (work->worklets.empty()
+                    || !work->worklets.back()
+                    || (work->worklets.back()->output.flags &
+                        C2FrameData::FLAG_INCOMPLETE) == 0) {
+                InputBufferManager::
+                        unregisterFrameData(mListener, work->input);
+            }
+        }
+    }
+
+    WorkBundle flushedWorkBundle;
+    Status res = static_cast<Status>(c2res);
+    beginTransferBufferQueueBlocks(c2flushedWorks, true);
+    if (c2res == C2_OK) {
+        if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+            res = Status::CORRUPTED;
+        }
+    }
+    _hidl_cb(res, flushedWorkBundle);
+    endTransferBufferQueueBlocks(c2flushedWorks, true, true);
+    return Void();
+}
+
+Return<Status> Component::drain(bool withEos) {
+    return static_cast<Status>(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);
+        }
+    }
+    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;
+}
+
+namespace /* unnamed */ {
+
+struct BlockPoolIntf : public ConfigurableC2Intf {
+    BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
+          : ConfigurableC2Intf{
+                "C2BlockPool:" +
+                    (pool ? std::to_string(pool->getLocalId()) : "null"),
+                0},
+            mPool{pool} {
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*>& params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        (void)params;
+        (void)mayBlock;
+        (void)failures;
+        return C2_OK;
+    }
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index>& indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        (void)indices;
+        (void)mayBlock;
+        (void)params;
+        return C2_OK;
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        (void)params;
+        return C2_OK;
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const override {
+        (void)fields;
+        (void)mayBlock;
+        return C2_OK;
+    }
+
+protected:
+    std::shared_ptr<C2BlockPool> mPool;
+};
+
+} // unnamed namespace
+
+Return<void> Component::createBlockPool(
+        uint32_t allocatorId,
+        createBlockPool_cb _hidl_cb) {
+    std::shared_ptr<C2BlockPool> blockPool;
+#ifdef __ANDROID_APEX__
+    c2_status_t status = CreateCodec2BlockPool(
+            static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
+            mComponent,
+            &blockPool);
+#else
+    c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool(
+            static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
+            mComponent,
+            &blockPool);
+#endif
+    if (status != C2_OK) {
+        blockPool = nullptr;
+    }
+    if (blockPool) {
+        mBlockPoolsMutex.lock();
+        mBlockPools.emplace(blockPool->getLocalId(), blockPool);
+        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();
+}
+
+Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
+    std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+    return mBlockPools.erase(blockPoolId) == 1 ?
+            Status::OK : Status::CORRUPTED;
+}
+
+Return<Status> Component::start() {
+    return static_cast<Status>(mComponent->start());
+}
+
+Return<Status> Component::stop() {
+    InputBufferManager::unregisterFrameData(mListener);
+    return static_cast<Status>(mComponent->stop());
+}
+
+Return<Status> Component::reset() {
+    Status status = static_cast<Status>(mComponent->reset());
+    {
+        std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+        mBlockPools.clear();
+    }
+    InputBufferManager::unregisterFrameData(mListener);
+    return status;
+}
+
+Return<Status> Component::release() {
+    Status status = static_cast<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());
+    }
+    return {mSink};
+}
+
+Return<void> Component::configureVideoTunnel(
+        uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
+    (void)avSyncHwId;
+    _hidl_cb(Status::OMITTED, hidl_handle{});
+    return Void();
+}
+
+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) {
+    std::shared_ptr<C2Component::Listener> c2listener =
+            std::make_shared<Listener>(self);
+    c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
+    if (res != C2_OK) {
+        mInit = res;
+    }
+
+    struct ListenerDeathRecipient : public HwDeathRecipient {
+        ListenerDeathRecipient(const wp<Component>& comp)
+            : component{comp} {
+        }
+
+        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.";
+    }
+    if (!static_cast<bool>(transStatus)) {
+        LOG(DEBUG) << "Listener linkToDeath() call failed.";
+    }
+}
+
+Component::~Component() {
+    InputBufferManager::unregisterFrameData(mListener);
+    mStore->reportComponentDeath(this);
+}
+
+} // namespace utils
+} // namespace V1_2
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hal/aidl/ComponentInterface.cpp b/media/codec2/hal/aidl/ComponentInterface.cpp
new file mode 100644
index 0000000..12078e0
--- /dev/null
+++ b/media/codec2/hal/aidl/ComponentInterface.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-ComponentInterface"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+namespace /* unnamed */ {
+
+// Implementation of ConfigurableC2Intf based on C2ComponentInterface
+struct CompIntf : public ConfigurableC2Intf {
+    CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
+        ConfigurableC2Intf{intf->getName(), intf->getId()},
+        mIntf{intf} {
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*>& params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        return mIntf->config_vb(params, mayBlock, failures);
+    }
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index>& indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        return mIntf->query_vb({}, indices, mayBlock, params);
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        return mIntf->querySupportedParams_nb(params);
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const override {
+        return mIntf->querySupportedValues_vb(fields, mayBlock);
+    }
+
+protected:
+    std::shared_ptr<C2ComponentInterface> mIntf;
+};
+
+} // unnamed namespace
+
+// ComponentInterface
+ComponentInterface::ComponentInterface(
+        const std::shared_ptr<C2ComponentInterface>& intf,
+        const std::shared_ptr<ParameterCache>& cache)
+      : mInterface{intf},
+        mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
+    mInit = mConfigurable->init(cache);
+}
+
+c2_status_t ComponentInterface::status() const {
+    return mInit;
+}
+
+Return<sp<IConfigurable>> ComponentInterface::getConfigurable() {
+    return mConfigurable;
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
new file mode 100644
index 0000000..9fac5d5
--- /dev/null
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-ComponentStore@1.2"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.2/ComponentStore.h>
+#include <codec2/hidl/1.2/InputSurface.h>
+#include <codec2/hidl/1.2/types.h>
+
+#include <android-base/file.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <utils/Errors.h>
+
+#include <C2PlatformSupport.h>
+#include <util/C2InterfaceHelper.h>
+
+#include <chrono>
+#include <ctime>
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+
+#ifndef __ANDROID_APEX__
+#include <codec2/hidl/plugin/FilterPlugin.h>
+#include <dlfcn.h>
+#include <C2Config.h>
+#include <DefaultFilterPlugin.h>
+#include <FilterWrapper.h>
+#endif
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_2 {
+namespace utils {
+
+using namespace ::android;
+using ::android::GraphicBufferSource;
+using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
+
+namespace /* unnamed */ {
+
+struct StoreIntf : public ConfigurableC2Intf {
+    StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
+          : ConfigurableC2Intf{store ? store->getName() : "", 0},
+            mStore{store} {
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>> *const failures
+            ) override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->config_sm(params, failures);
+    }
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>> *const params) const override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->query_sm({}, indices, params);
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+            ) const override {
+        return mStore->querySupportedParams_nb(params);
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery> &fields,
+            c2_blocking_t mayBlock) const override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->querySupportedValues_sm(fields);
+    }
+
+protected:
+    std::shared_ptr<C2ComponentStore> mStore;
+};
+
+} // unnamed namespace
+
+struct ComponentStore::StoreParameterCache : public ParameterCache {
+    std::mutex mStoreMutex;
+    ComponentStore* mStore;
+
+    StoreParameterCache(ComponentStore* store): mStore{store} {
+    }
+
+    virtual c2_status_t validate(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
+            ) override {
+        std::scoped_lock _lock(mStoreMutex);
+        return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
+    }
+
+    void onStoreDestroyed() {
+        std::scoped_lock _lock(mStoreMutex);
+        mStore = nullptr;
+    }
+};
+
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
+      : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+        mParameterCache{std::make_shared<StoreParameterCache>(this)},
+        mStore{store} {
+
+    std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
+    SetPreferredCodec2ComponentStore(store);
+
+    // Retrieve struct descriptors
+    mParamReflector = mStore->getParamReflector();
+
+    // Retrieve supported parameters from store
+    using namespace std::placeholders;
+    mInit = mConfigurable->init(mParameterCache);
+}
+
+ComponentStore::~ComponentStore() {
+    mParameterCache->onStoreDestroyed();
+}
+
+c2_status_t ComponentStore::status() const {
+    return mInit;
+}
+
+c2_status_t ComponentStore::validateSupportedParams(
+        const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
+    c2_status_t res = C2_OK;
+
+    for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
+        if (!desc) {
+            // All descriptors should be valid
+            res = res ? res : C2_BAD_VALUE;
+            continue;
+        }
+        C2Param::CoreIndex coreIndex = desc->index().coreIndex();
+        std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+        auto it = mStructDescriptors.find(coreIndex);
+        if (it == mStructDescriptors.end()) {
+            std::shared_ptr<C2StructDescriptor> structDesc =
+                    mParamReflector->describe(coreIndex);
+            if (!structDesc) {
+                // All supported params must be described
+                res = C2_BAD_INDEX;
+            }
+            mStructDescriptors.insert({ coreIndex, structDesc });
+        }
+    }
+    return res;
+}
+
+std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
+    return mParameterCache;
+}
+
+#ifndef __ANDROID_APEX__
+// static
+std::shared_ptr<FilterWrapper> ComponentStore::GetFilterWrapper() {
+    constexpr const char kPluginPath[] = "libc2filterplugin.so";
+    static std::shared_ptr<FilterWrapper> wrapper = FilterWrapper::Create(
+            std::make_unique<DefaultFilterPlugin>(kPluginPath));
+    return wrapper;
+}
+#endif
+
+// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
+Return<void> ComponentStore::createComponent(
+        const hidl_string& name,
+        const sp<IComponentListener>& listener,
+        const sp<IClientManager>& pool,
+        createComponent_cb _hidl_cb) {
+
+    sp<Component> component;
+    std::shared_ptr<C2Component> c2component;
+    Status status = static_cast<Status>(
+            mStore->createComponent(name, &c2component));
+
+    if (status == Status::OK) {
+#ifndef __ANDROID_APEX__
+        c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
+#endif
+        onInterfaceLoaded(c2component->intf());
+        component = new Component(c2component, listener, this, pool);
+        if (!component) {
+            status = Status::CORRUPTED;
+        } else {
+            reportComponentBirth(component.get());
+            if (component->status() != C2_OK) {
+                status = static_cast<Status>(component->status());
+            } else {
+                component->initListener(component);
+                if (component->status() != C2_OK) {
+                    status = static_cast<Status>(component->status());
+                }
+            }
+        }
+    }
+    _hidl_cb(status, component);
+    return Void();
+}
+
+Return<void> ComponentStore::createInterface(
+        const hidl_string& name,
+        createInterface_cb _hidl_cb) {
+    std::shared_ptr<C2ComponentInterface> c2interface;
+    c2_status_t res = mStore->createInterface(name, &c2interface);
+    sp<IComponentInterface> interface;
+    if (res == C2_OK) {
+#ifndef __ANDROID_APEX__
+        c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
+#endif
+        onInterfaceLoaded(c2interface);
+        interface = new ComponentInterface(c2interface, mParameterCache);
+    }
+    _hidl_cb(static_cast<Status>(res), interface);
+    return Void();
+}
+
+Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) {
+    std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
+            mStore->listComponents();
+    hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size());
+    size_t ix = 0;
+    for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
+        if (c2trait) {
+            if (objcpy(&traits[ix], *c2trait)) {
+                ++ix;
+            } else {
+                break;
+            }
+        }
+    }
+    traits.resize(ix);
+    _hidl_cb(Status::OK, traits);
+    return Void();
+}
+
+Return<void> ComponentStore::createInputSurface(createInputSurface_cb _hidl_cb) {
+    sp<GraphicBufferSource> source = new GraphicBufferSource();
+    if (source->initCheck() != OK) {
+        _hidl_cb(Status::CORRUPTED, nullptr);
+        return Void();
+    }
+    using namespace std::placeholders;
+    sp<InputSurface> inputSurface = new InputSurface(
+            mParameterCache,
+            std::make_shared<C2ReflectorHelper>(),
+            source->getHGraphicBufferProducer(),
+            source);
+    _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
+             inputSurface);
+    return Void();
+}
+
+void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
+    // invalidate unsupported struct descriptors if a new interface is loaded as it may have
+    // exposed new descriptors
+    std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+    if (!mLoadedInterfaces.count(intf->getName())) {
+        mUnsupportedStructDescriptors.clear();
+        mLoadedInterfaces.emplace(intf->getName());
+    }
+}
+
+Return<void> ComponentStore::getStructDescriptors(
+        const hidl_vec<uint32_t>& indices,
+        getStructDescriptors_cb _hidl_cb) {
+    hidl_vec<StructDescriptor> descriptors(indices.size());
+    size_t dstIx = 0;
+    Status res = Status::OK;
+    for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
+        std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+        const C2Param::CoreIndex coreIndex = C2Param::CoreIndex(indices[srcIx]).coreIndex();
+        const auto item = mStructDescriptors.find(coreIndex);
+        if (item == mStructDescriptors.end()) {
+            // not in the cache, and not known to be unsupported, query local reflector
+            if (!mUnsupportedStructDescriptors.count(coreIndex)) {
+                std::shared_ptr<C2StructDescriptor> structDesc =
+                    mParamReflector->describe(coreIndex);
+                if (!structDesc) {
+                    mUnsupportedStructDescriptors.emplace(coreIndex);
+                } else {
+                    mStructDescriptors.insert({ coreIndex, structDesc });
+                    if (objcpy(&descriptors[dstIx], *structDesc)) {
+                        ++dstIx;
+                        continue;
+                    }
+                    res = Status::CORRUPTED;
+                    break;
+                }
+            }
+            res = Status::NOT_FOUND;
+        } else if (item->second) {
+            if (objcpy(&descriptors[dstIx], *item->second)) {
+                ++dstIx;
+                continue;
+            }
+            res = Status::CORRUPTED;
+            break;
+        } else {
+            res = Status::NO_MEMORY;
+            break;
+        }
+    }
+    descriptors.resize(dstIx);
+    _hidl_cb(res, descriptors);
+    return Void();
+}
+
+Return<sp<IClientManager>> ComponentStore::getPoolClientManager() {
+    return ClientManager::getInstance();
+}
+
+Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
+    // TODO implement
+    (void)src;
+    (void)dst;
+    return Status::OMITTED;
+}
+
+Return<sp<IConfigurable>> ComponentStore::getConfigurable() {
+    return mConfigurable;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponentStore
+Return<void> ComponentStore::createComponent_1_1(
+        const hidl_string& name,
+        const sp<IComponentListener>& listener,
+        const sp<IClientManager>& pool,
+        createComponent_1_1_cb _hidl_cb) {
+
+    sp<Component> component;
+    std::shared_ptr<C2Component> c2component;
+    Status status = static_cast<Status>(
+            mStore->createComponent(name, &c2component));
+
+    if (status == Status::OK) {
+#ifndef __ANDROID_APEX__
+        c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
+#endif
+        onInterfaceLoaded(c2component->intf());
+        component = new Component(c2component, listener, this, pool);
+        if (!component) {
+            status = Status::CORRUPTED;
+        } else {
+            reportComponentBirth(component.get());
+            if (component->status() != C2_OK) {
+                status = static_cast<Status>(component->status());
+            } else {
+                component->initListener(component);
+                if (component->status() != C2_OK) {
+                    status = static_cast<Status>(component->status());
+                }
+            }
+        }
+    }
+    _hidl_cb(status, component);
+    return Void();
+}
+
+// Methods from ::android::hardware::media::c2::V1_2::IComponentStore
+Return<void> ComponentStore::createComponent_1_2(
+        const hidl_string& name,
+        const sp<IComponentListener>& listener,
+        const sp<IClientManager>& pool,
+        createComponent_1_2_cb _hidl_cb) {
+
+    sp<Component> component;
+    std::shared_ptr<C2Component> c2component;
+    Status status = static_cast<Status>(
+            mStore->createComponent(name, &c2component));
+
+    if (status == Status::OK) {
+#ifndef __ANDROID_APEX__
+        c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
+#endif
+        onInterfaceLoaded(c2component->intf());
+        component = new Component(c2component, listener, this, pool);
+        if (!component) {
+            status = Status::CORRUPTED;
+        } else {
+            reportComponentBirth(component.get());
+            if (component->status() != C2_OK) {
+                status = static_cast<Status>(component->status());
+            } else {
+                component->initListener(component);
+                if (component->status() != C2_OK) {
+                    status = static_cast<Status>(component->status());
+                }
+            }
+        }
+    }
+    _hidl_cb(status, component);
+    return Void();
+}
+
+// Called from createComponent() after a successful creation of `component`.
+void ComponentStore::reportComponentBirth(Component* component) {
+    ComponentStatus componentStatus;
+    componentStatus.c2Component = component->mComponent;
+    componentStatus.birthTime = std::chrono::system_clock::now();
+
+    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+    mComponentRoster.emplace(component, componentStatus);
+}
+
+// Called from within the destructor of `component`. No virtual function calls
+// are made on `component` here.
+void ComponentStore::reportComponentDeath(Component* component) {
+    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+    mComponentRoster.erase(component);
+}
+
+// Dumps component traits.
+std::ostream& ComponentStore::dump(
+        std::ostream& out,
+        const std::shared_ptr<const C2Component::Traits>& comp) {
+
+    constexpr const char indent[] = "    ";
+
+    out << indent << "name: " << comp->name << std::endl;
+    out << indent << "domain: " << comp->domain << std::endl;
+    out << indent << "kind: " << comp->kind << std::endl;
+    out << indent << "rank: " << comp->rank << std::endl;
+    out << indent << "mediaType: " << comp->mediaType << std::endl;
+    out << indent << "aliases:";
+    for (const auto& alias : comp->aliases) {
+        out << ' ' << alias;
+    }
+    out << std::endl;
+
+    return out;
+}
+
+// Dumps component status.
+std::ostream& ComponentStore::dump(
+        std::ostream& out,
+        ComponentStatus& compStatus) {
+
+    constexpr const char indent[] = "    ";
+
+    // Print birth time.
+    std::chrono::milliseconds ms =
+            std::chrono::duration_cast<std::chrono::milliseconds>(
+                compStatus.birthTime.time_since_epoch());
+    std::time_t birthTime = std::chrono::system_clock::to_time_t(
+            compStatus.birthTime);
+    std::tm tm = *std::localtime(&birthTime);
+    out << indent << "Creation time: "
+        << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
+        << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
+        << std::endl;
+
+    // Print name and id.
+    std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
+    if (!intf) {
+        out << indent << "Unknown component -- null interface" << std::endl;
+        return out;
+    }
+    out << indent << "Name: " << intf->getName() << std::endl;
+    out << indent << "Id: " << intf->getId() << std::endl;
+
+    return out;
+}
+
+// Dumps information when lshal is called.
+Return<void> ComponentStore::debug(
+        const hidl_handle& handle,
+        const hidl_vec<hidl_string>& /* args */) {
+    LOG(INFO) << "debug -- dumping...";
+    const native_handle_t *h = handle.getNativeHandle();
+    if (!h || h->numFds != 1) {
+       LOG(ERROR) << "debug -- dumping failed -- "
+               "invalid file descriptor to dump to";
+       return Void();
+    }
+    std::ostringstream out;
+
+    { // Populate "out".
+
+        constexpr const char indent[] = "  ";
+
+        // Show name.
+        out << "Beginning of dump -- C2ComponentStore: "
+                << mStore->getName() << std::endl << std::endl;
+
+        // Retrieve the list of supported components.
+        std::vector<std::shared_ptr<const C2Component::Traits>> traitsList =
+                mStore->listComponents();
+
+        // Dump the traits of supported components.
+        out << indent << "Supported components:" << std::endl << std::endl;
+        if (traitsList.size() == 0) {
+            out << indent << indent << "NONE" << std::endl << std::endl;
+        } else {
+            for (const auto& traits : traitsList) {
+                dump(out, traits) << std::endl;
+            }
+        }
+
+        // Dump active components.
+        {
+            out << indent << "Active components:" << std::endl << std::endl;
+            std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+            if (mComponentRoster.size() == 0) {
+                out << indent << indent << "NONE" << std::endl << std::endl;
+            } else {
+                for (auto& pair : mComponentRoster) {
+                    dump(out, pair.second) << std::endl;
+                }
+            }
+        }
+
+        out << "End of dump -- C2ComponentStore: "
+                << mStore->getName() << std::endl;
+    }
+
+    if (!android::base::WriteStringToFd(out.str(), h->data[0])) {
+        PLOG(WARNING) << "debug -- dumping failed -- write()";
+    } else {
+        LOG(INFO) << "debug -- dumping succeeded";
+    }
+    return Void();
+}
+
+} // namespace utils
+} // namespace V1_2
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hal/aidl/Configurable.cpp b/media/codec2/hal/aidl/Configurable.cpp
new file mode 100644
index 0000000..530576d
--- /dev/null
+++ b/media/codec2/hal/aidl/Configurable.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-Configurable"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <C2ParamInternal.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+CachedConfigurable::CachedConfigurable(
+        std::unique_ptr<ConfigurableC2Intf>&& intf)
+      : mIntf{std::move(intf)} {
+}
+
+c2_status_t CachedConfigurable::init(
+        const std::shared_ptr<ParameterCache>& cache) {
+    // Retrieve supported parameters from store
+    c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
+    c2_status_t validate = cache->validate(mSupportedParams);
+    return init == C2_OK ? C2_OK : validate;
+}
+
+// Methods from ::android::hardware::media::c2::V1_0::IConfigurable follow.
+Return<uint32_t> CachedConfigurable::getId() {
+    return mIntf->getId();
+}
+
+Return<void> CachedConfigurable::getName(getName_cb _hidl_cb) {
+    _hidl_cb(mIntf->getName());
+    return Void();
+}
+
+Return<void> CachedConfigurable::query(
+        const hidl_vec<uint32_t>& indices,
+        bool mayBlock,
+        query_cb _hidl_cb) {
+    typedef C2Param::Index Index;
+    std::vector<Index> c2heapParamIndices(
+            (Index*)indices.data(),
+            (Index*)indices.data() + indices.size());
+    std::vector<std::unique_ptr<C2Param>> c2heapParams;
+    c2_status_t c2res = mIntf->query(
+            c2heapParamIndices,
+            mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
+            &c2heapParams);
+
+    hidl_vec<uint8_t> params;
+    if (!createParamsBlob(&params, c2heapParams)) {
+        LOG(WARNING) << "query -- invalid output params.";
+    }
+    _hidl_cb(static_cast<Status>(c2res), params);
+    return Void();
+}
+
+Return<void> CachedConfigurable::config(
+        const hidl_vec<uint8_t>& inParams,
+        bool mayBlock,
+        config_cb _hidl_cb) {
+    // inParams is not writable, so create a copy as config modifies the parameters
+    hidl_vec<uint8_t> inParamsCopy = inParams;
+    std::vector<C2Param*> c2params;
+    if (!parseParamsBlob(&c2params, inParamsCopy)) {
+        LOG(WARNING) << "config -- invalid input params.";
+        _hidl_cb(Status::CORRUPTED,
+                hidl_vec<SettingResult>(),
+                hidl_vec<uint8_t>());
+        return Void();
+    }
+    // TODO: check if blob was invalid
+    std::vector<std::unique_ptr<C2SettingResult>> c2failures;
+    c2_status_t c2res = mIntf->config(
+            c2params,
+            mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
+            &c2failures);
+    hidl_vec<SettingResult> failures(c2failures.size());
+    {
+        size_t ix = 0;
+        for (const std::unique_ptr<C2SettingResult>& c2result : c2failures) {
+            if (c2result) {
+                if (objcpy(&failures[ix], *c2result)) {
+                    ++ix;
+                } else {
+                    LOG(DEBUG) << "config -- invalid setting results.";
+                    break;
+                }
+            }
+        }
+        failures.resize(ix);
+    }
+    hidl_vec<uint8_t> outParams;
+    if (!createParamsBlob(&outParams, c2params)) {
+        LOG(DEBUG) << "config -- invalid output params.";
+    }
+    _hidl_cb((Status)c2res, failures, outParams);
+    return Void();
+}
+
+Return<void> CachedConfigurable::querySupportedParams(
+        uint32_t start,
+        uint32_t count,
+        querySupportedParams_cb _hidl_cb) {
+    C2LinearRange request = C2LinearCapacity(mSupportedParams.size()).range(
+            start, count);
+    hidl_vec<ParamDescriptor> params(request.size());
+    Status res = Status::OK;
+    size_t dstIx = 0;
+    for (size_t srcIx = request.offset(); srcIx < request.endOffset(); ++srcIx) {
+        if (mSupportedParams[srcIx]) {
+            if (objcpy(&params[dstIx], *mSupportedParams[srcIx])) {
+                ++dstIx;
+            } else {
+                res = Status::CORRUPTED;
+                LOG(WARNING) << "querySupportedParams -- invalid output params.";
+                break;
+            }
+        } else {
+            res = Status::BAD_INDEX;
+        }
+    }
+    params.resize(dstIx);
+    _hidl_cb(res, params);
+    return Void();
+}
+
+Return<void> CachedConfigurable::querySupportedValues(
+        const hidl_vec<FieldSupportedValuesQuery>& inFields,
+        bool mayBlock,
+        querySupportedValues_cb _hidl_cb) {
+    std::vector<C2FieldSupportedValuesQuery> c2fields;
+    {
+        // C2FieldSupportedValuesQuery objects are restricted in that some
+        // members are const.
+        // C2ParamField - required for its constructor - has no constructors
+        // from fields. Use C2ParamInspector.
+        for (const FieldSupportedValuesQuery &query : inFields) {
+            c2fields.emplace_back(_C2ParamInspector::CreateParamField(
+                    query.field.index,
+                    query.field.fieldId.offset,
+                    query.field.fieldId.size),
+                    query.type == FieldSupportedValuesQuery::Type::POSSIBLE ?
+                    C2FieldSupportedValuesQuery::POSSIBLE :
+                    C2FieldSupportedValuesQuery::CURRENT);
+        }
+    }
+    c2_status_t c2res = mIntf->querySupportedValues(
+            c2fields,
+            mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
+    hidl_vec<FieldSupportedValuesQueryResult> outFields(inFields.size());
+    size_t dstIx = 0;
+    for (const C2FieldSupportedValuesQuery &result : c2fields) {
+        if (objcpy(&outFields[dstIx], result)) {
+            ++dstIx;
+        } else {
+            outFields.resize(dstIx);
+            c2res = C2_CORRUPTED;
+            LOG(WARNING) << "querySupportedValues -- invalid output params.";
+            break;
+        }
+    }
+    _hidl_cb((Status)c2res, outFields);
+    return Void();
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/codec2/hal/aidl/InputBufferManager.cpp b/media/codec2/hal/aidl/InputBufferManager.cpp
new file mode 100644
index 0000000..8c0d0a4
--- /dev/null
+++ b/media/codec2/hal/aidl/InputBufferManager.cpp
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-InputBufferManager"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputBufferManager.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android-base/logging.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <chrono>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+void InputBufferManager::registerFrameData(
+        const sp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    getInstance()._registerFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+        const wp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    getInstance()._unregisterFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+        const wp<IComponentListener>& listener) {
+    getInstance()._unregisterFrameData(listener);
+}
+
+void InputBufferManager::setNotificationInterval(
+        nsecs_t notificationIntervalNs) {
+    getInstance()._setNotificationInterval(notificationIntervalNs);
+}
+
+void InputBufferManager::_registerFrameData(
+        const sp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+    LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- called with "
+                 << "listener @ 0x" << std::hex << listener.get()
+                 << ", frameIndex = " << std::dec << frameIndex
+                 << ".";
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    std::set<TrackedBuffer*> &bufferIds =
+            mTrackedBuffersMap[listener][frameIndex];
+
+    for (size_t i = 0; i < input.buffers.size(); ++i) {
+        if (!input.buffers[i]) {
+            LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- "
+                         << "Input buffer at index " << i << " is null.";
+            continue;
+        }
+        TrackedBuffer *bufferId =
+            new TrackedBuffer(listener, frameIndex, i, input.buffers[i]);
+        mTrackedBufferCache.emplace(bufferId);
+        bufferIds.emplace(bufferId);
+
+        c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
+                onBufferDestroyed,
+                reinterpret_cast<void*>(bufferId));
+        if (status != C2_OK) {
+            LOG(DEBUG) << "InputBufferManager::_registerFrameData -- "
+                       << "registerOnDestroyNotify() failed "
+                       << "(listener @ 0x" << std::hex << listener.get()
+                       << ", frameIndex = " << std::dec << frameIndex
+                       << ", bufferIndex = " << i
+                       << ") => status = " << status
+                       << ".";
+        }
+    }
+
+    mDeathNotifications.emplace(
+            listener,
+            DeathNotifications(
+                mNotificationIntervalNs.load(std::memory_order_relaxed)));
+}
+
+// Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
+// mDeathNotifications. This implies all bufferIndices are removed.
+//
+// This is called from onWorkDone() and flush().
+void InputBufferManager::_unregisterFrameData(
+        const wp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+    LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+                 << "listener @ 0x" << std::hex << listener.unsafe_get()
+                 << ", frameIndex = " << std::dec << frameIndex
+                 << ".";
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    auto findListener = mTrackedBuffersMap.find(listener);
+    if (findListener != mTrackedBuffersMap.end()) {
+        std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds
+                = findListener->second;
+        auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
+        if (findFrameIndex != frameIndex2BufferIds.end()) {
+            std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+            for (TrackedBuffer* bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId->buffer.lock();
+                if (buffer) {
+                    c2_status_t status = buffer->unregisterOnDestroyNotify(
+                            onBufferDestroyed,
+                            reinterpret_cast<void*>(bufferId));
+                    if (status != C2_OK) {
+                        LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+                                   << "-- unregisterOnDestroyNotify() failed "
+                                   << "(listener @ 0x"
+                                        << std::hex
+                                        << bufferId->listener.unsafe_get()
+                                   << ", frameIndex = "
+                                        << std::dec << bufferId->frameIndex
+                                   << ", bufferIndex = " << bufferId->bufferIndex
+                                   << ") => status = " << status
+                                   << ".";
+                    }
+                }
+                mTrackedBufferCache.erase(bufferId);
+                delete bufferId;
+            }
+
+            frameIndex2BufferIds.erase(findFrameIndex);
+            if (frameIndex2BufferIds.empty()) {
+                mTrackedBuffersMap.erase(findListener);
+            }
+        }
+    }
+
+    auto findListenerD = mDeathNotifications.find(listener);
+    if (findListenerD != mDeathNotifications.end()) {
+        DeathNotifications &deathNotifications = findListenerD->second;
+        auto findFrameIndex = deathNotifications.indices.find(frameIndex);
+        if (findFrameIndex != deathNotifications.indices.end()) {
+            std::vector<size_t> &bufferIndices = findFrameIndex->second;
+            deathNotifications.count -= bufferIndices.size();
+            deathNotifications.indices.erase(findFrameIndex);
+        }
+    }
+}
+
+// Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
+// all frameIndices and bufferIndices are removed.
+//
+// This is called when the component cleans up all input buffers, i.e., when
+// reset(), release(), stop() or ~Component() is called.
+void InputBufferManager::_unregisterFrameData(
+        const wp<IComponentListener>& listener) {
+    LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+                 << "listener @ 0x" << std::hex << listener.unsafe_get()
+                 << std::dec << ".";
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    auto findListener = mTrackedBuffersMap.find(listener);
+    if (findListener != mTrackedBuffersMap.end()) {
+        std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds =
+                findListener->second;
+        for (auto findFrameIndex = frameIndex2BufferIds.begin();
+                findFrameIndex != frameIndex2BufferIds.end();
+                ++findFrameIndex) {
+            std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+            for (TrackedBuffer* bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId->buffer.lock();
+                if (buffer) {
+                    c2_status_t status = buffer->unregisterOnDestroyNotify(
+                            onBufferDestroyed,
+                            reinterpret_cast<void*>(bufferId));
+                    if (status != C2_OK) {
+                        LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+                                   << "-- unregisterOnDestroyNotify() failed "
+                                   << "(listener @ 0x"
+                                        << std::hex
+                                        << bufferId->listener.unsafe_get()
+                                   << ", frameIndex = "
+                                        << std::dec << bufferId->frameIndex
+                                   << ", bufferIndex = " << bufferId->bufferIndex
+                                   << ") => status = " << status
+                                   << ".";
+                    }
+                    mTrackedBufferCache.erase(bufferId);
+                    delete bufferId;
+                }
+            }
+        }
+        mTrackedBuffersMap.erase(findListener);
+    }
+
+    mDeathNotifications.erase(listener);
+}
+
+// Set mNotificationIntervalNs.
+void InputBufferManager::_setNotificationInterval(
+        nsecs_t notificationIntervalNs) {
+    mNotificationIntervalNs.store(
+            notificationIntervalNs,
+            std::memory_order_relaxed);
+}
+
+// Move a buffer from mTrackedBuffersMap to mDeathNotifications.
+// This is called when a registered C2Buffer object is destroyed.
+void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
+    getInstance()._onBufferDestroyed(buf, arg);
+}
+
+void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
+    if (!buf || !arg) {
+        LOG(WARNING) << "InputBufferManager::_onBufferDestroyed -- called with "
+                     << "null argument (s): "
+                     << "buf @ 0x" << std::hex << buf
+                     << ", arg @ 0x" << std::hex << arg
+                     << std::dec << ".";
+        return;
+    }
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    TrackedBuffer *bufferId = reinterpret_cast<TrackedBuffer*>(arg);
+
+    if (mTrackedBufferCache.find(bufferId) == mTrackedBufferCache.end()) {
+        LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+                     << "unregistered buffer: "
+                     << "buf @ 0x" << std::hex << buf
+                     << ", arg @ 0x" << std::hex << arg
+                     << std::dec << ".";
+        return;
+    }
+
+    LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+                 << "buf @ 0x" << std::hex << buf
+                 << ", arg @ 0x" << std::hex << arg
+                 << std::dec << " -- "
+                 << "listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+                 << ", frameIndex = " << std::dec << bufferId->frameIndex
+                 << ", bufferIndex = " << bufferId->bufferIndex
+                 << ".";
+    auto findListener = mTrackedBuffersMap.find(bufferId->listener);
+    if (findListener == mTrackedBuffersMap.end()) {
+        LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- "
+                     << "received invalid listener: "
+                     << "listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+                     << " (frameIndex = " << std::dec << bufferId->frameIndex
+                     << ", bufferIndex = " << bufferId->bufferIndex
+                     << ").";
+        return;
+    }
+
+    std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds
+            = findListener->second;
+    auto findFrameIndex = frameIndex2BufferIds.find(bufferId->frameIndex);
+    if (findFrameIndex == frameIndex2BufferIds.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid frame index: "
+                   << "frameIndex = " << bufferId->frameIndex
+                   << " (listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+                   << ", bufferIndex = " << std::dec << bufferId->bufferIndex
+                   << ").";
+        return;
+    }
+
+    std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+    auto findBufferId = bufferIds.find(bufferId);
+    if (findBufferId == bufferIds.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid buffer index: "
+                   << "bufferIndex = " << bufferId->bufferIndex
+                   << " (frameIndex = " << bufferId->frameIndex
+                   << ", listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+                   << std::dec << ").";
+        return;
+    }
+
+    bufferIds.erase(findBufferId);
+    if (bufferIds.empty()) {
+        frameIndex2BufferIds.erase(findFrameIndex);
+        if (frameIndex2BufferIds.empty()) {
+            mTrackedBuffersMap.erase(findListener);
+        }
+    }
+
+    DeathNotifications &deathNotifications = mDeathNotifications[bufferId->listener];
+    deathNotifications.indices[bufferId->frameIndex].emplace_back(bufferId->bufferIndex);
+    ++deathNotifications.count;
+    mOnBufferDestroyed.notify_one();
+
+    mTrackedBufferCache.erase(bufferId);
+    delete bufferId;
+}
+
+// Notify the clients about buffer destructions.
+// Return false if all destructions have been notified.
+// Return true and set timeToRetry to the time point to wait for before
+// retrying if some destructions have not been notified.
+bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
+
+    struct Notification {
+        sp<IComponentListener> listener;
+        hidl_vec<IComponentListener::InputBuffer> inputBuffers;
+        Notification(const sp<IComponentListener>& l, size_t s)
+              : listener(l), inputBuffers(s) {}
+    };
+    std::list<Notification> notifications;
+    nsecs_t notificationIntervalNs =
+            mNotificationIntervalNs.load(std::memory_order_relaxed);
+
+    bool retry = false;
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        *timeToRetryNs = notificationIntervalNs;
+        nsecs_t timeNowNs = systemTime();
+        for (auto it = mDeathNotifications.begin();
+                it != mDeathNotifications.end(); ) {
+            sp<IComponentListener> listener = it->first.promote();
+            if (!listener) {
+                ++it;
+                continue;
+            }
+            DeathNotifications &deathNotifications = it->second;
+
+            nsecs_t timeSinceLastNotifiedNs =
+                    timeNowNs - deathNotifications.lastSentNs;
+            // If not enough time has passed since the last callback, leave the
+            // notifications for this listener untouched for now and retry
+            // later.
+            if (timeSinceLastNotifiedNs < notificationIntervalNs) {
+                retry = true;
+                *timeToRetryNs = std::min(*timeToRetryNs,
+                        notificationIntervalNs - timeSinceLastNotifiedNs);
+                LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                             << "Notifications for listener @ "
+                                 << std::hex << listener.get()
+                             << " will be postponed.";
+                ++it;
+                continue;
+            }
+
+            // If enough time has passed since the last notification to this
+            // listener but there are currently no pending notifications, the
+            // listener can be removed from mDeathNotifications---there is no
+            // need to keep track of the last notification time anymore.
+            if (deathNotifications.count == 0) {
+                it = mDeathNotifications.erase(it);
+                continue;
+            }
+
+            // Create the argument for the callback.
+            notifications.emplace_back(listener, deathNotifications.count);
+            hidl_vec<IComponentListener::InputBuffer> &inputBuffers =
+                    notifications.back().inputBuffers;
+            size_t i = 0;
+            for (std::pair<const uint64_t, std::vector<size_t>>& p :
+                    deathNotifications.indices) {
+                uint64_t frameIndex = p.first;
+                const std::vector<size_t> &bufferIndices = p.second;
+                for (const size_t& bufferIndex : bufferIndices) {
+                    IComponentListener::InputBuffer &inputBuffer
+                            = inputBuffers[i++];
+                    inputBuffer.arrayIndex = bufferIndex;
+                    inputBuffer.frameIndex = frameIndex;
+                }
+            }
+
+            // Clear deathNotifications for this listener and set retry to true
+            // so processNotifications will be called again. This will
+            // guarantee that a listener with no pending notifications will
+            // eventually be removed from mDeathNotifications after
+            // mNotificationIntervalNs nanoseconds has passed.
+            retry = true;
+            deathNotifications.indices.clear();
+            deathNotifications.count = 0;
+            deathNotifications.lastSentNs = timeNowNs;
+            ++it;
+        }
+    }
+
+    // Call onInputBuffersReleased() outside the lock to avoid deadlock.
+    for (const Notification& notification : notifications) {
+        if (!notification.listener->onInputBuffersReleased(
+                notification.inputBuffers).isOk()) {
+            // This may trigger if the client has died.
+            LOG(DEBUG) << "InputBufferManager::processNotifications -- "
+                       << "failed to send death notifications to "
+                       << "listener @ 0x" << std::hex
+                                          << notification.listener.get()
+                       << std::dec << ".";
+        } else {
+#if LOG_NDEBUG == 0
+            std::stringstream inputBufferLog;
+            for (const IComponentListener::InputBuffer& inputBuffer :
+                    notification.inputBuffers) {
+                inputBufferLog << " (" << inputBuffer.frameIndex
+                               << ", " << inputBuffer.arrayIndex
+                               << ")";
+            }
+            LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                         << "death notifications sent to "
+                         << "listener @ 0x" << std::hex
+                                            << notification.listener.get()
+                                            << std::dec
+                         << " with these (frameIndex, bufferIndex) pairs:"
+                         << inputBufferLog.str();
+#endif
+        }
+    }
+#if LOG_NDEBUG == 0
+    if (retry) {
+        LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                     << "will retry again in " << *timeToRetryNs << "ns.";
+    } else {
+        LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                     << "no pending death notifications.";
+    }
+#endif
+    return retry;
+}
+
+void InputBufferManager::main() {
+    LOG(VERBOSE) << "InputBufferManager main -- started.";
+    nsecs_t timeToRetryNs;
+    while (true) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        while (mDeathNotifications.empty()) {
+            mOnBufferDestroyed.wait(lock);
+        }
+        lock.unlock();
+        while (processNotifications(&timeToRetryNs)) {
+            std::this_thread::sleep_for(
+                    std::chrono::nanoseconds(timeToRetryNs));
+        }
+    }
+}
+
+InputBufferManager::InputBufferManager()
+      : mMainThread{&InputBufferManager::main, this} {
+}
+
+InputBufferManager& InputBufferManager::getInstance() {
+    static InputBufferManager instance{};
+    return instance;
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+
+
diff --git a/media/codec2/hal/aidl/InputSurface.cpp b/media/codec2/hal/aidl/InputSurface.cpp
new file mode 100644
index 0000000..c3c32e9
--- /dev/null
+++ b/media/codec2/hal/aidl/InputSurface.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-InputSurface"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputSurface.h>
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+
+#include <C2Component.h>
+#include <C2Config.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+// Derived class of C2InterfaceHelper
+class InputSurface::Interface : public C2InterfaceHelper {
+public:
+    explicit Interface(
+            const std::shared_ptr<C2ReflectorHelper> &helper)
+        : C2InterfaceHelper(helper) {
+
+        setDerivedInstance(this);
+
+        addParameter(
+                DefineParam(mEos, C2_PARAMKEY_INPUT_SURFACE_EOS)
+                .withDefault(new C2InputSurfaceEosTuning(false))
+                .withFields({C2F(mEos, value).oneOf({true, false})})
+                .withSetter(EosSetter)
+                .build());
+    }
+
+    static C2R EosSetter(bool mayBlock, C2P<C2InputSurfaceEosTuning> &me) {
+        (void)mayBlock;
+        return me.F(me.v.value).validatePossible(me.v.value);
+    }
+
+    bool eos() const { return mEos->value; }
+
+private:
+    std::shared_ptr<C2InputSurfaceEosTuning> mEos;
+};
+
+// Derived class of ConfigurableC2Intf
+class InputSurface::ConfigurableIntf : public ConfigurableC2Intf {
+public:
+    ConfigurableIntf(
+            const std::shared_ptr<InputSurface::Interface> &intf,
+            const sp<GraphicBufferSource> &source)
+        : ConfigurableC2Intf("input-surface", 0),
+          mIntf(intf),
+          mSource(source) {
+    }
+
+    virtual ~ConfigurableIntf() override = default;
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        return mIntf->query({}, indices, mayBlock, params);
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        c2_status_t err = mIntf->config(params, mayBlock, failures);
+        if (mIntf->eos()) {
+            sp<GraphicBufferSource> source = mSource.promote();
+            if (source == nullptr || source->signalEndOfInputStream() != OK) {
+                // TODO: put something in |failures|
+                err = C2_BAD_VALUE;
+            }
+            // TODO: reset eos?
+        }
+        return err;
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        return mIntf->querySupportedParams(params);
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const override {
+        return mIntf->querySupportedValues(fields, mayBlock);
+    }
+
+private:
+    const std::shared_ptr<InputSurface::Interface> mIntf;
+    wp<GraphicBufferSource> mSource;
+};
+
+Return<sp<InputSurface::HGraphicBufferProducer>> InputSurface::getGraphicBufferProducer() {
+    return mProducer;
+}
+
+Return<sp<IConfigurable>> InputSurface::getConfigurable() {
+    return mConfigurable;
+}
+
+Return<void> InputSurface::connect(
+        const sp<IInputSink>& sink,
+        connect_cb _hidl_cb) {
+    Status status;
+    sp<InputSurfaceConnection> connection;
+    if (!sink) {
+        _hidl_cb(Status::BAD_VALUE, nullptr);
+        return Void();
+    }
+    std::shared_ptr<C2Component> comp = Component::findLocalComponent(sink);
+    if (comp) {
+        connection = new InputSurfaceConnection(mSource, comp, mParameterCache);
+    } else {
+        connection = new InputSurfaceConnection(mSource, sink, mParameterCache);
+    }
+    if (!connection->init()) {
+        connection = nullptr;
+        status = Status::BAD_VALUE;
+    } else {
+        status = Status::OK;
+    }
+    _hidl_cb(status, connection);
+    return Void();
+}
+
+// Constructor is exclusive to ComponentStore.
+InputSurface::InputSurface(
+        const std::shared_ptr<ParameterCache>& cache,
+        const std::shared_ptr<C2ReflectorHelper>& reflector,
+        const sp<HGraphicBufferProducer>& producer,
+        const sp<GraphicBufferSource>& source)
+      : mParameterCache{cache},
+        mProducer{producer},
+        mSource{source},
+        mIntf{std::make_shared<Interface>(reflector)},
+        mConfigurable{new CachedConfigurable(
+                std::make_unique<ConfigurableIntf>(
+                    mIntf, source))} {
+
+    mConfigurable->init(mParameterCache);
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/codec2/hal/aidl/InputSurfaceConnection.cpp b/media/codec2/hal/aidl/InputSurfaceConnection.cpp
new file mode 100644
index 0000000..7c2e014
--- /dev/null
+++ b/media/codec2/hal/aidl/InputSurfaceConnection.cpp
@@ -0,0 +1,531 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-InputSurfaceConnection"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+
+#include <memory>
+#include <list>
+#include <mutex>
+#include <atomic>
+
+#include <hidl/HidlSupport.h>
+#include <media/stagefright/bqhelper/ComponentWrapper.h>
+#include <system/graphics.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+
+#include <C2.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2Component.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+#include <C2Work.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+constexpr int32_t kBufferCount = 16;
+
+using namespace ::android;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+namespace /* unnamed */ {
+
+class Buffer2D : public C2Buffer {
+public:
+    explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {
+    }
+};
+
+} // unnamed namespace
+
+// Derived class of ComponentWrapper for use with
+// GraphicBufferSource::configure().
+//
+struct InputSurfaceConnection::Impl : public ComponentWrapper {
+
+    Impl(const sp<GraphicBufferSource>& source,
+         const std::shared_ptr<C2Component>& localComp)
+          : mSource{source}, mLocalComp{localComp}, mSink{}, mFrameIndex{0} {
+        std::shared_ptr<C2ComponentInterface> intf = localComp->intf();
+        mSinkName = intf ? intf->getName() : "";
+    }
+
+    Impl(const sp<GraphicBufferSource>& source,
+         const sp<IInputSink>& sink)
+          : mSource{source}, mLocalComp{}, mSink{sink}, mFrameIndex{0} {
+        Return<sp<IConfigurable>> transResult = sink->getConfigurable();
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "Remote sink is dead.";
+            return;
+        }
+        mSinkConfigurable =
+                static_cast<sp<IConfigurable>>(transResult);
+        if (!mSinkConfigurable) {
+            LOG(ERROR) << "Remote sink is not configurable.";
+            mSinkName = "";
+            return;
+        }
+
+        hidl_string name;
+        Return<void> transStatus = mSinkConfigurable->getName(
+                [&name](const hidl_string& n) {
+                    name = n;
+                });
+        if (!transStatus.isOk()) {
+            LOG(ERROR) << "Remote sink's configurable is dead.";
+            mSinkName = "";
+            return;
+        }
+        mSinkName = name.c_str();
+    }
+
+    virtual ~Impl() {
+        mSource->stop();
+        mSource->release();
+    }
+
+    bool init() {
+        if (mSource == nullptr) {
+            return false;
+        }
+        status_t err = mSource->initCheck();
+        if (err != OK) {
+            LOG(WARNING) << "Impl::init -- GraphicBufferSource init failed: "
+                         << "status = " << err << ".";
+            return false;
+        }
+
+        // TODO: read settings properly from the interface
+        C2StreamPictureSizeInfo::input inputSize;
+        C2StreamUsageTuning::input usage;
+        c2_status_t c2Status = queryFromSink({ &inputSize, &usage },
+                                         {},
+                                         C2_MAY_BLOCK,
+                                         nullptr);
+        if (c2Status != C2_OK) {
+            LOG(WARNING) << "Impl::init -- cannot query information from "
+                            "the component interface: "
+                         << "status = " << asString(c2Status) << ".";
+            return false;
+        }
+
+        // TODO: proper color aspect & dataspace
+        android_dataspace dataSpace = HAL_DATASPACE_BT709;
+
+        // TODO: use the usage read from intf
+        // uint32_t grallocUsage =
+        //         C2AndroidMemoryUsage(C2MemoryUsage(usage.value)).
+        //         asGrallocUsage();
+
+        uint32_t grallocUsage =
+                mSinkName.compare(0, 11, "c2.android.") == 0 ?
+                GRALLOC_USAGE_SW_READ_OFTEN :
+                GRALLOC_USAGE_HW_VIDEO_ENCODER;
+
+        err = mSource->configure(
+                this, dataSpace, kBufferCount,
+                inputSize.width, inputSize.height,
+                grallocUsage);
+        if (err != OK) {
+            LOG(WARNING) << "Impl::init -- GBS configure failed: "
+                         << "status = " << err << ".";
+            return false;
+        }
+        for (int32_t i = 0; i < kBufferCount; ++i) {
+            if (mSource->onInputBufferAdded(i) != OK) {
+                LOG(WARNING) << "Impl::init: failed to populate GBS slots.";
+                return false;
+            }
+        }
+        if (mSource->start() != OK) {
+            LOG(WARNING) << "Impl::init -- GBS failed to start.";
+            return false;
+        }
+        mAllocatorMutex.lock();
+        c2_status_t c2err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
+                C2AllocatorStore::PLATFORM_START + 1,  // GRALLOC
+                &mAllocator);
+        mAllocatorMutex.unlock();
+        if (c2err != OK) {
+            LOG(WARNING) << "Impl::init -- failed to fetch gralloc allocator: "
+                         << "status = " << asString(c2err) << ".";
+            return false;
+        }
+        return true;
+    }
+
+    // From ComponentWrapper
+    virtual status_t submitBuffer(
+            int32_t bufferId,
+            const sp<GraphicBuffer>& buffer,
+            int64_t timestamp,
+            int fenceFd) override {
+        LOG(VERBOSE) << "Impl::submitBuffer -- bufferId = " << bufferId << ".";
+        // TODO: Use fd to construct fence
+        (void)fenceFd;
+
+        std::shared_ptr<C2GraphicAllocation> alloc;
+        C2Handle* handle = WrapNativeCodec2GrallocHandle(
+                buffer->handle,
+                buffer->width, buffer->height,
+                buffer->format, buffer->usage, buffer->stride);
+        mAllocatorMutex.lock();
+        c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
+        mAllocatorMutex.unlock();
+        if (err != OK) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+            return UNKNOWN_ERROR;
+        }
+        std::shared_ptr<C2GraphicBlock> block =
+                _C2BlockFactory::CreateGraphicBlock(alloc);
+
+        std::unique_ptr<C2Work> work(new C2Work);
+        work->input.flags = (C2FrameData::flags_t)0;
+        work->input.ordinal.timestamp = timestamp;
+        work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
+                1, std::memory_order_relaxed);
+        work->input.buffers.clear();
+        std::shared_ptr<C2Buffer> c2Buffer(
+                // TODO: fence
+                new Buffer2D(block->share(
+                        C2Rect(block->width(), block->height()), ::C2Fence())),
+                [bufferId, source = mSource](C2Buffer* ptr) {
+                    delete ptr;
+                    if (source != nullptr) {
+                        // TODO: fence
+                        (void)source->onInputBufferEmptied(bufferId, -1);
+                    }
+                });
+        work->input.buffers.push_back(c2Buffer);
+        work->worklets.clear();
+        work->worklets.emplace_back(new C2Worklet);
+        std::list<std::unique_ptr<C2Work>> items;
+        items.push_back(std::move(work));
+
+        err = queueToSink(&items);
+        return (err == C2_OK) ? OK : UNKNOWN_ERROR;
+    }
+
+    virtual status_t submitEos(int32_t bufferId) override {
+        LOG(VERBOSE) << "Impl::submitEos -- bufferId = " << bufferId << ".";
+        (void)bufferId;
+
+        std::unique_ptr<C2Work> work(new C2Work);
+        work->input.flags = (C2FrameData::flags_t)0;
+        work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
+                1, std::memory_order_relaxed);
+        work->input.buffers.clear();
+        work->worklets.clear();
+        work->worklets.emplace_back(new C2Worklet);
+        std::list<std::unique_ptr<C2Work>> items;
+        items.push_back(std::move(work));
+
+        c2_status_t err = queueToSink(&items);
+        return (err == C2_OK) ? OK : UNKNOWN_ERROR;
+    }
+
+    virtual void dispatchDataSpaceChanged(
+            int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
+        // TODO
+        (void)dataSpace;
+        (void)aspects;
+        (void)pixelFormat;
+    }
+
+    // Configurable interface for InputSurfaceConnection::Impl.
+    //
+    // This class is declared as an inner class so that it will have access to
+    // all Impl's members.
+    struct ConfigurableIntf : public ConfigurableC2Intf {
+        sp<Impl> mConnection;
+        ConfigurableIntf(const sp<Impl>& connection)
+              : ConfigurableC2Intf{"input-surface-connection", 0},
+                mConnection{connection} {}
+        virtual c2_status_t config(
+                const std::vector<C2Param*> &params,
+                c2_blocking_t mayBlock,
+                std::vector<std::unique_ptr<C2SettingResult>> *const failures
+                ) override;
+        virtual c2_status_t query(
+                const std::vector<C2Param::Index> &indices,
+                c2_blocking_t mayBlock,
+                std::vector<std::unique_ptr<C2Param>> *const params) const override;
+        virtual c2_status_t querySupportedParams(
+                std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+                ) const override;
+        virtual c2_status_t querySupportedValues(
+                std::vector<C2FieldSupportedValuesQuery> &fields,
+                c2_blocking_t mayBlock) const override;
+    };
+
+private:
+    c2_status_t queryFromSink(
+            const std::vector<C2Param*> &stackParams,
+            const std::vector<C2Param::Index> &heapParamIndices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const heapParams) {
+        if (mLocalComp) {
+            std::shared_ptr<C2ComponentInterface> intf = mLocalComp->intf();
+            if (intf) {
+                return intf->query_vb(stackParams,
+                                      heapParamIndices,
+                                      mayBlock,
+                                      heapParams);
+            } else {
+                LOG(ERROR) << "queryFromSink -- "
+                           << "component does not have an interface.";
+                return C2_BAD_STATE;
+            }
+        }
+
+        CHECK(mSink) << "-- queryFromSink "
+                     << "-- connection has no sink.";
+        CHECK(mSinkConfigurable) << "-- queryFromSink "
+                                 << "-- sink has no configurable.";
+
+        hidl_vec<ParamIndex> indices(
+                stackParams.size() + heapParamIndices.size());
+        size_t numIndices = 0;
+        for (C2Param* const& stackParam : stackParams) {
+            if (!stackParam) {
+                LOG(DEBUG) << "queryFromSink -- null stack param encountered.";
+                continue;
+            }
+            indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
+        }
+        size_t numStackIndices = numIndices;
+        for (const C2Param::Index& index : heapParamIndices) {
+            indices[numIndices++] =
+                    static_cast<ParamIndex>(static_cast<uint32_t>(index));
+        }
+        indices.resize(numIndices);
+        if (heapParams) {
+            heapParams->reserve(heapParams->size() + numIndices);
+        }
+        c2_status_t status;
+        Return<void> transStatus = mSinkConfigurable->query(
+                indices,
+                mayBlock == C2_MAY_BLOCK,
+                [&status, &numStackIndices, &stackParams, heapParams](
+                        Status s, const Params& p) {
+                    status = static_cast<c2_status_t>(s);
+                    if (status != C2_OK && status != C2_BAD_INDEX) {
+                        LOG(DEBUG) << "queryFromSink -- call failed: "
+                                   << "status = " << asString(status) << ".";
+                        return;
+                    }
+                    std::vector<C2Param*> paramPointers;
+                    if (!parseParamsBlob(&paramPointers, p)) {
+                        LOG(DEBUG) << "queryFromSink -- error while "
+                                   << "parsing params.";
+                        status = C2_CORRUPTED;
+                        return;
+                    }
+                    size_t i = 0;
+                    for (auto it = paramPointers.begin();
+                            it != paramPointers.end(); ) {
+                        C2Param* paramPointer = *it;
+                        if (numStackIndices > 0) {
+                            --numStackIndices;
+                            if (!paramPointer) {
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "null stack param.";
+                                ++it;
+                                continue;
+                            }
+                            for (; i < stackParams.size() &&
+                                    !stackParams[i]; ) {
+                                ++i;
+                            }
+                            CHECK(i < stackParams.size());
+                            if (stackParams[i]->index() !=
+                                    paramPointer->index()) {
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "param skipped (index = "
+                                           << stackParams[i]->index() << ").";
+                                stackParams[i++]->invalidate();
+                                continue;
+                            }
+                            if (!stackParams[i++]->updateFrom(*paramPointer)) {
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "param update failed (index = "
+                                           << paramPointer->index() << ").";
+                            }
+                        } else {
+                            if (!paramPointer) {
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "null heap param.";
+                                ++it;
+                                continue;
+                            }
+                            if (!heapParams) {
+                                LOG(WARNING) << "queryFromSink -- "
+                                                "too many stack params.";
+                                break;
+                            }
+                            heapParams->emplace_back(C2Param::Copy(*paramPointer));
+                        }
+                        ++it;
+                    }
+                });
+        if (!transStatus.isOk()) {
+            LOG(ERROR) << "queryFromSink -- transaction failed.";
+            return C2_CORRUPTED;
+        }
+        return status;
+    }
+
+    c2_status_t queueToSink(std::list<std::unique_ptr<C2Work>>* const items) {
+        if (mLocalComp) {
+            return mLocalComp->queue_nb(items);
+        }
+
+        CHECK(mSink) << "-- queueToSink "
+                     << "-- connection has no sink.";
+
+        WorkBundle workBundle;
+        if (!objcpy(&workBundle, *items, nullptr)) {
+            LOG(ERROR) << "queueToSink -- bad input.";
+            return C2_CORRUPTED;
+        }
+        Return<Status> transStatus = mSink->queue(workBundle);
+        if (!transStatus.isOk()) {
+            LOG(ERROR) << "queueToSink -- transaction failed.";
+            return C2_CORRUPTED;
+        }
+        c2_status_t status =
+                static_cast<c2_status_t>(static_cast<Status>(transStatus));
+        if (status != C2_OK) {
+            LOG(DEBUG) << "queueToSink -- call failed: "
+                         << asString(status);
+        }
+        return status;
+    }
+
+    sp<GraphicBufferSource> mSource;
+    std::shared_ptr<C2Component> mLocalComp;
+    sp<IInputSink> mSink;
+    sp<IConfigurable> mSinkConfigurable;
+    std::string mSinkName;
+
+    // Needed for ComponentWrapper implementation
+    std::mutex mAllocatorMutex;
+    std::shared_ptr<C2Allocator> mAllocator;
+    std::atomic_uint64_t mFrameIndex;
+
+};
+
+InputSurfaceConnection::InputSurfaceConnection(
+        const sp<GraphicBufferSource>& source,
+        const std::shared_ptr<C2Component>& comp,
+        const std::shared_ptr<ParameterCache>& cache)
+      : mImpl{new Impl(source, comp)},
+        mConfigurable{new CachedConfigurable(
+            std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+    mConfigurable->init(cache);
+}
+
+InputSurfaceConnection::InputSurfaceConnection(
+        const sp<GraphicBufferSource>& source,
+        const sp<IInputSink>& sink,
+        const std::shared_ptr<ParameterCache>& cache)
+      : mImpl{new Impl(source, sink)},
+        mConfigurable{new CachedConfigurable(
+            std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+    mConfigurable->init(cache);
+}
+
+Return<Status> InputSurfaceConnection::disconnect() {
+    std::lock_guard<std::mutex> lock(mImplMutex);
+    mImpl = nullptr;
+    return Status::OK;
+}
+
+InputSurfaceConnection::~InputSurfaceConnection() {
+    mImpl = nullptr;
+}
+
+bool InputSurfaceConnection::init() {
+    std::lock_guard<std::mutex> lock(mImplMutex);
+    return mImpl->init();
+}
+
+Return<sp<IConfigurable>> InputSurfaceConnection::getConfigurable() {
+    return mConfigurable;
+}
+
+// Configurable interface for InputSurfaceConnection::Impl
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::config(
+        const std::vector<C2Param*> &params,
+        c2_blocking_t mayBlock,
+        std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
+    // TODO: implement
+    (void)params;
+    (void)mayBlock;
+    (void)failures;
+    return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::query(
+        const std::vector<C2Param::Index> &indices,
+        c2_blocking_t mayBlock,
+        std::vector<std::unique_ptr<C2Param>> *const params) const {
+    // TODO: implement
+    (void)indices;
+    (void)mayBlock;
+    (void)params;
+    return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedParams(
+        std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+    // TODO: implement
+    (void)params;
+    return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedValues(
+        std::vector<C2FieldSupportedValuesQuery> &fields,
+        c2_blocking_t mayBlock) const {
+    // TODO: implement
+    (void)fields;
+    (void)mayBlock;
+    return C2_OK;
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
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/Component.h b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
new file mode 100644
index 0000000..e343655
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
+
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.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>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <hidl/Status.h>
+#include <hwbinder/IBinder.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::IBinder;
+using ::android::sp;
+using ::android::wp;
+
+struct ComponentStore;
+
+struct Component : public IComponent,
+                   public std::enable_shared_from_this<Component> {
+    Component(
+            const std::shared_ptr<C2Component>&,
+            const sp<IComponentListener>& listener,
+            const sp<ComponentStore>& store,
+            const sp<::android::hardware::media::bufferpool::V2_0::
+                IClientManager>& clientPoolManager);
+    c2_status_t status() const;
+
+    typedef ::android::hardware::graphics::bufferqueue::V1_0::
+            IGraphicBufferProducer HGraphicBufferProducer1;
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer HGraphicBufferProducer2;
+
+    // Methods from IComponent follow.
+    virtual Return<Status> queue(const WorkBundle& workBundle) override;
+    virtual Return<void> flush(flush_cb _hidl_cb) override;
+    virtual Return<Status> drain(bool withEos) override;
+    virtual Return<Status> setOutputSurface(
+            uint64_t blockPoolId,
+            const sp<HGraphicBufferProducer2>& surface) override;
+    virtual Return<void> connectToInputSurface(
+            const sp<IInputSurface>& inputSurface,
+            connectToInputSurface_cb _hidl_cb) override;
+    virtual Return<void> connectToOmxInputSurface(
+            const sp<HGraphicBufferProducer1>& producer,
+            const sp<::android::hardware::media::omx::V1_0::
+            IGraphicBufferSource>& source,
+            connectToOmxInputSurface_cb _hidl_cb) override;
+    virtual Return<Status> disconnectFromInputSurface() override;
+    virtual Return<void> createBlockPool(
+            uint32_t allocatorId,
+            createBlockPool_cb _hidl_cb) override;
+    virtual Return<Status> destroyBlockPool(uint64_t blockPoolId) override;
+    virtual Return<Status> start() override;
+    virtual Return<Status> stop() override;
+    virtual Return<Status> reset() override;
+    virtual Return<Status> release() override;
+    virtual Return<sp<IComponentInterface>> getInterface() override;
+    virtual Return<sp<IInputSink>> asInputSink() override;
+
+    // Returns a C2Component associated to the given sink if the sink is indeed
+    // a local component. Returns nullptr otherwise.
+    //
+    // This function is used by InputSurface::connect().
+    static std::shared_ptr<C2Component> findLocalComponent(
+            const sp<IInputSink>& sink);
+
+protected:
+    c2_status_t mInit;
+    std::shared_ptr<C2Component> mComponent;
+    sp<ComponentInterface> mInterface;
+    sp<IComponentListener> mListener;
+    sp<ComponentStore> mStore;
+    ::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender
+            mBufferPoolSender;
+
+    struct Sink;
+    std::mutex mSinkMutex;
+    sp<Sink> mSink;
+
+    std::mutex mBlockPoolsMutex;
+    // This map keeps C2BlockPool objects that are created by createBlockPool()
+    // alive. These C2BlockPool objects can be deleted by calling
+    // destroyBlockPool(), reset() or release(), or by destroying the component.
+    std::map<uint64_t, std::shared_ptr<C2BlockPool>> mBlockPools;
+
+    void initListener(const sp<Component>& self);
+
+    virtual ~Component() override;
+
+    friend struct ComponentStore;
+
+    struct Listener;
+
+    using HwDeathRecipient = ::android::hardware::hidl_death_recipient;
+    sp<HwDeathRecipient> mDeathRecipient;
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h
new file mode 100644
index 0000000..9102f92
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+struct ComponentInterface : public IComponentInterface {
+    ComponentInterface(
+            const std::shared_ptr<C2ComponentInterface>& interface,
+            const std::shared_ptr<ParameterCache>& cache);
+    c2_status_t status() const;
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+protected:
+    std::shared_ptr<C2ComponentInterface> mInterface;
+    sp<CachedConfigurable> mConfigurable;
+    c2_status_t mInit;
+};
+
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
new file mode 100644
index 0000000..27e2a05
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/Configurable.h>
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <chrono>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <vector>
+
+namespace android {
+class FilterWrapper;
+
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::media::bufferpool::V2_0::IClientManager;
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore : public IComponentStore {
+    ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
+    virtual ~ComponentStore();
+
+    /**
+     * Returns the status of the construction of this object.
+     */
+    c2_status_t status() const;
+
+    /**
+     * This function is called by CachedConfigurable::init() to validate
+     * supported parameters.
+     */
+    c2_status_t validateSupportedParams(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
+
+    /**
+     * Returns the store's ParameterCache. This is used for validation by
+     * Configurable::init().
+     */
+    std::shared_ptr<ParameterCache> getParameterCache() const;
+
+    static std::shared_ptr<FilterWrapper> GetFilterWrapper();
+
+    // Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
+    virtual Return<void> createComponent(
+            const hidl_string& name,
+            const sp<IComponentListener>& listener,
+            const sp<IClientManager>& pool,
+            createComponent_cb _hidl_cb) override;
+    virtual Return<void> createInterface(
+            const hidl_string& name,
+            createInterface_cb _hidl_cb) override;
+    virtual Return<void> listComponents(listComponents_cb _hidl_cb) override;
+    virtual Return<void> createInputSurface(
+            createInputSurface_cb _hidl_cb) override;
+    virtual Return<void> getStructDescriptors(
+            const hidl_vec<uint32_t>& indices,
+            getStructDescriptors_cb _hidl_cb) override;
+    virtual Return<sp<IClientManager>> getPoolClientManager() override;
+    virtual Return<Status> copyBuffer(
+            const Buffer& src,
+            const Buffer& dst) override;
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+    /**
+     * Dumps information when lshal is called.
+     */
+    virtual Return<void> debug(
+            const hidl_handle& handle,
+            const hidl_vec<hidl_string>& args) override;
+
+protected:
+    sp<CachedConfigurable> mConfigurable;
+    struct StoreParameterCache;
+    std::shared_ptr<StoreParameterCache> mParameterCache;
+
+    // Does bookkeeping for an interface that has been loaded.
+    void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
+
+    c2_status_t mInit;
+    std::shared_ptr<C2ComponentStore> mStore;
+    std::shared_ptr<C2ParamReflector> mParamReflector;
+
+    std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
+    std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
+    std::set<C2String> mLoadedInterfaces;
+    mutable std::mutex mStructDescriptorsMutex;
+
+    // ComponentStore keeps track of live Components.
+
+    struct ComponentStatus {
+        std::shared_ptr<C2Component> c2Component;
+        std::chrono::system_clock::time_point birthTime;
+    };
+
+    mutable std::mutex mComponentRosterMutex;
+    std::map<Component*, ComponentStatus> mComponentRoster;
+
+    // Called whenever Component is created.
+    void reportComponentBirth(Component* component);
+    // Called only from the destructor of Component.
+    void reportComponentDeath(Component* component);
+
+    friend Component;
+
+    // Helper functions for dumping.
+
+    std::ostream& dump(
+            std::ostream& out,
+            const std::shared_ptr<const C2Component::Traits>& comp);
+
+    std::ostream& dump(
+            std::ostream& out,
+            ComponentStatus& compStatus);
+
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
new file mode 100644
index 0000000..8f49a97
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+#define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+/**
+ * Codec2 objects of different types may have different querying and configuring
+ * functions, but across the Treble boundary, they share the same HIDL
+ * interface, IConfigurable.
+ *
+ * ConfigurableC2Intf is an abstract class that a Codec2 object can implement to
+ * easily expose an IConfigurable instance. See CachedConfigurable below.
+ */
+struct ConfigurableC2Intf {
+    C2String getName() const { return mName; }
+    uint32_t getId() const { return mId; }
+    /** C2ComponentInterface::query_vb sans stack params */
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
+    /** C2ComponentInterface::config_vb */
+    virtual c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+    /** C2ComponentInterface::querySupportedParams_nb */
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
+    /** C2ComponentInterface::querySupportedParams_nb */
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
+
+    virtual ~ConfigurableC2Intf() = default;
+
+    ConfigurableC2Intf(const C2String& name, uint32_t id)
+          : mName{name}, mId{id} {}
+
+protected:
+    C2String mName; /* cached component name */
+    uint32_t mId;
+};
+
+/**
+ * Type for validating and caching parameters when CachedConfigurable is
+ * initialized.
+ *
+ * This is meant to be created by the ComponentStore. The purpose of abstracting
+ * this is to allow different versions of ComponentStore to work with this
+ * CachedConfigurable.
+ */
+struct ParameterCache {
+    virtual c2_status_t validate(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>&) = 0;
+    virtual ~ParameterCache() = default;
+};
+
+/**
+ * Implementation of the IConfigurable interface that supports caching of
+ * supported parameters from a supplied ComponentStore.
+ *
+ * CachedConfigurable essentially converts a ConfigurableC2Intf into HIDL's
+ * IConfigurable. A Codec2 object generally implements ConfigurableC2Intf and
+ * passes the implementation to the constructor of CachedConfigurable.
+ *
+ * Note that caching happens
+ */
+struct CachedConfigurable : public IConfigurable {
+    CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
+
+    // Populates mSupportedParams.
+    c2_status_t init(const std::shared_ptr<ParameterCache> &cache);
+
+    // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
+
+    virtual Return<uint32_t> getId() override;
+
+    virtual Return<void> getName(getName_cb _hidl_cb) override;
+
+    virtual Return<void> query(
+            const hidl_vec<uint32_t>& indices,
+            bool mayBlock,
+            query_cb _hidl_cb) override;
+
+    virtual Return<void> config(
+            const hidl_vec<uint8_t>& inParams,
+            bool mayBlock,
+            config_cb _hidl_cb) override;
+
+    virtual Return<void> querySupportedParams(
+            uint32_t start,
+            uint32_t count,
+            querySupportedParams_cb _hidl_cb) override;
+
+    virtual Return<void> querySupportedValues(
+            const hidl_vec<FieldSupportedValuesQuery>& inFields,
+            bool mayBlock,
+            querySupportedValues_cb _hidl_cb) override;
+
+protected:
+    // Common Codec2.0 interface wrapper
+    std::unique_ptr<ConfigurableC2Intf> mIntf;
+
+    // Cached supported params
+    std::vector<std::shared_ptr<C2ParamDescriptor>> mSupportedParams;
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/InputBufferManager.h b/media/codec2/hal/aidl/include/codec2/aidl/InputBufferManager.h
new file mode 100644
index 0000000..42fa557
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/InputBufferManager.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <utils/Timers.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <set>
+#include <map>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+/**
+ * InputBufferManager
+ * ==================
+ *
+ * InputBufferManager presents a way to track and untrack input buffers in this
+ * (codec) process and send a notification to a listener, possibly in a
+ * different process, when a tracked buffer no longer has any references in this
+ * process.
+ *
+ * InputBufferManager holds a collection of records representing tracked buffers
+ * and their callback listeners. Conceptually, one record is a triple (listener,
+ * frameIndex, bufferIndex) where
+ *
+ * - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
+ * - listener is of type IComponentListener. Its onInputBuffersReleased()
+ *   function will be called after the associated buffer dies. The argument of
+ *   onInputBuffersReleased() is a list of InputBuffer objects, each of which
+ *   has the following members:
+ *
+ *     uint64_t frameIndex
+ *     uint32_t arrayIndex
+ *
+ * When a tracked buffer associated to the triple (listener, frameIndex,
+ * bufferIndex) goes out of scope, listener->onInputBuffersReleased() will be
+ * called with an InputBuffer object whose members are set as follows:
+ *
+ *     inputBuffer.frameIndex = frameIndex
+ *     inputBuffer.arrayIndex = bufferIndex
+ *
+ * IPC Optimization
+ * ----------------
+ *
+ * Since onInputBuffersReleased() is an IPC call, InputBufferManager tries not
+ * to call it too often. Any two calls to the same listener are at least
+ * mNotificationIntervalNs nanoseconds apart, where mNotificationIntervalNs is
+ * configurable via calling setNotificationInterval(). The default value of
+ * mNotificationIntervalNs is kDefaultNotificationInternalNs.
+ *
+ * Public Member Functions
+ * -----------------------
+ *
+ * InputBufferManager is a singleton class. Its only instance is accessible via
+ * the following public functions:
+ *
+ * - registerFrameData(const sp<IComponentListener>& listener,
+ *                     const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener,
+ *                       const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener)
+ *
+ * - setNotificationInterval(nsecs_t notificationIntervalNs)
+ *
+ */
+
+struct InputBufferManager {
+
+    /**
+     * The default value for the time interval between 2 subsequent IPCs.
+     */
+    static constexpr nsecs_t kDefaultNotificationIntervalNs = 1000000; /* 1ms */
+
+    /**
+     * Track all buffers in a C2FrameData object.
+     *
+     * input (C2FrameData) has the following two members that are of interest:
+     *
+     *   C2WorkOrdinal                ordinal
+     *   vector<shared_ptr<C2Buffer>> buffers
+     *
+     * Calling registerFrameData(listener, input) will register multiple
+     * triples (listener, frameIndex, bufferIndex) where frameIndex is equal to
+     * input.ordinal.frameIndex and bufferIndex runs through the indices of
+     * input.buffers such that input.buffers[bufferIndex] is not null.
+     *
+     * This should be called from queue().
+     *
+     * \param listener Listener of death notifications.
+     * \param input Input frame data whose input buffers are to be tracked.
+     */
+    static void registerFrameData(
+            const sp<IComponentListener>& listener,
+            const C2FrameData& input);
+
+    /**
+     * Untrack all buffers in a C2FrameData object.
+     *
+     * Calling unregisterFrameData(listener, input) will unregister and remove
+     * pending notifications for all triples (l, fi, bufferIndex) such that
+     * l = listener and fi = input.ordinal.frameIndex.
+     *
+     * This should be called from onWorkDone() and flush().
+     *
+     * \param listener Previously registered listener.
+     * \param input Previously registered frame data.
+     */
+    static void unregisterFrameData(
+            const wp<IComponentListener>& listener,
+            const C2FrameData& input);
+
+    /**
+     * Untrack all buffers associated to a given listener.
+     *
+     * Calling unregisterFrameData(listener) will unregister and remove
+     * pending notifications for all triples (l, frameIndex, bufferIndex) such
+     * that l = listener.
+     *
+     * This should be called when the component cleans up all input buffers,
+     * i.e., when reset(), release(), stop() or ~Component() is called.
+     *
+     * \param listener Previously registered listener.
+     */
+    static void unregisterFrameData(
+            const wp<IComponentListener>& listener);
+
+    /**
+     * Set the notification interval.
+     *
+     * \param notificationIntervalNs New notification interval, in nanoseconds.
+     */
+    static void setNotificationInterval(nsecs_t notificationIntervalNs);
+
+private:
+    void _registerFrameData(
+            const sp<IComponentListener>& listener,
+            const C2FrameData& input);
+    void _unregisterFrameData(
+            const wp<IComponentListener>& listener,
+            const C2FrameData& input);
+    void _unregisterFrameData(
+            const wp<IComponentListener>& listener);
+    void _setNotificationInterval(nsecs_t notificationIntervalNs);
+
+    // The callback function tied to C2Buffer objects.
+    //
+    // Note: This function assumes that sInstance is the only instance of this
+    //       class.
+    static void onBufferDestroyed(const C2Buffer* buf, void* arg);
+    void _onBufferDestroyed(const C2Buffer* buf, void* arg);
+
+    // Persistent data to be passed as "arg" in onBufferDestroyed().
+    // This is essentially the triple (listener, frameIndex, bufferIndex) plus a
+    // weak pointer to the C2Buffer object.
+    //
+    // Note that the "key" is bufferIndex according to operator<(). This is
+    // designed to work with TrackedBuffersMap defined below.
+    struct TrackedBuffer {
+        wp<IComponentListener> listener;
+        uint64_t frameIndex;
+        size_t bufferIndex;
+        std::weak_ptr<C2Buffer> buffer;
+        TrackedBuffer(const wp<IComponentListener>& listener,
+                      uint64_t frameIndex,
+                      size_t bufferIndex,
+                      const std::shared_ptr<C2Buffer>& buffer)
+              : listener(listener),
+                frameIndex(frameIndex),
+                bufferIndex(bufferIndex),
+                buffer(buffer) {}
+    };
+
+    // Map: listener -> frameIndex -> set<TrackedBuffer*>.
+    // Essentially, this is used to store triples (listener, frameIndex,
+    // bufferIndex) that's searchable by listener and (listener, frameIndex).
+    // However, the value of the innermost map is TrackedBuffer, which also
+    // contains an extra copy of listener and frameIndex. This is needed
+    // because onBufferDestroyed() needs to know listener and frameIndex too.
+    typedef std::map<wp<IComponentListener>,
+                     std::map<uint64_t,
+                              std::set<TrackedBuffer*>>> TrackedBuffersMap;
+
+    // Storage for pending (unsent) death notifications for one listener.
+    // Each pair in member named "indices" are (frameIndex, bufferIndex) from
+    // the (listener, frameIndex, bufferIndex) triple.
+    struct DeathNotifications {
+
+        // The number of pending notifications for this listener.
+        // count may be 0, in which case the DeathNotifications object will
+        // remain valid for only a small period (specified
+        // nanoseconds).
+        size_t count;
+
+        // The timestamp of the most recent callback on this listener. This is
+        // used to guarantee that callbacks do not occur too frequently, and
+        // also to trigger expiration of a DeathNotifications object that has
+        // count = 0.
+        nsecs_t lastSentNs;
+
+        // Map: frameIndex -> vector of bufferIndices
+        // This is essentially a collection of (framdeIndex, bufferIndex).
+        std::map<uint64_t, std::vector<size_t>> indices;
+
+        DeathNotifications(
+                nsecs_t notificationIntervalNs = kDefaultNotificationIntervalNs)
+              : count(0),
+                lastSentNs(systemTime() - notificationIntervalNs),
+                indices() {}
+    };
+
+    // The minimum time period between IPC calls to notify the client about the
+    // destruction of input buffers.
+    std::atomic<nsecs_t> mNotificationIntervalNs{kDefaultNotificationIntervalNs};
+
+    // Mutex for the management of all input buffers.
+    std::mutex mMutex;
+
+    // Cache for all TrackedBuffers.
+    //
+    // Whenever registerOnDestroyNotify() is called, an argument of type
+    // TrackedBuffer is created and stored into this cache.
+    // Whenever unregisterOnDestroyNotify() or onBufferDestroyed() is called,
+    // the TrackedBuffer is removed from this cache.
+    //
+    // mTrackedBuffersMap stores references to TrackedBuffers inside this cache.
+    std::set<TrackedBuffer*> mTrackedBufferCache;
+
+    // Tracked input buffers.
+    TrackedBuffersMap mTrackedBuffersMap;
+
+    // Death notifications to be sent.
+    //
+    // A DeathNotifications object is associated to each listener. An entry in
+    // this map will be removed if its associated DeathNotifications has count =
+    // 0 and lastSentNs < systemTime() - mNotificationIntervalNs.
+    std::map<wp<IComponentListener>, DeathNotifications> mDeathNotifications;
+
+    // Condition variable signaled when an entry is added to mDeathNotifications.
+    std::condition_variable mOnBufferDestroyed;
+
+    // Notify the clients about buffer destructions.
+    // Return false if all destructions have been notified.
+    // Return true and set timeToRetry to the duration to wait for before
+    // retrying if some destructions have not been notified.
+    bool processNotifications(nsecs_t* timeToRetryNs);
+
+    // Main function for the input buffer manager thread.
+    void main();
+
+    // The thread that manages notifications.
+    //
+    // Note: This variable is declared last so its initialization will happen
+    // after all other member variables have been initialized.
+    std::thread mMainThread;
+
+    // Private constructor.
+    InputBufferManager();
+
+    // The only instance of this class.
+    static InputBufferManager& getInstance();
+
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/InputSurface.h b/media/codec2/hal/aidl/include/codec2/aidl/InputSurface.h
new file mode 100644
index 0000000..062dcd9
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/InputSurface.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_INPUTSURFACE_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUTSURFACE_H
+
+#include <codec2/hidl/1.0/ComponentStore.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
+#include <hidl/Status.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+
+#include <util/C2InterfaceHelper.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct InputSurface : public IInputSurface {
+
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer HGraphicBufferProducer;
+
+    typedef ::android::
+            GraphicBufferSource GraphicBufferSource;
+
+    virtual Return<sp<HGraphicBufferProducer>> getGraphicBufferProducer() override;
+
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+    virtual Return<void> connect(
+            const sp<IInputSink>& sink,
+            connect_cb _hidl_cb) override;
+
+    InputSurface(
+            const std::shared_ptr<ParameterCache>& cache,
+            const std::shared_ptr<C2ReflectorHelper>& reflector,
+            const sp<HGraphicBufferProducer>& base,
+            const sp<GraphicBufferSource>& source);
+
+protected:
+
+    class Interface;
+    class ConfigurableIntf;
+
+    std::shared_ptr<ParameterCache> mParameterCache;
+    sp<HGraphicBufferProducer> mProducer;
+    sp<GraphicBufferSource> mSource;
+    std::shared_ptr<Interface> mIntf;
+    sp<CachedConfigurable> mConfigurable;
+
+    virtual ~InputSurface() override = default;
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_INPUTSURFACE_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/InputSurfaceConnection.h b/media/codec2/hal/aidl/include/codec2/aidl/InputSurfaceConnection.h
new file mode 100644
index 0000000..475ce8b
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/InputSurfaceConnection.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/Configurable.h>
+
+#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <android/hardware/media/c2/1.0/IInputSurfaceConnection.h>
+
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::GraphicBufferSource;
+
+// An InputSurfaceConnection connects an InputSurface to a sink, which may be an
+// IInputSink or a local C2Component. This can be specified by choosing the
+// corresponding constructor. The reason for distinguishing these two cases is
+// that when an InputSurfaceConnection lives in the same process as the
+// component that processes the buffers, data parceling is not needed.
+struct InputSurfaceConnection : public IInputSurfaceConnection {
+
+    virtual Return<Status> disconnect() override;
+
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+protected:
+
+    InputSurfaceConnection(
+            const sp<GraphicBufferSource>& source,
+            const std::shared_ptr<C2Component>& comp,
+            const std::shared_ptr<ParameterCache>& cache);
+
+    InputSurfaceConnection(
+            const sp<GraphicBufferSource>& source,
+            const sp<IInputSink>& sink,
+            const std::shared_ptr<ParameterCache>& cache);
+
+    bool init();
+
+    friend struct InputSurface;
+
+    InputSurfaceConnection() = delete;
+    InputSurfaceConnection(const InputSurfaceConnection&) = delete;
+    void operator=(const InputSurfaceConnection&) = delete;
+
+    struct Impl;
+
+    std::mutex mImplMutex;
+    sp<Impl> mImpl;
+    sp<CachedConfigurable> mConfigurable;
+
+    virtual ~InputSurfaceConnection() override;
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
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 b5cb546..b680931 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -25,7 +25,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>
@@ -34,6 +33,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>
@@ -42,9 +43,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>
@@ -86,6 +95,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;
@@ -179,6 +189,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
@@ -606,18 +630,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.";
@@ -686,17 +703,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) {
@@ -721,17 +731,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) {
@@ -757,17 +760,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 "
@@ -923,14 +919,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 {
@@ -940,36 +1041,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 {
@@ -980,13 +1098,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(),
@@ -1001,8 +1147,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(),
@@ -1016,8 +1162,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(),
@@ -1060,15 +1206,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,
@@ -1099,8 +1262,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) {
@@ -1128,7 +1296,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) {
@@ -1164,12 +1354,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;
@@ -1211,80 +1401,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;
 }
 
@@ -1323,14 +1545,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);
 }
 
@@ -1432,8 +1674,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) {
@@ -1519,13 +1760,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 =
@@ -1535,11 +1771,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 =
@@ -1555,14 +1871,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 =
@@ -1578,14 +1894,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 =
@@ -1601,22 +1917,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,
@@ -1641,7 +1989,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.";
@@ -1658,12 +2010,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;
@@ -1679,25 +2040,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.
@@ -1722,7 +2096,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.";
@@ -1737,7 +2116,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;
@@ -1751,7 +2134,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;
@@ -1765,7 +2152,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;
@@ -1779,7 +2170,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;
@@ -1796,11 +2191,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);
@@ -1841,8 +2250,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
@@ -1881,11 +2290,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);
 
@@ -1925,7 +2338,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.";
@@ -1943,8 +2360,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) {
@@ -1967,8 +2388,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) {
@@ -1988,7 +2413,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;
@@ -2002,6 +2431,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) {
@@ -2022,12 +2457,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 6fa19b0..0c7dd77 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/codec2/vndk/internal/C2BlockInternal.h b/media/codec2/vndk/internal/C2BlockInternal.h
index 1eefd87..81cdb43 100644
--- a/media/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/codec2/vndk/internal/C2BlockInternal.h
@@ -17,10 +17,14 @@
 #ifndef ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
 #define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
 
-#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
-
 #include <C2Buffer.h>
 
+#include <utils/RefBase.h>
+
+namespace android::hardware::graphics::bufferqueue::V2_0 {
+struct IGraphicBufferProducer;
+}
+
 // Note: HIDL-BufferPool and AIDL-BufferPool are not compatible
 namespace android::hardware::media::bufferpool {
 
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 91599e7..10a1da7 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 41a322a..b511372 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",
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 3d5c1d2..6f19a7a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -618,13 +618,15 @@
     }
     // Convert Sink name to port pointer
     sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
-    if (sink == NULL && !mIgnoreVendorExtensions) {
-        ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
-        return BAD_VALUE;
-    } else if (sink == NULL) {
-        ALOGW("Skipping route to sink \"%s\" as it likely has vendor extension type",
-                sinkAttr.c_str());
-        return NO_INIT;
+    if (sink == NULL) {
+        if (!mIgnoreVendorExtensions) {
+            ALOGE("%s: no sink found with name \"%s\"", __func__, sinkAttr.c_str());
+            return BAD_VALUE;
+        } else {
+            ALOGW("%s: skipping route to sink \"%s\" as it likely has vendor extension type",
+                  __func__, sinkAttr.c_str());
+            return NO_INIT;
+        }
     }
     route->setSink(sink);
 
@@ -641,12 +643,14 @@
     while (devTag != NULL) {
         if (strlen(devTag) != 0) {
             sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
-            if (source == NULL && !mIgnoreVendorExtensions) {
-                ALOGE("%s: no source found with name=%s", __func__, devTag);
-                return BAD_VALUE;
-            } else if (source == NULL) {
-                ALOGW("Skipping route source \"%s\" as it likely has vendor extension type",
-                        devTag);
+            if (source == NULL) {
+                if (!mIgnoreVendorExtensions) {
+                    ALOGE("%s: no source found with name \"%s\"", __func__, devTag);
+                    return BAD_VALUE;
+                } else {
+                    ALOGW("%s: skipping route source \"%s\" as it likely has vendor extension type",
+                          __func__, devTag);
+                }
             } else {
                 sources.add(source);
             }
@@ -728,10 +732,16 @@
                         sp<DeviceDescriptor> device = module->getDeclaredDevices().
                                 getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
                                                         attachedDevice.get())));
-                        if (device == nullptr && mIgnoreVendorExtensions) {
-                            ALOGW("Skipped attached device \"%s\" because it likely uses a vendor"
-                                    "extension type",
-                                    reinterpret_cast<const char*>(attachedDevice.get()));
+                        if (device == NULL) {
+                            if (mIgnoreVendorExtensions) {
+                                ALOGW("%s: skipped attached device \"%s\" because it likely uses a "
+                                      "vendor extension type",
+                                      __func__,
+                                      reinterpret_cast<const char*>(attachedDevice.get()));
+                            } else {
+                                ALOGE("%s: got null device in %s, \"%s\"", __func__, child->name,
+                                      reinterpret_cast<const char*>(attachedDevice.get()));
+                            }
                             continue;
                         }
                         ctx->addDevice(device);