Initial commit for the Codec2.0 HAL

Test: make cts -j123 && cts-tradefed run cts-dev -m \
CtsMediaTestCases --compatibility:module-arg \
CtsMediaTestCases:include-annotation:\
android.platform.test.annotations.RequiresDevice

Bug: 112362730

Change-Id: I26b99ba4b83c527c1caed7492d6d57b7056361e3
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index c5ad6a0..d0296a5 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -8,8 +8,10 @@
 
     srcs: [
         "Component.cpp",
+        "ComponentInterface.cpp",
         "ComponentStore.cpp",
         "Configurable.cpp",
+        "InputBufferManager.cpp",
         "InputSurface.cpp",
         "InputSurfaceConnection.cpp",
         "types.cpp",
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index 5ae1972..0473b57 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,11 +18,11 @@
 #define LOG_TAG "Codec2-Component"
 #include <android-base/logging.h>
 
-#include <C2PlatformSupport.h>
 #include <codec2/hidl/1.0/Component.h>
 #include <codec2/hidl/1.0/ComponentStore.h>
-#include <codec2/hidl/1.0/types.h>
+#include <codec2/hidl/1.0/InputBufferManager.h>
 
+#include <android/hardware/media/c2/1.0/IInputSink.h>
 #include <hidl/HidlBinderSupport.h>
 #include <utils/Timers.h>
 
@@ -42,281 +42,6 @@
 
 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()),
-        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 {
-        ALOGV("config");
-        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 {
-        ALOGV("query");
-        return mIntf->query_vb({}, indices, mayBlock, params);
-    }
-
-    virtual c2_status_t querySupportedParams(
-            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
-            ) const override {
-        ALOGV("querySupportedParams");
-        return mIntf->querySupportedParams_nb(params);
-    }
-
-    virtual c2_status_t querySupportedValues(
-            std::vector<C2FieldSupportedValuesQuery>& fields,
-            c2_blocking_t mayBlock) const override {
-        ALOGV("querySupportedValues");
-        return mIntf->querySupportedValues_vb(fields, mayBlock);
-    }
-
-protected:
-    std::shared_ptr<C2ComponentInterface> mIntf;
-};
-
-} // unnamed namespace
-
-// 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. (In fact, this class would work for listeners in the same process
-// too, but the optimization discussed below will not be beneficial.)
-//
-// 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 onFramesRendered() function
-//   will be called after the associated buffer dies. The argument of
-//   onFramesRendered() is a list of RenderedFrame objects, each of which has
-//   the following members:
-//
-//     uint64_t bufferQueueId
-//     int32_t  slotId
-//     int64_t  timestampNs
-//
-// When a tracked buffer associated to the triple (listener, frameIndex,
-// bufferIndex) goes out of scope, listener->onFramesRendered() will be called
-// with a RenderedFrame object whose members are set as follows:
-//
-//     bufferQueueId = frameIndex
-//     slotId        = ~bufferIndex
-//     timestampNs   = systemTime() at the time of notification
-//
-// The reason for the bitwise negation of bufferIndex is that onFramesRendered()
-// may be used for a different purpose when slotId is non-negative (which is a
-// more general use case).
-//
-// IPC Optimization
-// ----------------
-//
-// Since onFramesRendered() generally is an IPC call, InputBufferManager tries
-// not to call it too often. There is a mechanism to guarantee that any two
-// calls to the same listener are at least kNotificationPeriodNs nanoseconds
-// apart.
-//
-struct InputBufferManager {
-    // The minimum time period between IPC calls to notify the client about the
-    // destruction of input buffers.
-    static constexpr nsecs_t kNotificationPeriodNs = 1000000;
-
-    // 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 (, 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().
-    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().
-    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.
-    static void unregisterFrameData(
-            const wp<IComponentListener>& listener);
-
-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);
-
-    // 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);
-
-    // Comparison operator for weak pointers.
-    struct CompareWeakComponentListener {
-        constexpr bool operator()(
-                const wp<IComponentListener>& x,
-                const wp<IComponentListener>& y) const {
-            return x.get_refs() < y.get_refs();
-        }
-    };
-
-    // 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) {}
-        TrackedBuffer(const TrackedBuffer&) = default;
-        bool operator<(const TrackedBuffer& other) const {
-            return bufferIndex < other.bufferIndex;
-        }
-    };
-
-    // 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>>,
-                     CompareWeakComponentListener> 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 (kNotificationPeriodNs
-        // 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()
-              : count(0),
-                lastSentNs(systemTime() - kNotificationPeriodNs),
-                indices() {}
-    };
-
-    // Mutex for the management of all input buffers.
-    std::mutex mMutex;
-
-    // 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() - kNotificationPeriodNs.
-    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();
-
-};
-
-// ComponentInterface
-ComponentInterface::ComponentInterface(
-        const std::shared_ptr<C2ComponentInterface>& intf,
-        const sp<ComponentStore>& store) :
-    Configurable(new CachedConfigurable(std::make_unique<CompIntf>(intf))),
-    mInterface(intf) {
-    mInit = init(store.get());
-}
-
-c2_status_t ComponentInterface::status() const {
-    return mInit;
-}
-
 // ComponentListener wrapper
 struct Component::Listener : public C2Component::Listener {
 
@@ -328,12 +53,12 @@
     virtual void onError_nb(
             std::weak_ptr<C2Component> /* c2component */,
             uint32_t errorCode) override {
-        ALOGV("onError");
         sp<IComponentListener> listener = mListener.promote();
         if (listener) {
             Return<void> transStatus = listener->onError(Status::OK, errorCode);
             if (!transStatus.isOk()) {
-                ALOGE("onError -- transaction failed.");
+                LOG(ERROR) << "Component::Listener::onError_nb -- "
+                           << "transaction failed.";
             }
         }
     }
@@ -342,7 +67,6 @@
             std::weak_ptr<C2Component> /* c2component */,
             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
             ) override {
-        ALOGV("onTripped");
         sp<IComponentListener> listener = mListener.promote();
         if (listener) {
             hidl_vec<SettingResult> settingResults(c2settingResult.size());
@@ -350,8 +74,7 @@
             for (const std::shared_ptr<C2SettingResult> &c2result :
                     c2settingResult) {
                 if (c2result) {
-                    if (objcpy(&settingResults[ix++], *c2result) !=
-                            Status::OK) {
+                    if (!objcpy(&settingResults[ix++], *c2result)) {
                         break;
                     }
                 }
@@ -359,7 +82,8 @@
             settingResults.resize(ix);
             Return<void> transStatus = listener->onTripped(settingResults);
             if (!transStatus.isOk()) {
-                ALOGE("onTripped -- transaction failed.");
+                LOG(ERROR) << "Component::Listener::onTripped_nb -- "
+                           << "transaction failed.";
             }
         }
     }
@@ -367,7 +91,6 @@
     virtual void onWorkDone_nb(
             std::weak_ptr<C2Component> /* c2component */,
             std::list<std::unique_ptr<C2Work>> c2workItems) override {
-        ALOGV("onWorkDone");
         for (const std::unique_ptr<C2Work>& work : c2workItems) {
             if (work) {
                 if (work->worklets.empty()
@@ -385,15 +108,16 @@
             WorkBundle workBundle;
 
             sp<Component> strongComponent = mComponent.promote();
-            if (objcpy(&workBundle, c2workItems, strongComponent ?
-                    &strongComponent->mBufferPoolSender : nullptr)
-                    != Status::OK) {
-                ALOGE("onWorkDone() received corrupted work items.");
+            if (!objcpy(&workBundle, c2workItems, strongComponent ?
+                    &strongComponent->mBufferPoolSender : nullptr)) {
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "received corrupted work items.";
                 return;
             }
             Return<void> transStatus = listener->onWorkDone(workBundle);
             if (!transStatus.isOk()) {
-                ALOGE("onWorkDone -- transaction failed.");
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "transaction failed.";
                 return;
             }
             yieldBufferQueueBlocks(c2workItems, true);
@@ -405,23 +129,86 @@
     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) :
-    Configurable(new CachedConfigurable(
-            std::make_unique<CompIntf>(component->intf()))),
-    mComponent(component),
-    mInterface(component->intf()),
-    mListener(listener),
-    mStore(store),
-    mBufferPoolSender(clientPoolManager) {
+        IClientManager>& clientPoolManager)
+      : mComponent{component},
+        mInterface{new ComponentInterface(component->intf(), store.get())},
+        mListener{listener},
+        mStore{store},
+        mBufferPoolSender{clientPoolManager} {
     // Retrieve supported parameters from store
     // TODO: We could cache this per component/interface type
-    mInit = init(store.get());
+    mInit = mInterface->status();
 }
 
 c2_status_t Component::status() const {
@@ -430,11 +217,9 @@
 
 // Methods from ::android::hardware::media::c2::V1_0::IComponent
 Return<Status> Component::queue(const WorkBundle& workBundle) {
-    ALOGV("queue -- converting input");
     std::list<std::unique_ptr<C2Work>> c2works;
 
-    if (objcpy(&c2works, workBundle) != C2_OK) {
-        ALOGV("queue -- corrupted");
+    if (!objcpy(&c2works, workBundle)) {
         return Status::CORRUPTED;
     }
 
@@ -446,13 +231,11 @@
         }
     }
 
-    ALOGV("queue -- calling");
     return static_cast<Status>(mComponent->queue_nb(&c2works));
 }
 
 Return<void> Component::flush(flush_cb _hidl_cb) {
     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
-    ALOGV("flush -- calling");
     c2_status_t c2res = mComponent->flush_sm(
             C2Component::FLUSH_COMPONENT,
             &c2flushedWorks);
@@ -473,8 +256,9 @@
     WorkBundle flushedWorkBundle;
     Status res = static_cast<Status>(c2res);
     if (c2res == C2_OK) {
-        ALOGV("flush -- converting output");
-        res = objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender);
+        if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+            res = Status::CORRUPTED;
+        }
     }
     _hidl_cb(res, flushedWorkBundle);
     yieldBufferQueueBlocks(c2flushedWorks, true);
@@ -482,7 +266,6 @@
 }
 
 Return<Status> Component::drain(bool withEos) {
-    ALOGV("drain");
     return static_cast<Status>(mComponent->drain_nb(withEos ?
             C2Component::DRAIN_COMPONENT_WITH_EOS :
             C2Component::DRAIN_COMPONENT_NO_EOS));
@@ -512,14 +295,39 @@
     return Status::OK;
 }
 
-Return<Status> Component::connectToOmxInputSurface(
+Return<void> Component::connectToInputSurface(
+        const sp<IInputSurface>& inputSurface,
+        connectToInputSurface_cb _hidl_cb) {
+    sp<Sink> sink;
+    {
+        std::lock_guard<std::mutex> lock(mSinkMutex);
+        if (!mSink) {
+            mSink = new Sink(shared_from_this());
+        }
+        sink = mSink;
+    }
+    Status status;
+    sp<IInputSurfaceConnection> connection;
+    auto transStatus = inputSurface->connect(sink,
+            [&status, &connection](Status s,
+                                   const sp<IInputSurfaceConnection>& c) {
+                status = s;
+                connection = c;
+            }
+        );
+    _hidl_cb(status, connection);
+    return Void();
+}
+
+Return<void> Component::connectToOmxInputSurface(
         const sp<HGraphicBufferProducer>& producer,
         const sp<::android::hardware::media::omx::V1_0::
-        IGraphicBufferSource>& source) {
-    // TODO implement
+        IGraphicBufferSource>& source,
+        connectToOmxInputSurface_cb _hidl_cb) {
     (void)producer;
     (void)source;
-    return Status::OMITTED;
+    (void)_hidl_cb;
+    return Void();
 }
 
 Return<Status> Component::disconnectFromInputSurface() {
@@ -530,11 +338,12 @@
 namespace /* unnamed */ {
 
 struct BlockPoolIntf : public ConfigurableC2Intf {
-    BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool) :
-        ConfigurableC2Intf("C2BlockPool:" +
-                           (pool ? std::to_string(pool->getLocalId()) :
-                           "null")),
-        mPool(pool) {
+    BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
+          : ConfigurableC2Intf{
+                "C2BlockPool:" +
+                    (pool ? std::to_string(pool->getLocalId()) : "null"),
+                0},
+            mPool{pool} {
     }
 
     virtual c2_status_t config(
@@ -613,18 +422,15 @@
 }
 
 Return<Status> Component::start() {
-    ALOGV("start");
     return static_cast<Status>(mComponent->start());
 }
 
 Return<Status> Component::stop() {
-    ALOGV("stop");
     InputBufferManager::unregisterFrameData(mListener);
     return static_cast<Status>(mComponent->stop());
 }
 
 Return<Status> Component::reset() {
-    ALOGV("reset");
     Status status = static_cast<Status>(mComponent->reset());
     {
         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
@@ -635,7 +441,6 @@
 }
 
 Return<Status> Component::release() {
-    ALOGV("release");
     Status status = static_cast<Status>(mComponent->release());
     {
         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
@@ -645,8 +450,13 @@
     return status;
 }
 
-void Component::setLocalId(const Component::LocalId& localId) {
-    mLocalId = localId;
+Return<sp<IComponentInterface>> Component::getInterface() {
+    return sp<IComponentInterface>(mInterface);
+}
+
+std::shared_ptr<C2Component> Component::findLocalComponent(
+        const sp<IInputSink>& sink) {
+    return Component::Sink::findLocalComponent(sink);
 }
 
 void Component::initListener(const sp<Component>& self) {
@@ -660,395 +470,7 @@
 
 Component::~Component() {
     InputBufferManager::unregisterFrameData(mListener);
-    mStore->reportComponentDeath(mLocalId);
-}
-
-Component::InterfaceKey::InterfaceKey(const sp<IComponent>& component) {
-    isRemote = component->isRemote();
-    if (isRemote) {
-        remote = ::android::hardware::toBinder(component);
-    } else {
-        local = component;
-    }
-}
-
-// InputBufferManager implementation
-
-constexpr nsecs_t InputBufferManager::kNotificationPeriodNs;
-
-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::_registerFrameData(
-        const sp<IComponentListener>& listener,
-        const C2FrameData& input) {
-    uint64_t frameIndex = input.ordinal.frameIndex.peeku();
-    ALOGV("InputBufferManager::_registerFrameData called "
-          "(listener @ %p, frameIndex = %llu)",
-          listener.get(),
-          static_cast<long long unsigned>(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]) {
-            ALOGV("InputBufferManager::_registerFrameData: "
-                  "Input buffer at index %zu is null", i);
-            continue;
-        }
-        const TrackedBuffer &bufferId =
-                *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
-                first;
-
-        c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
-                onBufferDestroyed,
-                const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
-        if (status != C2_OK) {
-            ALOGD("InputBufferManager: registerOnDestroyNotify failed "
-                  "(listener @ %p, frameIndex = %llu, bufferIndex = %zu) "
-                  "=> %s (%d)",
-                  listener.get(),
-                  static_cast<unsigned long long>(frameIndex),
-                  i,
-                  asString(status), static_cast<int>(status));
-        }
-    }
-
-    mDeathNotifications.emplace(listener, DeathNotifications());
-}
-
-// 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();
-    ALOGV("InputBufferManager::_unregisterFrameData called "
-          "(listener @ %p, frameIndex = %llu)",
-          listener.unsafe_get(),
-          static_cast<long long unsigned>(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 (const TrackedBuffer& bufferId : bufferIds) {
-                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
-                if (buffer) {
-                    c2_status_t status = buffer->unregisterOnDestroyNotify(
-                            onBufferDestroyed,
-                            const_cast<void*>(
-                            reinterpret_cast<const void*>(&bufferId)));
-                    if (status != C2_OK) {
-                        ALOGD("InputBufferManager: "
-                              "unregisterOnDestroyNotify failed "
-                              "(listener @ %p, "
-                              "frameIndex = %llu, "
-                              "bufferIndex = %zu) "
-                              "=> %s (%d)",
-                              bufferId.listener.unsafe_get(),
-                              static_cast<unsigned long long>(
-                                  bufferId.frameIndex),
-                              bufferId.bufferIndex,
-                              asString(status), static_cast<int>(status));
-                    }
-                }
-            }
-
-            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) {
-    ALOGV("InputBufferManager::_unregisterFrameData called (listener @ %p)",
-            listener.unsafe_get());
-    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 (const TrackedBuffer& bufferId : bufferIds) {
-                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
-                if (buffer) {
-                    c2_status_t status = buffer->unregisterOnDestroyNotify(
-                            onBufferDestroyed,
-                            const_cast<void*>(
-                            reinterpret_cast<const void*>(&bufferId)));
-                    if (status != C2_OK) {
-                        ALOGD("InputBufferManager: "
-                              "unregisterOnDestroyNotify failed "
-                              "(listener @ %p, "
-                              "frameIndex = %llu, "
-                              "bufferIndex = %zu) "
-                              "=> %s (%d)",
-                              bufferId.listener.unsafe_get(),
-                              static_cast<unsigned long long>(bufferId.frameIndex),
-                              bufferId.bufferIndex,
-                              asString(status), static_cast<int>(status));
-                    }
-                }
-            }
-        }
-        mTrackedBuffersMap.erase(findListener);
-    }
-
-    mDeathNotifications.erase(listener);
-}
-
-// 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) {
-        ALOGW("InputBufferManager::_onBufferDestroyed called "
-              "with null argument(s) (buf @ %p, arg @ %p)",
-              buf, arg);
-        return;
-    }
-    TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
-    ALOGV("InputBufferManager::_onBufferDestroyed called "
-          "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-          id.listener.unsafe_get(),
-          static_cast<unsigned long long>(id.frameIndex),
-          id.bufferIndex);
-
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    auto findListener = mTrackedBuffersMap.find(id.listener);
-    if (findListener == mTrackedBuffersMap.end()) {
-        ALOGD("InputBufferManager::_onBufferDestroyed received "
-              "invalid listener "
-              "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-              id.listener.unsafe_get(),
-              static_cast<unsigned long long>(id.frameIndex),
-              id.bufferIndex);
-        return;
-    }
-
-    std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
-            = findListener->second;
-    auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
-    if (findFrameIndex == frameIndex2BufferIds.end()) {
-        ALOGD("InputBufferManager::_onBufferDestroyed received "
-              "invalid frame index "
-              "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-              id.listener.unsafe_get(),
-              static_cast<unsigned long long>(id.frameIndex),
-              id.bufferIndex);
-        return;
-    }
-
-    std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
-    auto findBufferId = bufferIds.find(id);
-    if (findBufferId == bufferIds.end()) {
-        ALOGD("InputBufferManager::_onBufferDestroyed received "
-              "invalid buffer index: "
-              "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-              id.listener.unsafe_get(),
-              static_cast<unsigned long long>(id.frameIndex),
-              id.bufferIndex);
-    }
-
-    bufferIds.erase(findBufferId);
-    if (bufferIds.empty()) {
-        frameIndex2BufferIds.erase(findFrameIndex);
-        if (frameIndex2BufferIds.empty()) {
-            mTrackedBuffersMap.erase(findListener);
-        }
-    }
-
-    DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
-    deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
-    ++deathNotifications.count;
-    mOnBufferDestroyed.notify_one();
-}
-
-// 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::RenderedFrame> renderedFrames;
-        Notification(const sp<IComponentListener>& l, size_t s)
-              : listener(l), renderedFrames(s) {}
-    };
-    std::list<Notification> notifications;
-
-    bool retry = false;
-    {
-        std::lock_guard<std::mutex> lock(mMutex);
-        *timeToRetryNs = kNotificationPeriodNs;
-        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 < kNotificationPeriodNs) {
-                retry = true;
-                *timeToRetryNs = std::min(*timeToRetryNs,
-                        kNotificationPeriodNs - timeSinceLastNotifiedNs);
-                ALOGV("InputBufferManager: Notifications for "
-                      "listener @ %p will be postponed.",
-                      listener.get());
-                ++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::RenderedFrame>& renderedFrames =
-                    notifications.back().renderedFrames;
-            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::RenderedFrame &renderedFrame
-                            = renderedFrames[i++];
-                    renderedFrame.slotId = ~bufferIndex;
-                    renderedFrame.bufferQueueId = frameIndex;
-                    renderedFrame.timestampNs = timeNowNs;
-                    ALOGV("InputBufferManager: "
-                          "Sending death notification (listener @ %p, "
-                          "frameIndex = %llu, bufferIndex = %zu)",
-                          listener.get(),
-                          static_cast<long long unsigned>(frameIndex),
-                          bufferIndex);
-                }
-            }
-
-            // 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
-            // kNotificationPeriodNs nanoseconds has passed.
-            retry = true;
-            deathNotifications.indices.clear();
-            deathNotifications.count = 0;
-            deathNotifications.lastSentNs = timeNowNs;
-            ++it;
-        }
-    }
-
-    // Call onFramesRendered outside the lock to avoid deadlock.
-    for (const Notification& notification : notifications) {
-        if (!notification.listener->onFramesRendered(
-                notification.renderedFrames).isOk()) {
-            // This may trigger if the client has died.
-            ALOGD("InputBufferManager: onFramesRendered transaction failed "
-                  "(listener @ %p)",
-                  notification.listener.get());
-        }
-    }
-    if (retry) {
-        ALOGV("InputBufferManager: Pending death notifications"
-              "will be sent in %lldns.",
-              static_cast<long long>(*timeToRetryNs));
-    }
-    return retry;
-}
-
-void InputBufferManager::main() {
-    ALOGV("InputBufferManager: Starting main thread");
-    nsecs_t timeToRetryNs;
-    while (true) {
-        std::unique_lock<std::mutex> lock(mMutex);
-        while (mDeathNotifications.empty()) {
-            ALOGV("InputBufferManager: Waiting for buffer deaths");
-            mOnBufferDestroyed.wait(lock);
-        }
-        lock.unlock();
-        ALOGV("InputBufferManager: Sending buffer death notifications");
-        while (processNotifications(&timeToRetryNs)) {
-            std::this_thread::sleep_for(
-                    std::chrono::nanoseconds(timeToRetryNs));
-            ALOGV("InputBufferManager: Sending pending death notifications");
-        }
-        ALOGV("InputBufferManager: No pending death notifications");
-    }
-}
-
-InputBufferManager::InputBufferManager()
-      : mMainThread(&InputBufferManager::main, this) {
-}
-
-InputBufferManager& InputBufferManager::getInstance() {
-    static InputBufferManager instance{};
-    return instance;
+    mStore->reportComponentDeath(this);
 }
 
 }  // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
new file mode 100644
index 0000000..39e5357
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/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,
+        ComponentStore* store)
+      : mInterface{intf},
+        mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
+    mInit = mConfigurable->init(store);
+}
+
+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/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index 9c05014..bb5faa5 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,37 +16,25 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-ComponentStore"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/ComponentStore.h>
 #include <codec2/hidl/1.0/InputSurface.h>
-#include <codec2/hidl/1.0/Component.h>
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
 #include <codec2/hidl/1.0/types.h>
 
+#include <android-base/file.h>
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <utils/Errors.h>
 
 #include <C2PlatformSupport.h>
 #include <util/C2InterfaceHelper.h>
 
-#include <utils/Errors.h>
-
-#include <android-base/file.h>
-
-#ifdef LOG
-#undef LOG
-#endif
-
-#ifdef PLOG
-#undef PLOG
-#endif
-
-#include <android-base/logging.h>
-
+#include <chrono>
+#include <ctime>
+#include <iomanip>
 #include <ostream>
 #include <sstream>
-#include <iomanip>
 
 namespace android {
 namespace hardware {
@@ -62,12 +50,12 @@
 namespace /* unnamed */ {
 
 struct StoreIntf : public ConfigurableC2Intf {
-    StoreIntf(const std::shared_ptr<C2ComponentStore>& store) :
-        ConfigurableC2Intf(store ? store->getName() : ""),
-        mStore(store) {
+    StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
+          : ConfigurableC2Intf{store ? store->getName() : "", 0},
+            mStore{store} {
     }
 
-    c2_status_t config(
+    virtual c2_status_t config(
             const std::vector<C2Param*> &params,
             c2_blocking_t mayBlock,
             std::vector<std::unique_ptr<C2SettingResult>> *const failures
@@ -80,7 +68,7 @@
         return mStore->config_sm(params, failures);
     }
 
-    c2_status_t query(
+    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 {
@@ -92,13 +80,13 @@
         return mStore->query_sm({}, indices, params);
     }
 
-    c2_status_t querySupportedParams(
+    virtual c2_status_t querySupportedParams(
             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
             ) const override {
         return mStore->querySupportedParams_nb(params);
     }
 
-    c2_status_t querySupportedValues(
+    virtual c2_status_t querySupportedValues(
             std::vector<C2FieldSupportedValuesQuery> &fields,
             c2_blocking_t mayBlock) const override {
         // Assume all params are blocking
@@ -115,9 +103,9 @@
 
 } // unnamed namespace
 
-ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store) :
-    Configurable(new CachedConfigurable(std::make_unique<StoreIntf>(store))),
-    mStore(store) {
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
+      : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+        mStore{store} {
 
     std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
     SetPreferredCodec2ComponentStore(store);
@@ -126,7 +114,11 @@
     mParamReflector = mStore->getParamReflector();
 
     // Retrieve supported parameters from store
-    mInit = init(this);
+    mInit = mConfigurable->init(this);
+}
+
+c2_status_t ComponentStore::status() const {
+    return mInit;
 }
 
 c2_status_t ComponentStore::validateSupportedParams(
@@ -172,19 +164,15 @@
         component = new Component(c2component, listener, this, pool);
         if (!component) {
             status = Status::CORRUPTED;
-        } else if (component->status() != C2_OK) {
-            status = static_cast<Status>(component->status());
         } else {
-            component->initListener(component);
+            reportComponentBirth(component.get());
             if (component->status() != C2_OK) {
                 status = static_cast<Status>(component->status());
             } else {
-                std::lock_guard<std::mutex> lock(mComponentRosterMutex);
-                component->setLocalId(
-                        mComponentRoster.emplace(
-                            Component::InterfaceKey(component),
-                            c2component)
-                        .first);
+                component->initListener(component);
+                if (component->status() != C2_OK) {
+                    status = static_cast<Status>(component->status());
+                }
             }
         }
     }
@@ -202,7 +190,7 @@
         onInterfaceLoaded(c2interface);
         interface = new ComponentInterface(c2interface, this);
     }
-    _hidl_cb((Status)res, interface);
+    _hidl_cb(static_cast<Status>(res), interface);
     return Void();
 }
 
@@ -213,27 +201,35 @@
     size_t ix = 0;
     for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
         if (c2trait) {
-            objcpy(&traits[ix++], *c2trait);
+            if (objcpy(&traits[ix], *c2trait)) {
+                ++ix;
+            } else {
+                break;
+            }
         }
     }
     traits.resize(ix);
-    _hidl_cb(traits);
+    _hidl_cb(Status::OK, traits);
     return Void();
 }
 
-Return<sp<IInputSurface>> ComponentStore::createInputSurface() {
+Return<void> ComponentStore::createInputSurface(createInputSurface_cb _hidl_cb) {
     sp<GraphicBufferSource> source = new GraphicBufferSource();
     if (source->initCheck() != OK) {
-        return nullptr;
+        _hidl_cb(Status::CORRUPTED, nullptr);
+        return Void();
     }
     typedef ::android::hardware::graphics::bufferqueue::V1_0::
             IGraphicBufferProducer HGbp;
     typedef ::android::TWGraphicBufferProducer<HGbp> B2HGbp;
-    return new InputSurface(
+    sp<InputSurface> inputSurface = new InputSurface(
             this,
             std::make_shared<C2ReflectorHelper>(),
             new B2HGbp(source->getIGraphicBufferProducer()),
             source);
+    _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
+             inputSurface);
+    return Void();
 }
 
 void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
@@ -265,15 +261,25 @@
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
                     mStructDescriptors.insert({ coreIndex, structDesc });
-                    objcpy(&descriptors[dstIx++], *structDesc);
-                    continue;
+                    if (objcpy(&descriptors[dstIx], *structDesc)) {
+                        ++dstIx;
+                        continue;
+                    }
+                    res = Status::CORRUPTED;
+                    break;
                 }
             }
             res = Status::NOT_FOUND;
         } else if (item->second) {
-            objcpy(&descriptors[dstIx++], *item->second);
+            if (objcpy(&descriptors[dstIx], *item->second)) {
+                ++dstIx;
+                continue;
+            }
+            res = Status::CORRUPTED;
+            break;
         } else {
             res = Status::NO_MEMORY;
+            break;
         }
     }
     descriptors.resize(dstIx);
@@ -292,29 +298,29 @@
     return Status::OMITTED;
 }
 
-void ComponentStore::reportComponentDeath(
-        const Component::LocalId& componentLocalId) {
-    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
-    mComponentRoster.erase(componentLocalId);
+Return<sp<IConfigurable>> ComponentStore::getConfigurable() {
+    return mConfigurable;
 }
 
-std::shared_ptr<C2Component> ComponentStore::findC2Component(
-        const sp<IComponent>& component) const {
+// 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);
-    Component::LocalId it = mComponentRoster.find(
-            Component::InterfaceKey(component));
-    if (it == mComponentRoster.end()) {
-        return std::shared_ptr<C2Component>();
-    }
-    return it->second.lock();
+    mComponentRoster.emplace(component, componentStatus);
 }
 
-// Debug dump
+// 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);
+}
 
-namespace /* unnamed */ {
-
-// Dump component traits
-std::ostream& dump(
+// Dumps component traits.
+std::ostream& ComponentStore::dump(
         std::ostream& out,
         const std::shared_ptr<const C2Component::Traits>& comp) {
 
@@ -334,25 +340,38 @@
     return out;
 }
 
-// Dump component
-std::ostream& dump(
+// Dumps component status.
+std::ostream& ComponentStore::dump(
         std::ostream& out,
-        const std::shared_ptr<C2Component>& comp) {
+        ComponentStatus& compStatus) {
 
     constexpr const char indent[] = "    ";
 
-    std::shared_ptr<C2ComponentInterface> intf = comp->intf();
+    // 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 -- null interface" << std::endl;
+        out << indent << "Unknown component -- null interface" << std::endl;
         return out;
     }
-    out << indent << "name: " << intf->getName() << std::endl;
-    out << indent << "id: " << intf->getId() << std::endl;
+    out << indent << "Name: " << intf->getName() << std::endl;
+    out << indent << "Id: " << intf->getId() << std::endl;
+
     return out;
 }
 
-} // unnamed namespace
-
+// Dumps information when lshal is called.
 Return<void> ComponentStore::debug(
         const hidl_handle& handle,
         const hidl_vec<hidl_string>& /* args */) {
@@ -387,31 +406,16 @@
             }
         }
 
-        // Retrieve the list of active components.
-        std::list<std::shared_ptr<C2Component>> activeComps;
-        {
-            std::lock_guard<std::mutex> lock(mComponentRosterMutex);
-            auto i = mComponentRoster.begin();
-            while (i != mComponentRoster.end()) {
-                std::shared_ptr<C2Component> c2comp = i->second.lock();
-                if (!c2comp) {
-                    auto j = i;
-                    ++i;
-                    mComponentRoster.erase(j);
-                } else {
-                    ++i;
-                    activeComps.emplace_back(c2comp);
-                }
-            }
-        }
-
         // Dump active components.
-        out << indent << "Active components:" << std::endl << std::endl;
-        if (activeComps.size() == 0) {
-            out << indent << indent << "NONE" << std::endl << std::endl;
-        } else {
-            for (const std::shared_ptr<C2Component>& c2comp : activeComps) {
-                dump(out, c2comp) << std::endl;
+        {
+            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;
+                }
             }
         }
 
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index d023ba8..a35b74c 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,11 +16,12 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-Configurable"
-#include <log/log.h>
+#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 {
@@ -33,8 +34,8 @@
 using namespace ::android;
 
 CachedConfigurable::CachedConfigurable(
-        std::unique_ptr<ConfigurableC2Intf>&& intf) :
-    mIntf(std::move(intf)) {
+        std::unique_ptr<ConfigurableC2Intf>&& intf)
+      : mIntf{std::move(intf)} {
 }
 
 c2_status_t CachedConfigurable::init(ComponentStore* store) {
@@ -45,6 +46,10 @@
 }
 
 // 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();
@@ -65,9 +70,10 @@
             &c2heapParams);
 
     hidl_vec<uint8_t> params;
-    createParamsBlob(&params, c2heapParams);
+    if (!createParamsBlob(&params, c2heapParams)) {
+        LOG(WARNING) << "query -- invalid output params.";
+    }
     _hidl_cb(static_cast<Status>(c2res), params);
-
     return Void();
 }
 
@@ -78,7 +84,8 @@
     // 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) != C2_OK) {
+    if (!parseParamsBlob(&c2params, inParamsCopy)) {
+        LOG(WARNING) << "config -- invalid input params.";
         _hidl_cb(Status::CORRUPTED,
                 hidl_vec<SettingResult>(),
                 hidl_vec<uint8_t>());
@@ -95,13 +102,20 @@
         size_t ix = 0;
         for (const std::unique_ptr<C2SettingResult>& c2result : c2failures) {
             if (c2result) {
-                objcpy(&failures[ix++], *c2result);
+                if (objcpy(&failures[ix], *c2result)) {
+                    ++ix;
+                } else {
+                    LOG(DEBUG) << "config -- invalid setting results.";
+                    break;
+                }
             }
         }
         failures.resize(ix);
     }
     hidl_vec<uint8_t> outParams;
-    createParamsBlob(&outParams, c2params);
+    if (!createParamsBlob(&outParams, c2params)) {
+        LOG(DEBUG) << "config -- invalid output params.";
+    }
     _hidl_cb((Status)c2res, failures, outParams);
     return Void();
 }
@@ -117,7 +131,13 @@
     size_t dstIx = 0;
     for (size_t srcIx = request.offset(); srcIx < request.endOffset(); ++srcIx) {
         if (mSupportedParams[srcIx]) {
-            objcpy(&params[dstIx++], *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;
         }
@@ -154,7 +174,14 @@
     {
         size_t ix = 0;
         for (const C2FieldSupportedValuesQuery &result : c2fields) {
-            objcpy(&outFields[ix++], result);
+            if (!objcpy(&outFields[ix], result)) {
+                ++ix;
+            } else {
+                outFields.resize(ix);
+                c2res = C2_CORRUPTED;
+                LOG(WARNING) << "querySupportedValues -- invalid output params.";
+                break;
+            }
         }
     }
     _hidl_cb((Status)c2res, outFields);
diff --git a/media/codec2/hidl/1.0/utils/InputBufferManager.cpp b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
new file mode 100644
index 0000000..a023a05
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
@@ -0,0 +1,461 @@
+/*
+ * 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;
+        }
+        const TrackedBuffer &bufferId =
+                *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
+                first;
+
+        c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
+                onBufferDestroyed,
+                const_cast<void*>(reinterpret_cast<const 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 (const TrackedBuffer& bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+                if (buffer) {
+                    c2_status_t status = buffer->unregisterOnDestroyNotify(
+                            onBufferDestroyed,
+                            const_cast<void*>(
+                            reinterpret_cast<const 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
+                                   << ".";
+                    }
+                }
+            }
+
+            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 (const TrackedBuffer& bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+                if (buffer) {
+                    c2_status_t status = buffer->unregisterOnDestroyNotify(
+                            onBufferDestroyed,
+                            const_cast<void*>(
+                            reinterpret_cast<const 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
+                                   << ".";
+                    }
+                }
+            }
+        }
+        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;
+    }
+    TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
+    LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+                 << "buf @ 0x" << std::hex << buf
+                 << ", arg @ 0x" << std::hex << arg
+                 << std::dec << " -- "
+                 << "listener @ 0x" << std::hex << id.listener.unsafe_get()
+                 << ", frameIndex = " << std::dec << id.frameIndex
+                 << ", bufferIndex = " << id.bufferIndex
+                 << ".";
+
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    auto findListener = mTrackedBuffersMap.find(id.listener);
+    if (findListener == mTrackedBuffersMap.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid listener: "
+                   << "listener @ 0x" << std::hex << id.listener.unsafe_get()
+                   << " (frameIndex = " << std::dec << id.frameIndex
+                   << ", bufferIndex = " << id.bufferIndex
+                   << ").";
+        return;
+    }
+
+    std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
+            = findListener->second;
+    auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
+    if (findFrameIndex == frameIndex2BufferIds.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid frame index: "
+                   << "frameIndex = " << id.frameIndex
+                   << " (listener @ 0x" << std::hex << id.listener.unsafe_get()
+                   << ", bufferIndex = " << std::dec << id.bufferIndex
+                   << ").";
+        return;
+    }
+
+    std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
+    auto findBufferId = bufferIds.find(id);
+    if (findBufferId == bufferIds.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid buffer index: "
+                   << "bufferIndex = " << id.bufferIndex
+                   << " (frameIndex = " << id.frameIndex
+                   << ", listener @ 0x" << std::hex << id.listener.unsafe_get()
+                   << std::dec << ").";
+        return;
+    }
+
+    bufferIds.erase(findBufferId);
+    if (bufferIds.empty()) {
+        frameIndex2BufferIds.erase(findFrameIndex);
+        if (frameIndex2BufferIds.empty()) {
+            mTrackedBuffersMap.erase(findListener);
+        }
+    }
+
+    DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
+    deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
+    ++deathNotifications.count;
+    mOnBufferDestroyed.notify_one();
+}
+
+// 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/hidl/1.0/utils/InputSurface.cpp b/media/codec2/hidl/1.0/utils/InputSurface.cpp
index b669460..2cbe64b 100644
--- a/media/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,12 +16,11 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-InputSurface"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/InputSurface.h>
 #include <codec2/hidl/1.0/InputSurfaceConnection.h>
 
-#include <util/C2InterfaceHelper.h>
 #include <C2Component.h>
 #include <C2Config.h>
 
@@ -36,9 +35,10 @@
 
 using namespace ::android;
 
-class InputSurface::ConfigurableImpl : public C2InterfaceHelper {
+// Derived class of C2InterfaceHelper
+class InputSurface::Interface : public C2InterfaceHelper {
 public:
-    explicit ConfigurableImpl(
+    explicit Interface(
             const std::shared_ptr<C2ReflectorHelper> &helper)
         : C2InterfaceHelper(helper) {
 
@@ -63,33 +63,34 @@
     std::shared_ptr<C2InputSurfaceEosTuning> mEos;
 };
 
-namespace {
-
-class ConfigurableWrapper : public ConfigurableC2Intf {
+// Derived class of ConfigurableC2Intf
+class InputSurface::ConfigurableIntf : public ConfigurableC2Intf {
 public:
-    ConfigurableWrapper(
-            const std::shared_ptr<InputSurface::ConfigurableImpl> &impl,
+    ConfigurableIntf(
+            const std::shared_ptr<InputSurface::Interface> &intf,
             const sp<GraphicBufferSource> &source)
-        : ConfigurableC2Intf("input-surface"),
-          mImpl(impl),
+        : ConfigurableC2Intf("input-surface", 0),
+          mIntf(intf),
           mSource(source) {
     }
 
-    ~ConfigurableWrapper() override = default;
+    virtual ~ConfigurableIntf() override = default;
 
-    c2_status_t query(
+    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 mImpl->query({}, indices, mayBlock, params);
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        return mIntf->query({}, indices, mayBlock, params);
     }
 
-    c2_status_t config(
+    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 = mImpl->config(params, mayBlock, failures);
-        if (mImpl->eos()) {
+            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|
@@ -100,202 +101,71 @@
         return err;
     }
 
-    c2_status_t querySupportedParams(
-            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
-        return mImpl->querySupportedParams(params);
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        return mIntf->querySupportedParams(params);
     }
 
-    c2_status_t querySupportedValues(
+    virtual c2_status_t querySupportedValues(
             std::vector<C2FieldSupportedValuesQuery>& fields,
             c2_blocking_t mayBlock) const override {
-        return mImpl->querySupportedValues(fields, mayBlock);
+        return mIntf->querySupportedValues(fields, mayBlock);
     }
 
 private:
-    const std::shared_ptr<InputSurface::ConfigurableImpl> mImpl;
+    const std::shared_ptr<InputSurface::Interface> mIntf;
     wp<GraphicBufferSource> mSource;
 };
 
-}  // namespace
-
-
-Return<void> InputSurface::connectToComponent(
-        const sp<IComponent>& component,
-        connectToComponent_cb _hidl_cb) {
-    Status status;
-    sp<InputSurfaceConnection> conn;
-    if (!component) {
-        status = Status::BAD_VALUE;
-    } else {
-        std::shared_ptr<C2Component> comp = mStore->findC2Component(component);
-        if (!comp) {
-            conn = new InputSurfaceConnection(mSource, component);
-        } else {
-            conn = new InputSurfaceConnection(mSource, comp);
-        }
-        if (!conn->init()) {
-            conn = nullptr;
-            status = Status::BAD_VALUE;
-        } else {
-            status = Status::OK;
-        }
-    }
-    _hidl_cb(status, conn);
-    return Void();
+Return<sp<InputSurface::HGraphicBufferProducer>> InputSurface::getGraphicBufferProducer() {
+    return mProducer;
 }
 
 Return<sp<IConfigurable>> InputSurface::getConfigurable() {
     return mConfigurable;
 }
 
-// Derived methods from IGraphicBufferProducer
-
-Return<void> InputSurface::requestBuffer(
-        int32_t slot,
-        requestBuffer_cb _hidl_cb) {
-    return mBase->requestBuffer(slot, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::setMaxDequeuedBufferCount(
-        int32_t maxDequeuedBuffers) {
-    return mBase->setMaxDequeuedBufferCount(maxDequeuedBuffers);
-}
-
-Return<int32_t> InputSurface::setAsyncMode(
-        bool async) {
-    return mBase->setAsyncMode(async);
-}
-
-Return<void> InputSurface::dequeueBuffer(
-        uint32_t width,
-        uint32_t height,
-        PixelFormat format,
-        uint32_t usage,
-        bool getFrameTimestamps,
-        dequeueBuffer_cb _hidl_cb) {
-    return mBase->dequeueBuffer(
-            width, height, format, usage, getFrameTimestamps, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::detachBuffer(
-        int32_t slot) {
-    return mBase->detachBuffer(slot);
-}
-
-Return<void> InputSurface::detachNextBuffer(
-        detachNextBuffer_cb _hidl_cb) {
-    return mBase->detachNextBuffer(_hidl_cb);
-}
-
-Return<void> InputSurface::attachBuffer(
-        const AnwBuffer& buffer,
-        attachBuffer_cb _hidl_cb) {
-    return mBase->attachBuffer(buffer, _hidl_cb);
-}
-
-Return<void> InputSurface::queueBuffer(
-        int32_t slot,
-        const QueueBufferInput& input,
-        queueBuffer_cb _hidl_cb) {
-    return mBase->queueBuffer(slot, input, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::cancelBuffer(
-        int32_t slot,
-        const hidl_handle& fence) {
-    return mBase->cancelBuffer(slot, fence);
-}
-
-Return<void> InputSurface::query(
-        int32_t what,
-        query_cb _hidl_cb) {
-    return mBase->query(what, _hidl_cb);
-}
-
 Return<void> InputSurface::connect(
-        const sp<HProducerListener>& listener,
-        int32_t api,
-        bool producerControlledByApp,
+        const sp<IInputSink>& sink,
         connect_cb _hidl_cb) {
-    return mBase->connect(listener, api, producerControlledByApp, _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, mStore);
+    } else {
+        connection = new InputSurfaceConnection(mSource, sink, mStore);
+    }
+    if (!connection->init()) {
+        connection = nullptr;
+        status = Status::BAD_VALUE;
+    } else {
+        status = Status::OK;
+    }
+    _hidl_cb(status, connection);
+    return Void();
 }
 
-Return<int32_t> InputSurface::disconnect(
-        int32_t api,
-        DisconnectMode mode) {
-    return mBase->disconnect(api, mode);
-}
-
-Return<int32_t> InputSurface::setSidebandStream(
-        const hidl_handle& stream) {
-    return mBase->setSidebandStream(stream);
-}
-
-Return<void> InputSurface::allocateBuffers(
-        uint32_t width,
-        uint32_t height,
-        PixelFormat format,
-        uint32_t usage) {
-    return mBase->allocateBuffers(width, height, format, usage);
-}
-
-Return<int32_t> InputSurface::allowAllocation(
-        bool allow) {
-    return mBase->allowAllocation(allow);
-}
-
-Return<int32_t> InputSurface::setGenerationNumber(
-        uint32_t generationNumber) {
-    return mBase->setGenerationNumber(generationNumber);
-}
-
-Return<void> InputSurface::getConsumerName(
-        getConsumerName_cb _hidl_cb) {
-    return mBase->getConsumerName(_hidl_cb);
-}
-
-Return<int32_t> InputSurface::setSharedBufferMode(
-        bool sharedBufferMode) {
-    return mBase->setSharedBufferMode(sharedBufferMode);
-}
-
-Return<int32_t> InputSurface::setAutoRefresh(
-        bool autoRefresh) {
-    return mBase->setAutoRefresh(autoRefresh);
-}
-
-Return<int32_t> InputSurface::setDequeueTimeout(
-        int64_t timeoutNs) {
-    return mBase->setDequeueTimeout(timeoutNs);
-}
-
-Return<void> InputSurface::getLastQueuedBuffer(
-        getLastQueuedBuffer_cb _hidl_cb) {
-    return mBase->getLastQueuedBuffer(_hidl_cb);
-}
-
-Return<void> InputSurface::getFrameTimestamps(
-        getFrameTimestamps_cb _hidl_cb) {
-    return mBase->getFrameTimestamps(_hidl_cb);
-}
-
-Return<void> InputSurface::getUniqueId(
-        getUniqueId_cb _hidl_cb) {
-    return mBase->getUniqueId(_hidl_cb);
-}
+// Derived methods from IGraphicBufferProducer
 
 // Constructor is exclusive to ComponentStore.
 InputSurface::InputSurface(
         const sp<ComponentStore>& store,
         const std::shared_ptr<C2ReflectorHelper>& reflector,
-        const sp<HGraphicBufferProducer>& base,
-        const sp<GraphicBufferSource>& source) :
-    mStore(store),
-    mBase(base),
-    mSource(source),
-    mHelper(std::make_shared<ConfigurableImpl>(reflector)),
-    mConfigurable(new CachedConfigurable(
-            std::make_unique<ConfigurableWrapper>(mHelper, source))) {
+        const sp<HGraphicBufferProducer>& producer,
+        const sp<GraphicBufferSource>& source)
+      : mStore{store},
+        mProducer{producer},
+        mSource{source},
+        mIntf{std::make_shared<Interface>(reflector)},
+        mConfigurable{new CachedConfigurable(
+                std::make_unique<ConfigurableIntf>(
+                    mIntf, source))} {
 
     mConfigurable->init(store.get());
 }
diff --git a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
index 8b1ece3..1024f50 100644
--- a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,9 +16,10 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-InputSurfaceConnection"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/InputSurfaceConnection.h>
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
 
 #include <memory>
 #include <list>
@@ -65,51 +66,74 @@
 
 } // 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>& comp) :
-            mSource(source), mComp(comp), mRemoteComp(),
-            mFrameIndex(0) {
-        std::shared_ptr<C2ComponentInterface> intf = comp->intf();
-        mCompName = intf ? intf->getName() : "";
+         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<IComponent>& comp) :
-            mSource(source), mComp(), mRemoteComp(comp),
-            mFrameIndex(0) {
-        Return<void> transStatus = comp->getName(
-                [this](const hidl_string& name) {
-                    mCompName = name.c_str();
+         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()) {
-            ALOGD("getName -- Cannot obtain remote component name.");
+            LOG(ERROR) << "Remote sink's configurable is dead.";
+            mSinkName = "";
+            return;
         }
+        mSinkName = name.c_str();
     }
 
-    virtual ~Impl() = default;
+    virtual ~Impl() {
+        mSource->stop();
+        mSource->release();
+    }
 
     bool init() {
-        sp<GraphicBufferSource> source = mSource.promote();
-        if (source == nullptr) {
+        if (mSource == nullptr) {
             return false;
         }
-        status_t err = source->initCheck();
+        status_t err = mSource->initCheck();
         if (err != OK) {
-            ALOGD("Impl::init -- GBS init failed: %d", err);
+            LOG(WARNING) << "Impl::init -- GraphicBufferSource init failed: "
+                         << "status = " << err << ".";
             return false;
         }
 
         // TODO: read settings properly from the interface
         C2VideoSizeStreamTuning::input inputSize;
         C2StreamUsageTuning::input usage;
-        c2_status_t c2Status = compQuery({ &inputSize, &usage },
+        c2_status_t c2Status = queryFromSink({ &inputSize, &usage },
                                          {},
                                          C2_MAY_BLOCK,
                                          nullptr);
         if (c2Status != C2_OK) {
-            ALOGD("Impl::init -- cannot query information from "
-                    "the component interface: %s.", asString(c2Status));
+            LOG(WARNING) << "Impl::init -- cannot query information from "
+                            "the component interface: "
+                         << "status = " << asString(c2Status) << ".";
             return false;
         }
 
@@ -122,26 +146,27 @@
         //         asGrallocUsage();
 
         uint32_t grallocUsage =
-                mCompName.compare(0, 11, "c2.android.") == 0 ?
+                mSinkName.compare(0, 11, "c2.android.") == 0 ?
                 GRALLOC_USAGE_SW_READ_OFTEN :
                 GRALLOC_USAGE_HW_VIDEO_ENCODER;
 
-        err = source->configure(
+        err = mSource->configure(
                 this, dataSpace, kBufferCount,
                 inputSize.width, inputSize.height,
                 grallocUsage);
         if (err != OK) {
-            ALOGD("Impl::init -- GBS configure failed: %d", err);
+            LOG(WARNING) << "Impl::init -- GBS configure failed: "
+                         << "status = " << err << ".";
             return false;
         }
         for (int32_t i = 0; i < kBufferCount; ++i) {
-            if (!source->onInputBufferAdded(i).isOk()) {
-                ALOGD("Impl::init: populating GBS slots failed");
+            if (!mSource->onInputBufferAdded(i).isOk()) {
+                LOG(WARNING) << "Impl::init: failed to populate GBS slots.";
                 return false;
             }
         }
-        if (!source->start().isOk()) {
-            ALOGD("Impl::init -- GBS start failed");
+        if (!mSource->start().isOk()) {
+            LOG(WARNING) << "Impl::init -- GBS failed to start.";
             return false;
         }
         mAllocatorMutex.lock();
@@ -150,7 +175,8 @@
                 &mAllocator);
         mAllocatorMutex.unlock();
         if (c2err != OK) {
-            ALOGD("Impl::init -- failed to fetch gralloc allocator: %d", c2err);
+            LOG(WARNING) << "Impl::init -- failed to fetch gralloc allocator: "
+                         << "status = " << asString(c2err) << ".";
             return false;
         }
         return true;
@@ -162,7 +188,7 @@
             const sp<GraphicBuffer>& buffer,
             int64_t timestamp,
             int fenceFd) override {
-        ALOGV("Impl::submitBuffer -- bufferId = %d", bufferId);
+        LOG(VERBOSE) << "Impl::submitBuffer -- bufferId = " << bufferId << ".";
         // TODO: Use fd to construct fence
         (void)fenceFd;
 
@@ -190,9 +216,8 @@
                 // TODO: fence
                 new Buffer2D(block->share(
                         C2Rect(block->width(), block->height()), ::C2Fence())),
-                [bufferId, src = mSource](C2Buffer* ptr) {
+                [bufferId, source = mSource](C2Buffer* ptr) {
                     delete ptr;
-                    sp<GraphicBufferSource> source = src.promote();
                     if (source != nullptr) {
                         // TODO: fence
                         (void)source->onInputBufferEmptied(bufferId, -1);
@@ -204,12 +229,13 @@
         std::list<std::unique_ptr<C2Work>> items;
         items.push_back(std::move(work));
 
-        err = compQueue(&items);
+        err = queueToSink(&items);
         return (err == C2_OK) ? OK : UNKNOWN_ERROR;
     }
 
-    virtual status_t submitEos(int32_t /* bufferId */) override {
-        ALOGV("Impl::submitEos");
+    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;
@@ -221,11 +247,11 @@
         std::list<std::unique_ptr<C2Work>> items;
         items.push_back(std::move(work));
 
-        c2_status_t err = compQueue(&items);
+        c2_status_t err = queueToSink(&items);
         return (err == C2_OK) ? OK : UNKNOWN_ERROR;
     }
 
-    void dispatchDataSpaceChanged(
+    virtual void dispatchDataSpaceChanged(
             int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
         // TODO
         (void)dataSpace;
@@ -233,36 +259,63 @@
         (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 compQuery(
+    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) {
-        std::shared_ptr<C2Component> comp = mComp.lock();
-        if (comp) {
-            std::shared_ptr<C2ComponentInterface> intf = comp->intf();
+        if (mLocalComp) {
+            std::shared_ptr<C2ComponentInterface> intf = mLocalComp->intf();
             if (intf) {
                 return intf->query_vb(stackParams,
                                       heapParamIndices,
                                       mayBlock,
                                       heapParams);
             } else {
-                ALOGD("compQuery -- component does not have an interface.");
+                LOG(ERROR) << "queryFromSink -- "
+                           << "component does not have an interface.";
                 return C2_BAD_STATE;
             }
         }
-        if (!mRemoteComp) {
-            ALOGD("compQuery -- component no longer exists.");
-            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) {
-                ALOGD("compQuery -- null stack param encountered.");
+                LOG(DEBUG) << "queryFromSink -- null stack param encountered.";
                 continue;
             }
             indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
@@ -277,22 +330,22 @@
             heapParams->reserve(heapParams->size() + numIndices);
         }
         c2_status_t status;
-        Return<void> transStatus = mRemoteComp->query(
+        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) {
-                        ALOGD("compQuery -- call failed: %s.", asString(status));
+                        LOG(DEBUG) << "queryFromSink -- call failed: "
+                                   << "status = " << asString(status) << ".";
                         return;
                     }
                     std::vector<C2Param*> paramPointers;
-                    c2_status_t parseStatus = parseParamsBlob(&paramPointers, p);
-                    if (parseStatus != C2_OK) {
-                        ALOGD("compQuery -- error while parsing params: %s.",
-                              asString(parseStatus));
-                        status = parseStatus;
+                    if (!parseParamsBlob(&paramPointers, p)) {
+                        LOG(DEBUG) << "queryFromSink -- error while "
+                                   << "parsing params.";
+                        status = C2_CORRUPTED;
                         return;
                     }
                     size_t i = 0;
@@ -302,7 +355,8 @@
                         if (numStackIndices > 0) {
                             --numStackIndices;
                             if (!paramPointer) {
-                                ALOGD("compQuery -- null stack param.");
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "null stack param.";
                                 ++it;
                                 continue;
                             }
@@ -313,25 +367,27 @@
                             CHECK(i < stackParams.size());
                             if (stackParams[i]->index() !=
                                     paramPointer->index()) {
-                                ALOGD("compQuery -- param skipped. index = %d",
-                                      static_cast<int>(
-                                      stackParams[i]->index()));
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "param skipped (index = "
+                                           << stackParams[i]->index() << ").";
                                 stackParams[i++]->invalidate();
                                 continue;
                             }
                             if (!stackParams[i++]->updateFrom(*paramPointer)) {
-                                ALOGD("compQuery -- param update failed: "
-                                      "index = %d.",
-                                      static_cast<int>(paramPointer->index()));
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "param update failed (index = "
+                                           << paramPointer->index() << ").";
                             }
                         } else {
                             if (!paramPointer) {
-                                ALOGD("compQuery -- null heap param.");
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "null heap param.";
                                 ++it;
                                 continue;
                             }
                             if (!heapParams) {
-                                ALOGD("compQuery -- too many stack params.");
+                                LOG(WARNING) << "queryFromSink -- "
+                                                "too many stack params.";
                                 break;
                             }
                             heapParams->emplace_back(C2Param::Copy(*paramPointer));
@@ -340,96 +396,130 @@
                     }
                 });
         if (!transStatus.isOk()) {
-            ALOGD("compQuery -- transaction failed.");
+            LOG(ERROR) << "queryFromSink -- transaction failed.";
             return C2_CORRUPTED;
         }
         return status;
     }
 
-    c2_status_t compQueue(std::list<std::unique_ptr<C2Work>>* const items) {
-        std::shared_ptr<C2Component> comp = mComp.lock();
-        if (comp) {
-            return comp->queue_nb(items);
+    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;
-        Status hidlStatus = objcpy(&workBundle, *items, nullptr);
-        if (hidlStatus != Status::OK) {
-            ALOGD("compQueue -- bad input.");
+        if (!objcpy(&workBundle, *items, nullptr)) {
+            LOG(ERROR) << "queueToSink -- bad input.";
             return C2_CORRUPTED;
         }
-        Return<Status> transStatus = mRemoteComp->queue(workBundle);
+        Return<Status> transStatus = mSink->queue(workBundle);
         if (!transStatus.isOk()) {
-            ALOGD("compQueue -- transaction failed.");
+            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) {
-            ALOGV("compQueue -- call failed: %s.", asString(status));
+            LOG(DEBUG) << "queueToSink -- call failed: "
+                         << asString(status);
         }
         return status;
     }
 
-    wp<GraphicBufferSource> mSource;
-    std::weak_ptr<C2Component> mComp;
-    sp<IComponent> mRemoteComp;
-    std::string mCompName;
+    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) :
-    mSource(source),
-    mImpl(new Impl(source, comp)) {
+        const std::shared_ptr<C2Component>& comp,
+        const sp<ComponentStore>& store)
+      : mImpl{new Impl(source, comp)},
+        mConfigurable{new CachedConfigurable(
+            std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+    mConfigurable->init(store.get());
 }
 
 InputSurfaceConnection::InputSurfaceConnection(
         const sp<GraphicBufferSource>& source,
-        const sp<IComponent>& comp) :
-    mSource(source),
-    mImpl(new Impl(source, comp)) {
-}
-
-InputSurfaceConnection::~InputSurfaceConnection() {
-    if (mSource) {
-        (void)mSource->stop();
-        (void)mSource->release();
-        mSource.clear();
-    }
-    mImpl.clear();
-}
-
-bool InputSurfaceConnection::init() {
-    mMutex.lock();
-    sp<Impl> impl = mImpl;
-    mMutex.unlock();
-
-    if (!impl) {
-        return false;
-    }
-    return impl->init();
+        const sp<IInputSink>& sink,
+        const sp<ComponentStore>& store)
+      : mImpl{new Impl(source, sink)},
+        mConfigurable{new CachedConfigurable(
+            std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+    mConfigurable->init(store.get());
 }
 
 Return<Status> InputSurfaceConnection::disconnect() {
-    ALOGV("disconnect");
-    mMutex.lock();
-    if (mSource) {
-        (void)mSource->stop();
-        (void)mSource->release();
-        mSource.clear();
-    }
-    mImpl.clear();
-    mMutex.unlock();
-    ALOGV("disconnected");
+    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
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
index 0908226..4ac95c5 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,13 +17,15 @@
 #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/IComponent.h>
 #include <hidl/Status.h>
 #include <hwbinder/IBinder.h>
 
@@ -31,9 +33,9 @@
 #include <C2Buffer.h>
 #include <C2.h>
 
-#include <list>
 #include <map>
 #include <memory>
+#include <mutex>
 
 namespace android {
 namespace hardware {
@@ -54,19 +56,8 @@
 
 struct ComponentStore;
 
-struct ComponentInterface : public Configurable<IComponentInterface> {
-    ComponentInterface(
-            const std::shared_ptr<C2ComponentInterface>& interface,
-            const sp<ComponentStore>& store);
-    c2_status_t status() const;
-
-protected:
-    c2_status_t mInit;
-    std::shared_ptr<C2ComponentInterface> mInterface;
-    sp<ComponentStore> mStore;
-};
-
-struct Component : public Configurable<IComponent> {
+struct Component : public IComponent,
+                   public std::enable_shared_from_this<Component> {
     Component(
             const std::shared_ptr<C2Component>&,
             const sp<IComponentListener>& listener,
@@ -85,10 +76,14 @@
     virtual Return<Status> setOutputSurface(
             uint64_t blockPoolId,
             const sp<HGraphicBufferProducer>& surface) override;
-    virtual Return<Status> connectToOmxInputSurface(
+    virtual Return<void> connectToInputSurface(
+            const sp<IInputSurface>& inputSurface,
+            connectToInputSurface_cb _hidl_cb) override;
+    virtual Return<void> connectToOmxInputSurface(
             const sp<HGraphicBufferProducer>& producer,
             const sp<::android::hardware::media::omx::V1_0::
-            IGraphicBufferSource>& source) override;
+            IGraphicBufferSource>& source,
+            connectToOmxInputSurface_cb _hidl_cb) override;
     virtual Return<Status> disconnectFromInputSurface() override;
     virtual Return<void> createBlockPool(
             uint32_t allocatorId,
@@ -98,63 +93,34 @@
     virtual Return<Status> stop() override;
     virtual Return<Status> reset() override;
     virtual Return<Status> release() override;
+    virtual Return<sp<IComponentInterface>> getInterface() 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;
-    std::shared_ptr<C2ComponentInterface> mInterface;
+    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;
 
-    // This struct is a comparable wrapper for IComponent.
-    //
-    // An IComponent object is either local or remote. If it is local, we can
-    // use the underlying pointer as a key. If it is remote, we have to use the
-    // underlying pointer of the associated binder object as a key.
-    //
-    // See interfacesEqual() for more detail.
-    struct InterfaceKey {
-        // An InterfaceKey is constructed from IComponent.
-        InterfaceKey(const sp<IComponent>& component);
-        // operator< is defined here to control the default definition of
-        // std::less<InterfaceKey>, which will be used in type Roster defined
-        // below.
-        bool operator<(const InterfaceKey& other) const {
-            return isRemote ?
-                    (other.isRemote ?
-                        // remote & remote
-                        std::less<IBinder*>()(
-                            remote.unsafe_get(),
-                            other.remote.unsafe_get()) :
-                        // remote & local
-                        false) :
-                    (other.isRemote ?
-                        // local & remote
-                        true :
-                        // local & local
-                        std::less<IComponent*>()(
-                            local.unsafe_get(),
-                            other.local.unsafe_get()));
-        }
-    private:
-        bool isRemote;
-        wp<IBinder> remote;
-        wp<IComponent> local;
-    };
-
-    typedef std::map<InterfaceKey, std::weak_ptr<C2Component>> Roster;
-    typedef Roster::const_iterator LocalId;
-    LocalId mLocalId;
-    void setLocalId(const LocalId& localId);
-
     void initListener(const sp<Component>& self);
 
     virtual ~Component() override;
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
new file mode 100644
index 0000000..a5d235e
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/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,
+            ComponentStore* store);
+    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/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index 41e1416..be80c62 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,15 +18,18 @@
 #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/c2/1.0/IComponentStore.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>
@@ -42,53 +45,61 @@
 
 using ::android::hardware::media::bufferpool::V2_0::IClientManager;
 
-using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_handle;
-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::sp;
-using ::android::wp;
 
-struct ComponentStore : public Configurable<IComponentStore> {
+struct ComponentStore : public IComponentStore {
     ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
     virtual ~ComponentStore() = default;
 
-    c2_status_t status() const {
-        return mInit;
-    }
+    /**
+     * 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);
 
-    // Methods from ::android::hardware::media::c2::V1_0::IComponentStore
-    Return<void> createComponent(
+    // 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;
-    Return<void> createInterface(
+    virtual Return<void> createInterface(
             const hidl_string& name,
             createInterface_cb _hidl_cb) override;
-    Return<void> listComponents(listComponents_cb _hidl_cb) override;
-    Return<sp<IInputSurface>> createInputSurface() override;
-    Return<void> getStructDescriptors(
+    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;
-    Return<sp<IClientManager>> getPoolClientManager() override;
-    Return<Status> copyBuffer(
+    virtual Return<sp<IClientManager>> getPoolClientManager() override;
+    virtual Return<Status> copyBuffer(
             const Buffer& src,
             const Buffer& dst) override;
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
 
-    // Debug dump
-    Return<void> debug(
+    /**
+     * Dumps information when lshal is called.
+     */
+    virtual Return<void> debug(
             const hidl_handle& handle,
             const hidl_vec<hidl_string>& args) override;
 
 protected:
-    // does bookkeeping for an interface that has been loaded
+    sp<CachedConfigurable> mConfigurable;
+
+    // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
     c2_status_t mInit;
@@ -100,18 +111,33 @@
     std::set<C2String> mLoadedInterfaces;
     mutable std::mutex mStructDescriptorsMutex;
 
-    // Component lifetime management
-    Component::Roster mComponentRoster;
+    // ComponentStore keeps track of live Components.
+
+    struct ComponentStatus {
+        std::shared_ptr<C2Component> c2Component;
+        std::chrono::system_clock::time_point birthTime;
+    };
+
     mutable std::mutex mComponentRosterMutex;
-    void reportComponentDeath(const Component::LocalId& componentLocalId);
+    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;
 
-    // C2Component lookup
-    std::shared_ptr<C2Component> findC2Component(
-            const sp<IComponent>& component) const;
+    // Helper functions for dumping.
 
-    friend struct InputSurface;
+    std::ostream& dump(
+            std::ostream& out,
+            const std::shared_ptr<const C2Component::Traits>& comp);
+
+    std::ostream& dump(
+            std::ostream& out,
+            ComponentStatus& compStatus);
+
 };
 
 }  // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
index 2e33a6f..8095185 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,15 +17,13 @@
 #ifndef CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
 #define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
 
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <hidl/Status.h>
 
 #include <C2Component.h>
 #include <C2Param.h>
 #include <C2.h>
 
-#include <android/hardware/media/c2/1.0/IConfigurable.h>
-#include <hidl/Status.h>
-
 #include <memory>
 
 namespace android {
@@ -35,9 +33,6 @@
 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;
@@ -46,12 +41,52 @@
 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;
+};
+
+/**
  * Implementation of the IConfigurable interface that supports caching of
  * supported parameters from a supplied ComponentStore.
  *
- * This is mainly the same for all of the configurable C2 interfaces though
- * there are slight differences in the blocking behavior. This is handled in the
- * ConfigurableC2Intf implementations.
+ * 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);
@@ -60,6 +95,8 @@
 
     // 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(
@@ -90,63 +127,6 @@
     std::vector<std::shared_ptr<C2ParamDescriptor>> mSupportedParams;
 };
 
-/**
- * Template that implements the `IConfigurable` interface for an inherited
- * interface. Classes that implement a child interface `I` of `IConfigurable`
- * can derive from `Configurable<I>`.
- */
-template <typename I>
-struct Configurable : public I {
-    Configurable(const sp<CachedConfigurable>& intf): mIntf(intf) {
-    }
-
-    c2_status_t init(ComponentStore* store) {
-        return mIntf->init(store);
-    }
-
-    // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
-
-    using getName_cb = typename I::getName_cb;
-    virtual Return<void> getName(getName_cb _hidl_cb) override {
-        return mIntf->getName(_hidl_cb);
-    }
-
-    using query_cb = typename I::query_cb;
-    virtual Return<void> query(
-            const hidl_vec<uint32_t>& indices,
-            bool mayBlock,
-            query_cb _hidl_cb) override {
-        return mIntf->query(indices, mayBlock, _hidl_cb);
-    }
-
-    using config_cb = typename I::config_cb;
-    virtual Return<void> config(
-            const hidl_vec<uint8_t>& inParams,
-            bool mayBlock,
-            config_cb _hidl_cb) override {
-        return mIntf->config(inParams, mayBlock, _hidl_cb);
-    }
-
-    using querySupportedParams_cb = typename I::querySupportedParams_cb;
-    virtual Return<void> querySupportedParams(
-            uint32_t start,
-            uint32_t count,
-            querySupportedParams_cb _hidl_cb) override {
-        return mIntf->querySupportedParams(start, count, _hidl_cb);
-    }
-
-    using querySupportedValues_cb = typename I::querySupportedValues_cb;
-    virtual Return<void> querySupportedValues(
-            const hidl_vec<FieldSupportedValuesQuery>& inFields,
-            bool mayBlock,
-            querySupportedValues_cb _hidl_cb) override {
-        return mIntf->querySupportedValues(inFields, mayBlock, _hidl_cb);
-    }
-
-protected:
-    sp<CachedConfigurable> mIntf;
-};
-
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace c2
@@ -155,3 +135,4 @@
 }  // namespace android
 
 #endif  // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h
deleted file mode 100644
index b8801bb..0000000
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 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_CONFIGURABLEC2INTF_H
-#define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
-
-#include <C2Work.h>
-#include <C2Component.h>
-#include <C2Param.h>
-#include <C2.h>
-
-#include <hidl/HidlSupport.h>
-#include <utils/StrongPointer.h>
-#include <vector>
-#include <memory>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
-
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-/**
- * Common Codec 2.0 interface wrapper.
- */
-struct ConfigurableC2Intf {
-    C2String getName() const { return mName; }
-    /** 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) : mName(name) {}
-
-protected:
-    C2String mName; /* cache component name */
-};
-
-}  // namespace utils
-}  // namespace V1_0
-}  // namespace c2
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
new file mode 100644
index 0000000..b6857d5
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
@@ -0,0 +1,294 @@
+/*
+ * 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) {}
+        TrackedBuffer(const TrackedBuffer&) = default;
+        bool operator<(const TrackedBuffer& other) const {
+            return bufferIndex < other.bufferIndex;
+        }
+    };
+
+    // 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;
+
+    // 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/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
index cef258e..2682c13 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -19,21 +19,14 @@
 
 #include <codec2/hidl/1.0/ComponentStore.h>
 
-#include <android/hardware/media/c2/1.0/IInputSurface.h>
-#include <android/hardware/media/c2/1.0/IComponent.h>
-
 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
-#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
-#include <android/hardware/graphics/common/1.0/types.h>
-#include <android/hardware/media/1.0/types.h>
-
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <hidl/Status.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
 
-#include <hidl/HidlSupport.h>
-#include <hidl/Status.h>
-
-class C2ReflectorHelper;
+#include <util/C2InterfaceHelper.h>
 
 namespace android {
 namespace hardware {
@@ -49,133 +42,31 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::media::V1_0::AnwBuffer;
-
 struct InputSurface : public IInputSurface {
 
-    typedef ::android::hidl::base::V1_0::IBase IBase;
-
-    typedef ::android::hardware::graphics::bufferqueue::V1_0::
-            IProducerListener HProducerListener;
-
-    typedef ::android::
-            IGraphicBufferProducer BGraphicBufferProducer;
-
     typedef ::android::hardware::graphics::bufferqueue::V1_0::
             IGraphicBufferProducer HGraphicBufferProducer;
 
     typedef ::android::
             GraphicBufferSource GraphicBufferSource;
 
-// Type disambiguation
-
-    typedef ::android::hardware::media::c2::V1_0::Status Status;
-
-// New methods from IInputSurface
-
-    virtual Return<void> connectToComponent(
-            const sp<IComponent>& component,
-            connectToComponent_cb _hidl_cb) override;
+    virtual Return<sp<HGraphicBufferProducer>> getGraphicBufferProducer() override;
 
     virtual Return<sp<IConfigurable>> getConfigurable() override;
 
-// Methods derived from IGraphicBufferProducer
-
-    virtual Return<void> requestBuffer(
-            int32_t slot,
-            requestBuffer_cb _hidl_cb) override;
-
-    virtual Return<int32_t> setMaxDequeuedBufferCount(
-            int32_t maxDequeuedBuffers) override;
-
-    virtual Return<int32_t> setAsyncMode(
-            bool async) override;
-
-    virtual Return<void> dequeueBuffer(
-            uint32_t width,
-            uint32_t height,
-            PixelFormat format,
-            uint32_t usage,
-            bool getFrameTimestamps,
-            dequeueBuffer_cb _hidl_cb) override;
-
-    virtual Return<int32_t> detachBuffer(
-            int32_t slot) override;
-
-    virtual Return<void> detachNextBuffer(
-            detachNextBuffer_cb _hidl_cb) override;
-
-    virtual Return<void> attachBuffer(
-            const AnwBuffer& buffer,
-            attachBuffer_cb _hidl_cb) override;
-
-    virtual Return<void> queueBuffer(
-            int32_t slot,
-            const QueueBufferInput& input,
-            queueBuffer_cb _hidl_cb) override;
-
-    virtual Return<int32_t> cancelBuffer(
-            int32_t slot,
-            const hidl_handle& fence) override;
-
-    virtual Return<void> query(
-            int32_t what,
-            query_cb _hidl_cb) override;
-
     virtual Return<void> connect(
-            const sp<HProducerListener>& listener,
-            int32_t api,
-            bool producerControlledByApp,
+            const sp<IInputSink>& sink,
             connect_cb _hidl_cb) override;
 
-    virtual Return<int32_t> disconnect(
-            int32_t api,
-            DisconnectMode mode) override;
-
-    virtual Return<int32_t> setSidebandStream(
-            const hidl_handle& stream) override;
-
-    virtual Return<void> allocateBuffers(
-            uint32_t width,
-            uint32_t height,
-            PixelFormat format,
-            uint32_t usage) override;
-
-    virtual Return<int32_t> allowAllocation(
-            bool allow) override;
-
-    virtual Return<int32_t> setGenerationNumber(
-            uint32_t generationNumber) override;
-
-    virtual Return<void> getConsumerName(
-            getConsumerName_cb _hidl_cb) override;
-
-    virtual Return<int32_t> setSharedBufferMode(
-            bool sharedBufferMode) override;
-
-    virtual Return<int32_t> setAutoRefresh(
-            bool autoRefresh) override;
-
-    virtual Return<int32_t> setDequeueTimeout(
-            int64_t timeoutNs) override;
-
-    virtual Return<void> getLastQueuedBuffer(
-            getLastQueuedBuffer_cb _hidl_cb) override;
-
-    virtual Return<void> getFrameTimestamps(
-            getFrameTimestamps_cb _hidl_cb) override;
-
-    virtual Return<void> getUniqueId(
-            getUniqueId_cb _hidl_cb) override;
-
-    class ConfigurableImpl;
-
 protected:
+
+    class Interface;
+    class ConfigurableIntf;
+
     sp<ComponentStore> mStore;
-    sp<HGraphicBufferProducer> mBase;
+    sp<HGraphicBufferProducer> mProducer;
     sp<GraphicBufferSource> mSource;
-    std::shared_ptr<ConfigurableImpl> mHelper;
+    std::shared_ptr<Interface> mIntf;
     sp<CachedConfigurable> mConfigurable;
 
     InputSurface(
@@ -187,6 +78,7 @@
     virtual ~InputSurface() override = default;
 
     friend struct ComponentStore;
+
 };
 
 
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
index 904fa9e..758b6b2 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,8 +18,10 @@
 #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>
@@ -44,19 +46,28 @@
 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>& component);
+            const std::shared_ptr<C2Component>& comp,
+            const sp<ComponentStore>& store);
 
     InputSurfaceConnection(
             const sp<GraphicBufferSource>& source,
-            const sp<IComponent>& component);
+            const sp<IInputSink>& sink,
+            const sp<ComponentStore>& store);
 
     bool init();
 
@@ -68,9 +79,9 @@
 
     struct Impl;
 
-    std::mutex mMutex;
-    sp<GraphicBufferSource> mSource;
+    std::mutex mImplMutex;
     sp<Impl> mImpl;
+    sp<CachedConfigurable> mConfigurable;
 
     virtual ~InputSurfaceConnection() override;
 };
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
index d8a50b6..c38e674 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,8 +17,6 @@
 #ifndef CODEC2_HIDL_V1_0_UTILS_TYPES_H
 #define CODEC2_HIDL_V1_0_UTILS_TYPES_H
 
-#include <chrono>
-
 #include <bufferpool/ClientManager.h>
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
 #include <android/hardware/media/bufferpool/2.0/types.h>
@@ -30,6 +28,9 @@
 #include <C2Param.h>
 #include <C2ParamDef.h>
 #include <C2Work.h>
+#include <util/C2Debug-base.h>
+
+#include <chrono>
 
 using namespace std::chrono_literals;
 
@@ -65,66 +66,74 @@
 };
 typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
 
+// 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
+ * conversion succeeds or not.
+ */
+
 // C2SettingResult -> SettingResult
-Status objcpy(
+bool objcpy(
         SettingResult* d,
         const C2SettingResult& s);
 
 // SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(
+bool objcpy(
         std::unique_ptr<C2SettingResult>* d,
         const SettingResult& s);
 
 // C2ParamDescriptor -> ParamDescriptor
-Status objcpy(
+bool objcpy(
         ParamDescriptor* d,
         const C2ParamDescriptor& s);
 
 // ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
-c2_status_t objcpy(
+bool objcpy(
         std::shared_ptr<C2ParamDescriptor>* d,
         const ParamDescriptor& s);
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQuery* d,
         const C2FieldSupportedValuesQuery& s);
 
 // FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& s);
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQueryResult* d,
         const C2FieldSupportedValuesQuery& s);
 
 // FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& sq,
         const FieldSupportedValuesQueryResult& sr);
 
 // C2Component::Traits -> ComponentTraits
-Status objcpy(
+bool objcpy(
         IComponentStore::ComponentTraits* d,
         const C2Component::Traits& s);
 
 // ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
 // Note: The output d is only valid as long as aliasesBuffer remains alive.
-c2_status_t objcpy(
+bool objcpy(
         C2Component::Traits* d,
         std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
         const IComponentStore::ComponentTraits& s);
 
 // C2StructDescriptor -> StructDescriptor
-Status objcpy(
+bool objcpy(
         StructDescriptor* d,
         const C2StructDescriptor& s);
 
 // StructDescriptor -> C2StructDescriptor
-c2_status_t objcpy(
+bool objcpy(
         std::unique_ptr<C2StructDescriptor>* d,
         const StructDescriptor& s);
 
@@ -208,68 +217,77 @@
 
 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
 // Note: If bufferpool will be used, bpSender must not be null.
-Status objcpy(
+bool objcpy(
         WorkBundle* d,
         const std::list<std::unique_ptr<C2Work>>& s,
         BufferPoolSender* bpSender = nullptr);
 
 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
-c2_status_t objcpy(
+bool objcpy(
         std::list<std::unique_ptr<C2Work>>* d,
         const WorkBundle& s);
 
 /**
- * Parses a params blob and returns C2Param pointers to its params.
+ * Parses a params blob and returns C2Param pointers to its params. The pointers
+ * point to locations inside the underlying buffer of \p blob. If \p blob is
+ * destroyed, the pointers become invalid.
+ *
  * \param[out] params target vector of C2Param pointers
  * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed
+ * \retval false otherwise
  */
-c2_status_t parseParamsBlob(
+bool parseParamsBlob(
         std::vector<C2Param*> *params,
         const hidl_vec<uint8_t> &blob);
 
 /**
  * Concatenates a list of C2Params into a params blob.
+ *
  * \param[out] blob target blob
  * \param[in] params parameters to concatenate
- * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- *         not const)
+ * \retval true if the blob was successfully created
+ * \retval false if the blob was not successful (this only happens if the
+ *         parameters were not const)
  */
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<C2Param*> &params);
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Param>> &params);
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::shared_ptr<const C2Info>> &params);
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Tuning>> &params);
 
 /**
  * Parses a params blob and create a vector of C2Params whose members are copies
  * of the params in the blob.
+ *
  * \param[out] params the resulting vector
  * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed and params was constructed
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed and params was constructed
+ * \retval false otherwise
  */
-c2_status_t copyParamsFromBlob(
+bool copyParamsFromBlob(
         std::vector<std::unique_ptr<C2Param>>* params,
         Params blob);
+bool copyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Tuning>>* params,
+        Params blob);
 
 /**
- * Parses a params blob and applies updates to params
+ * Parses a params blob and applies updates to params.
+ *
  * \param[in,out] params params to be updated
  * \param[in] blob parameter blob containing updates
- * \retval C2_OK if the full blob was parsed and params was updated
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed and params was updated
+ * \retval false otherwise
  */
-c2_status_t updateParamsFromBlob(
+bool updateParamsFromBlob(
         const std::vector<C2Param*>& params,
         const Params& blob);
 
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index a128a9d..caed839 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,11 +16,12 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-types"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/types.h>
 
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/foundation/AUtils.h>
 
 #include <C2AllocatorIon.h>
 #include <C2AllocatorGralloc.h>
@@ -35,10 +36,9 @@
 
 #include <algorithm>
 #include <functional>
+#include <iomanip>
 #include <unordered_map>
 
-#include <media/stagefright/foundation/AUtils.h>
-
 namespace android {
 namespace hardware {
 namespace media {
@@ -57,8 +57,18 @@
         TransactionId;
 using ::android::TWGraphicBufferProducer;
 
+const char* asString(Status status, const char* def) {
+    return asString(static_cast<c2_status_t>(status), def);
+}
+
 namespace /* unnamed */ {
 
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(
+        EnumClass x) {
+    return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
 template <typename Common, typename DstVector, typename SrcVector>
 void copyVector(DstVector* d, const SrcVector& s) {
     static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
@@ -73,10 +83,11 @@
 }
 
 // C2ParamField -> ParamField
-void objcpy(ParamField *d, const C2ParamField &s) {
+bool objcpy(ParamField *d, const C2ParamField &s) {
     d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
     d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
     d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+    return true;
 }
 
 struct C2ParamFieldBuilder : public C2ParamField {
@@ -92,21 +103,23 @@
 };
 
 // C2WorkOrdinalStruct -> WorkOrdinal
-void objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
     d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
     d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
     d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+    return true;
 }
 
 // WorkOrdinal -> C2WorkOrdinalStruct
-void objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
     d->frameIndex = c2_cntr64_t(s.frameIndex);
     d->timestamp = c2_cntr64_t(s.timestampUs);
     d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+    return true;
 }
 
 // C2FieldSupportedValues::range's type -> FieldSupportedValues::Range
-void objcpy(
+bool objcpy(
         FieldSupportedValues::Range* d,
         const decltype(C2FieldSupportedValues::range)& s) {
     d->min = static_cast<PrimitiveValue>(s.min.u64);
@@ -114,21 +127,24 @@
     d->step = static_cast<PrimitiveValue>(s.step.u64);
     d->num = static_cast<PrimitiveValue>(s.num.u64);
     d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+    return true;
 }
 
 // C2FieldSupportedValues -> FieldSupportedValues
-Status objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
-    d->typeOther = static_cast<int32_t>(s.type);
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
     switch (s.type) {
     case C2FieldSupportedValues::EMPTY:
         d->type = FieldSupportedValues::Type::EMPTY;
         d->values.resize(0);
-        return Status::OK;
+        break;
     case C2FieldSupportedValues::RANGE:
         d->type = FieldSupportedValues::Type::RANGE;
-        objcpy(&d->range, s.range);
+        if (!objcpy(&d->range, s.range)) {
+            LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+            return false;
+        }
         d->values.resize(0);
-        return Status::OK;
+        break;
     default:
         switch (s.type) {
         case C2FieldSupportedValues::VALUES:
@@ -138,18 +154,22 @@
             d->type = FieldSupportedValues::Type::FLAGS;
             break;
         default:
-            d->type = FieldSupportedValues::Type::OTHER;
-            // Copy all fields in this case
-            objcpy(&d->range, s.range);
+            LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+                       << "with underlying value " << underlying_value(s.type)
+                       << ".";
+            d->type = static_cast<FieldSupportedValues::Type>(s.type);
+            if (!objcpy(&d->range, s.range)) {
+                LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+                return false;
+            }
         }
-        d->values.resize(s.values.size());
         copyVector<uint64_t>(&d->values, s.values);
-        return Status::OK;
     }
+    return true;
 }
 
 // FieldSupportedValues::Range -> C2FieldSupportedValues::range's type
-void objcpy(
+bool objcpy(
         decltype(C2FieldSupportedValues::range)* d,
         const FieldSupportedValues::Range& s) {
     d->min.u64 = static_cast<uint64_t>(s.min);
@@ -157,19 +177,23 @@
     d->step.u64 = static_cast<uint64_t>(s.step);
     d->num.u64 = static_cast<uint64_t>(s.num);
     d->denom.u64 = static_cast<uint64_t>(s.denom);
+    return true;
 }
 
 // FieldSupportedValues -> C2FieldSupportedValues
-c2_status_t objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
     switch (s.type) {
     case FieldSupportedValues::Type::EMPTY:
         d->type = C2FieldSupportedValues::EMPTY;
-        return C2_OK;
+        break;
     case FieldSupportedValues::Type::RANGE:
         d->type = C2FieldSupportedValues::RANGE;
-        objcpy(&d->range, s.range);
+        if (!objcpy(&d->range, s.range)) {
+            LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+            return false;
+        }
         d->values.resize(0);
-        return C2_OK;
+        break;
     default:
         switch (s.type) {
         case FieldSupportedValues::Type::VALUES:
@@ -179,22 +203,30 @@
             d->type = C2FieldSupportedValues::FLAGS;
             break;
         default:
-            d->type = static_cast<C2FieldSupportedValues::type_t>(s.typeOther);
-            // Copy all fields in this case
-            objcpy(&d->range, s.range);
+            LOG(DEBUG) << "Unrecognized FieldSupportedValues::Type "
+                       << "with underlying value " << underlying_value(s.type)
+                       << ".";
+            d->type = static_cast<C2FieldSupportedValues::type_t>(s.type);
+            if (!objcpy(&d->range, s.range)) {
+                LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+                return false;
+            }
         }
         copyVector<uint64_t>(&d->values, s.values);
-        return C2_OK;
     }
+    return true;
 }
 
 } // unnamed namespace
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQuery* d,
         const C2FieldSupportedValuesQuery& s) {
-    objcpy(&d->field, s.field());
+    if (!objcpy(&d->field, s.field())) {
+        LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+        return false;
+    }
     switch (s.type()) {
     case C2FieldSupportedValuesQuery::POSSIBLE:
         d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
@@ -203,15 +235,16 @@
         d->type = FieldSupportedValuesQuery::Type::CURRENT;
         break;
     default:
-        ALOGE("Unknown type of C2FieldSupportedValuesQuery: %u",
-                static_cast<unsigned>(s.type()));
-        return Status::BAD_VALUE;
+        LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+                   << "with underlying value " << underlying_value(s.type())
+                   << ".";
+        d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
     }
-    return Status::OK;
+    return true;
 }
 
 // FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& s) {
     C2FieldSupportedValuesQuery::type_t dType;
@@ -223,16 +256,17 @@
         dType = C2FieldSupportedValuesQuery::CURRENT;
         break;
     default:
-        ALOGE("Unknown type of FieldSupportedValuesQuery: %u",
-                static_cast<unsigned>(s.type));
-        return C2_BAD_VALUE;
+        LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+                   << "with underlying value " << underlying_value(s.type)
+                   << ".";
+        dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
     }
     *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
-    return C2_OK;
+    return true;
 }
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQueryResult* d,
         const C2FieldSupportedValuesQuery& s) {
     d->status = static_cast<Status>(s.status);
@@ -241,20 +275,24 @@
 
 // FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
 // C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& sq,
         const FieldSupportedValuesQueryResult& sr) {
-    c2_status_t status = objcpy(d, sq);
-    if (status != C2_OK) {
-        return status;
+    if (!objcpy(d, sq)) {
+        LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+        return false;
     }
     d->status = static_cast<c2_status_t>(sr.status);
-    return objcpy(&d->values, sr.values);
+    if (!objcpy(&d->values, sr.values)) {
+        LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+        return false;
+    }
+    return true;
 }
 
 // C2Component::Traits -> IComponentStore::ComponentTraits
-Status objcpy(
+bool objcpy(
         IComponentStore::ComponentTraits *d,
         const C2Component::Traits &s) {
     d->name = s.name;
@@ -266,10 +304,19 @@
     case C2Component::DOMAIN_AUDIO:
         d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
         break;
-    default:
+    case C2Component::DOMAIN_IMAGE:
+        d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
+        break;
+    case C2Component::DOMAIN_OTHER:
         d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+        break;
+    default:
+        LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+                   << "with underlying value " << underlying_value(s.domain)
+                   << ".";
+        d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
+                s.domain);
     }
-    d->domainOther = static_cast<uint32_t>(s.domain);
 
     switch (s.kind) {
     case C2Component::KIND_DECODER:
@@ -278,10 +325,16 @@
     case C2Component::KIND_ENCODER:
         d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
         break;
-    default:
+    case C2Component::KIND_OTHER:
         d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+        break;
+    default:
+        LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+                   << "with underlying value " << underlying_value(s.kind)
+                   << ".";
+        d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
+                s.kind);
     }
-    d->kindOther = static_cast<uint32_t>(s.kind);
 
     d->rank = static_cast<uint32_t>(s.rank);
 
@@ -292,11 +345,11 @@
         --ix;
         d->aliases[ix] = s.aliases[ix];
     }
-    return Status::OK;
+    return true;
 }
 
 // ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
-c2_status_t objcpy(
+bool objcpy(
         C2Component::Traits* d,
         std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
         const IComponentStore::ComponentTraits& s) {
@@ -309,8 +362,17 @@
     case IComponentStore::ComponentTraits::Domain::AUDIO:
         d->domain = C2Component::DOMAIN_AUDIO;
         break;
+    case IComponentStore::ComponentTraits::Domain::IMAGE:
+        d->domain = C2Component::DOMAIN_IMAGE;
+        break;
+    case IComponentStore::ComponentTraits::Domain::OTHER:
+        d->domain = C2Component::DOMAIN_OTHER;
+        break;
     default:
-        d->domain = static_cast<C2Component::domain_t>(s.domainOther);
+        LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+                   << "with underlying value " << underlying_value(s.domain)
+                   << ".";
+        d->domain = static_cast<C2Component::domain_t>(s.domain);
     }
 
     switch (s.kind) {
@@ -320,8 +382,14 @@
     case IComponentStore::ComponentTraits::Kind::ENCODER:
         d->kind = C2Component::KIND_ENCODER;
         break;
+    case IComponentStore::ComponentTraits::Kind::OTHER:
+        d->kind = C2Component::KIND_OTHER;
+        break;
     default:
-        d->kind = static_cast<C2Component::kind_t>(s.kindOther);
+        LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+                   << "with underlying value " << underlying_value(s.kind)
+                   << ".";
+        d->kind = static_cast<C2Component::kind_t>(s.kind);
     }
 
     d->rank = static_cast<C2Component::rank_t>(s.rank);
@@ -336,52 +404,55 @@
         (**aliasesBuffer)[i] = s.aliases[i].c_str();
         d->aliases[i] = (**aliasesBuffer)[i].c_str();
     }
-    return C2_OK;
+    return true;
 }
 
 namespace /* unnamed */ {
 
 // C2ParamFieldValues -> ParamFieldValues
-Status objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
-    objcpy(&d->paramOrField, s.paramOrField);
+bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+    if (!objcpy(&d->paramOrField, s.paramOrField)) {
+        LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+        return false;
+    }
     if (s.values) {
         d->values.resize(1);
-        return objcpy(&d->values[0], *s.values);
+        if (!objcpy(&d->values[0], *s.values)) {
+            LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+            return false;
+        }
+        return true;
     }
     d->values.resize(0);
-    return Status::OK;
+    return true;
 }
 
 // ParamFieldValues -> C2ParamFieldValues
-c2_status_t objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
     d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
     if (s.values.size() == 1) {
         d->values = std::make_unique<C2FieldSupportedValues>();
-        return objcpy(d->values.get(), s.values[0]);
+        if (!objcpy(d->values.get(), s.values[0])) {
+            LOG(ERROR) << "Invalid ParamFieldValues::values.";
+            return false;
+        }
+        return true;
     } else if (s.values.size() == 0) {
         d->values.reset();
-        return C2_OK;
+        return true;
     }
-    ALOGE("Multiple FieldSupportedValues objects. "
-            "(Only one is allowed.)");
-    return C2_BAD_VALUE;
+    LOG(ERROR) << "Invalid ParamFieldValues: "
+                  "Two or more FieldSupportedValues objects exist in "
+                  "ParamFieldValues. "
+                  "Only zero or one is allowed.";
+    return false;
 }
 
 } // unnamed namespace
 
 // C2SettingResult -> SettingResult
-Status objcpy(SettingResult *d, const C2SettingResult &s) {
-    d->failureOther = static_cast<uint32_t>(s.failure);
+bool objcpy(SettingResult *d, const C2SettingResult &s) {
     switch (s.failure) {
-    case C2SettingResult::READ_ONLY:
-        d->failure = SettingResult::Failure::READ_ONLY;
-        break;
-    case C2SettingResult::MISMATCH:
-        d->failure = SettingResult::Failure::MISMATCH;
-        break;
-    case C2SettingResult::BAD_VALUE:
-        d->failure = SettingResult::Failure::BAD_VALUE;
-        break;
     case C2SettingResult::BAD_TYPE:
         d->failure = SettingResult::Failure::BAD_TYPE;
         break;
@@ -391,53 +462,61 @@
     case C2SettingResult::BAD_INDEX:
         d->failure = SettingResult::Failure::BAD_INDEX;
         break;
+    case C2SettingResult::READ_ONLY:
+        d->failure = SettingResult::Failure::READ_ONLY;
+        break;
+    case C2SettingResult::MISMATCH:
+        d->failure = SettingResult::Failure::MISMATCH;
+        break;
+    case C2SettingResult::BAD_VALUE:
+        d->failure = SettingResult::Failure::BAD_VALUE;
+        break;
     case C2SettingResult::CONFLICT:
         d->failure = SettingResult::Failure::CONFLICT;
         break;
     case C2SettingResult::UNSUPPORTED:
         d->failure = SettingResult::Failure::UNSUPPORTED;
         break;
+    case C2SettingResult::INFO_BAD_VALUE:
+        d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+        break;
     case C2SettingResult::INFO_CONFLICT:
         d->failure = SettingResult::Failure::INFO_CONFLICT;
         break;
     default:
-        d->failure = SettingResult::Failure::OTHER;
+        LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+                   << "with underlying value " << underlying_value(s.failure)
+                   << ".";
+        d->failure = static_cast<SettingResult::Failure>(s.failure);
     }
-    Status status = objcpy(&d->field, s.field);
-    if (status != Status::OK) {
-        return status;
+    if (!objcpy(&d->field, s.field)) {
+        LOG(ERROR) << "Invalid C2SettingResult::field.";
+        return false;
     }
     d->conflicts.resize(s.conflicts.size());
     size_t i = 0;
     for (const C2ParamFieldValues& sConflict : s.conflicts) {
         ParamFieldValues &dConflict = d->conflicts[i++];
-        status = objcpy(&dConflict, sConflict);
-        if (status != Status::OK) {
-            return status;
+        if (!objcpy(&dConflict, sConflict)) {
+            LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+                       << i - 1 << "].";
+            return false;
         }
     }
-    return Status::OK;
+    return true;
 }
 
 // SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
     *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
             .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
     if (!*d) {
-        return C2_NO_MEMORY;
+        LOG(ERROR) << "No memory for C2SettingResult.";
+        return false;
     }
 
     // failure
     switch (s.failure) {
-    case SettingResult::Failure::READ_ONLY:
-        (*d)->failure = C2SettingResult::READ_ONLY;
-        break;
-    case SettingResult::Failure::MISMATCH:
-        (*d)->failure = C2SettingResult::MISMATCH;
-        break;
-    case SettingResult::Failure::BAD_VALUE:
-        (*d)->failure = C2SettingResult::BAD_VALUE;
-        break;
     case SettingResult::Failure::BAD_TYPE:
         (*d)->failure = C2SettingResult::BAD_TYPE;
         break;
@@ -447,23 +526,38 @@
     case SettingResult::Failure::BAD_INDEX:
         (*d)->failure = C2SettingResult::BAD_INDEX;
         break;
+    case SettingResult::Failure::READ_ONLY:
+        (*d)->failure = C2SettingResult::READ_ONLY;
+        break;
+    case SettingResult::Failure::MISMATCH:
+        (*d)->failure = C2SettingResult::MISMATCH;
+        break;
+    case SettingResult::Failure::BAD_VALUE:
+        (*d)->failure = C2SettingResult::BAD_VALUE;
+        break;
     case SettingResult::Failure::CONFLICT:
         (*d)->failure = C2SettingResult::CONFLICT;
         break;
     case SettingResult::Failure::UNSUPPORTED:
         (*d)->failure = C2SettingResult::UNSUPPORTED;
         break;
+    case SettingResult::Failure::INFO_BAD_VALUE:
+        (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+        break;
     case SettingResult::Failure::INFO_CONFLICT:
         (*d)->failure = C2SettingResult::INFO_CONFLICT;
         break;
     default:
-        (*d)->failure = static_cast<C2SettingResult::Failure>(s.failureOther);
+        LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+                   << "with underlying value " << underlying_value(s.failure)
+                   << ".";
+        (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
     }
 
     // field
-    c2_status_t status = objcpy(&(*d)->field, s.field);
-    if (status != C2_OK) {
-        return status;
+    if (!objcpy(&(*d)->field, s.field)) {
+        LOG(ERROR) << "Invalid SettingResult::field.";
+        return false;
     }
 
     // conflicts
@@ -472,26 +566,26 @@
     for (const ParamFieldValues& sConflict : s.conflicts) {
         (*d)->conflicts.emplace_back(
                 C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
-        status = objcpy(&(*d)->conflicts.back(), sConflict);
-        if (status != C2_OK) {
-            return status;
+        if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+            LOG(ERROR) << "Invalid SettingResult::conflicts.";
+            return false;
         }
     }
-    return C2_OK;
+    return true;
 }
 
 // C2ParamDescriptor -> ParamDescriptor
-Status objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
     d->index = static_cast<ParamIndex>(s.index());
     d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
             _C2ParamInspector::GetAttrib(s));
     d->name = s.name();
     copyVector<uint32_t>(&d->dependencies, s.dependencies());
-    return Status::OK;
+    return true;
 }
 
 // ParamDescriptor -> C2ParamDescriptor
-c2_status_t objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
     std::vector<C2Param::Index> dDependencies;
     dDependencies.reserve(s.dependencies.size());
     for (const ParamIndex& sDependency : s.dependencies) {
@@ -502,11 +596,11 @@
             static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
             C2String(s.name.c_str()),
             std::move(dDependencies));
-    return C2_OK;
+    return true;
 }
 
 // C2StructDescriptor -> StructDescriptor
-Status objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
     d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
     d->fields.resize(s.numFields());
     size_t i = 0;
@@ -518,7 +612,7 @@
                 _C2ParamInspector::GetSize(sField));
         dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
                 sField.type());
-        dField.length = static_cast<uint32_t>(sField.extent());
+        dField.extent = static_cast<uint32_t>(sField.extent());
         dField.name = static_cast<hidl_string>(sField.name());
         const auto& sNamedValues = sField.namedValues();
         dField.namedValues.resize(sNamedValues.size());
@@ -530,18 +624,18 @@
                     sNamedValue.second.u64);
         }
     }
-    return Status::OK;
+    return true;
 }
 
 // StructDescriptor -> C2StructDescriptor
-c2_status_t objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
     C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
     std::vector<C2FieldDescriptor> dFields;
     dFields.reserve(s.fields.size());
     for (const auto &sField : s.fields) {
         C2FieldDescriptor dField = {
             static_cast<uint32_t>(sField.type),
-            sField.length,
+            sField.extent,
             sField.name,
             sField.fieldId.offset,
             sField.fieldId.size };
@@ -557,7 +651,7 @@
     }
     *d = std::make_unique<C2StructDescriptor>(
             _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
-    return C2_OK;
+    return true;
 }
 
 namespace /* unnamed */ {
@@ -565,14 +659,14 @@
 // Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
 // associated map.
 // Note: The handle is not cloned.
-Status _addBaseBlock(
+bool _addBaseBlock(
         uint32_t* index,
         const C2Handle* handle,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     if (!handle) {
-        ALOGE("addBaseBlock called on a null C2Handle.");
-        return Status::BAD_VALUE;
+        LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
+        return false;
     }
     auto it = baseBlockIndices->find(handle);
     if (it != baseBlockIndices->end()) {
@@ -583,26 +677,25 @@
         baseBlocks->emplace_back();
 
         BaseBlock &dBaseBlock = baseBlocks->back();
-        dBaseBlock.type = BaseBlock::Type::NATIVE;
         // This does not clone the handle.
-        dBaseBlock.nativeBlock =
-                reinterpret_cast<const native_handle_t*>(handle);
+        dBaseBlock.nativeBlock(
+                reinterpret_cast<const native_handle_t*>(handle));
 
     }
-    return Status::OK;
+    return true;
 }
 
 // Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
 // an associated map.
-Status _addBaseBlock(
+bool _addBaseBlock(
         uint32_t* index,
         const std::shared_ptr<BufferPoolData> bpData,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     if (!bpData) {
-        ALOGE("addBaseBlock called on a null BufferPoolData.");
-        return Status::BAD_VALUE;
+        LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
+        return false;
     }
     auto it = baseBlockIndices->find(bpData.get());
     if (it != baseBlockIndices->end()) {
@@ -613,24 +706,26 @@
         baseBlocks->emplace_back();
 
         BaseBlock &dBaseBlock = baseBlocks->back();
-        dBaseBlock.type = BaseBlock::Type::POOLED;
 
         if (bufferPoolSender) {
+            BufferStatusMessage pooledBlock;
             ResultStatus bpStatus = bufferPoolSender->send(
                     bpData,
-                    &dBaseBlock.pooledBlock);
+                    &pooledBlock);
 
             if (bpStatus != ResultStatus::OK) {
-                ALOGE("Failed to send buffer with BufferPool. Error: %d.",
-                        static_cast<int>(bpStatus));
-                return Status::BAD_VALUE;
+                LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
+                           << static_cast<int32_t>(bpStatus)
+                           << ".";
+                return false;
             }
+            dBaseBlock.pooledBlock(pooledBlock);
         }
     }
-    return Status::OK;
+    return true;
 }
 
-Status addBaseBlock(
+bool addBaseBlock(
         uint32_t* index,
         const C2Handle* handle,
         const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
@@ -649,8 +744,8 @@
             std::shared_ptr<BufferPoolData> bpData;
             if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
                     || !bpData) {
-                ALOGE("BufferPoolData unavailable in a block.");
-                return Status::BAD_VALUE;
+                LOG(ERROR) << "BufferPoolData unavailable in a block.";
+                return false;
             }
             return _addBaseBlock(
                     index, bpData,
@@ -662,69 +757,76 @@
                 index, handle,
                 baseBlocks, baseBlockIndices);
     default:
-        ALOGE("Unknown C2BlockPoolData type.");
-        return Status::BAD_VALUE;
+        LOG(ERROR) << "Unknown C2BlockPoolData type.";
+        return false;
     }
 }
 
 // C2Fence -> hidl_handle
 // Note: File descriptors are not duplicated. The original file descriptor must
 // not be closed before the transaction is complete.
-Status objcpy(hidl_handle* d, const C2Fence& s) {
+bool objcpy(hidl_handle* d, const C2Fence& s) {
     (void)s; // TODO: implement s.fd()
     int fenceFd = -1;
     d->setTo(nullptr);
     if (fenceFd >= 0) {
         native_handle_t *handle = native_handle_create(1, 0);
         if (!handle) {
-            return Status::NO_MEMORY;
+            LOG(ERROR) << "Failed to create a native handle.";
+            return false;
         }
         handle->data[0] = fenceFd;
         d->setTo(handle, true /* owns */);
     }
-    return Status::OK;
+    return true;
 }
 
 // C2ConstLinearBlock -> Block
 // Note: Native handles are not duplicated. The original handles must not be
 // closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstLinearBlock& s,
+bool objcpy(Block* d, const C2ConstLinearBlock& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     std::shared_ptr<const _C2BlockPoolData> bpData =
             _C2BlockFactory::GetLinearBlockPoolData(s);
-    Status status = addBaseBlock(&d->index, s.handle(), bpData,
-            bufferPoolSender, baseBlocks, baseBlockIndices);
-    if (status != Status::OK) {
-        return status;
+    if (!addBaseBlock(&d->index, s.handle(), bpData,
+            bufferPoolSender, baseBlocks, baseBlockIndices)) {
+        LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
+        return false;
     }
 
     // Create the metadata.
     C2Hidl_RangeInfo dRangeInfo;
     dRangeInfo.offset = static_cast<uint32_t>(s.offset());
     dRangeInfo.length = static_cast<uint32_t>(s.size());
-    status = createParamsBlob(&d->meta,
-            std::vector<C2Param*>{ &dRangeInfo });
-    if (status != Status::OK) {
-        return Status::BAD_VALUE;
+    if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
+        LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
+        return false;
     }
 
     // Copy the fence
-    return objcpy(&d->fence, s.fence());
+    if (!objcpy(&d->fence, s.fence())) {
+        LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
+        return false;
+    }
+    return true;
 }
 
 // C2ConstGraphicBlock -> Block
 // Note: Native handles are not duplicated. The original handles must not be
 // closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstGraphicBlock& s,
+bool objcpy(Block* d, const C2ConstGraphicBlock& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     std::shared_ptr<const _C2BlockPoolData> bpData =
             _C2BlockFactory::GetGraphicBlockPoolData(s);
-    Status status = addBaseBlock(&d->index, s.handle(), bpData,
-            bufferPoolSender, baseBlocks, baseBlockIndices);
+    if (!addBaseBlock(&d->index, s.handle(), bpData,
+            bufferPoolSender, baseBlocks, baseBlockIndices)) {
+        LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
+        return false;
+    }
 
     // Create the metadata.
     C2Hidl_RectInfo dRectInfo;
@@ -733,62 +835,70 @@
     dRectInfo.top = static_cast<uint32_t>(sRect.top);
     dRectInfo.width = static_cast<uint32_t>(sRect.width);
     dRectInfo.height = static_cast<uint32_t>(sRect.height);
-    status = createParamsBlob(&d->meta,
-            std::vector<C2Param*>{ &dRectInfo });
-    if (status != Status::OK) {
-        return Status::BAD_VALUE;
+    if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
+        LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
+        return false;
     }
 
     // Copy the fence
-    return objcpy(&d->fence, s.fence());
+    if (!objcpy(&d->fence, s.fence())) {
+        LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
+        return false;
+    }
+    return true;
 }
 
 // C2BufferData -> Buffer
 // This function only fills in d->blocks.
-Status objcpy(Buffer* d, const C2BufferData& s,
+bool objcpy(Buffer* d, const C2BufferData& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
-    Status status;
     d->blocks.resize(
             s.linearBlocks().size() +
             s.graphicBlocks().size());
     size_t i = 0;
     for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
         Block& dBlock = d->blocks[i++];
-        status = objcpy(
+        if (!objcpy(
                 &dBlock, linearBlock,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
+                       << "(Destination index = " << i - 1 << ".)";
+            return false;
         }
     }
     for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
         Block& dBlock = d->blocks[i++];
-        status = objcpy(
+        if (!objcpy(
                 &dBlock, graphicBlock,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
+                       << "(Destination index = " << i - 1 << ".)";
+            return false;
         }
     }
-    return Status::OK;
+    return true;
 }
 
 // C2Buffer -> Buffer
-Status objcpy(Buffer* d, const C2Buffer& s,
+bool objcpy(Buffer* d, const C2Buffer& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
-    Status status = createParamsBlob(&d->info, s.info());
-    if (status != Status::OK) {
-        return status;
+    if (!createParamsBlob(&d->info, s.info())) {
+        LOG(ERROR) << "Invalid C2Buffer::info.";
+        return false;
     }
-    return objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices);
+    if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+        LOG(ERROR) << "Invalid C2Buffer::data.";
+        return false;
+    }
+    return true;
 }
 
 // C2InfoBuffer -> InfoBuffer
-Status objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
@@ -798,24 +908,21 @@
     (void)bufferPoolSender;
     (void)baseBlocks;
     (void)baseBlockIndices;
-    return Status::OK;
-    /*
-    // Stub implementation that may work in the future.
-    d->index = static_cast<uint32_t>(s.index());
-    d->buffer.info.resize(0);
-    return objcpy(&d->buffer, s.data(), baseBlocks, baseBlockIndices);
-    */
+    LOG(INFO) << "InfoBuffer not implemented.";
+    return true;
 }
 
 // C2FrameData -> FrameData
-Status objcpy(FrameData* d, const C2FrameData& s,
+bool objcpy(FrameData* d, const C2FrameData& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
-    objcpy(&d->ordinal, s.ordinal);
+    if (!objcpy(&d->ordinal, s.ordinal)) {
+        LOG(ERROR) << "Invalid C2FrameData::ordinal.";
+        return false;
+    }
 
-    Status status;
     d->buffers.resize(s.buffers.size());
     size_t i = 0;
     for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
@@ -827,17 +934,18 @@
             dBuffer.blocks.resize(0);
             continue;
         }
-        status = objcpy(
+        if (!objcpy(
                 &dBuffer, *sBuffer,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2FrameData::buffers["
+                       << i - 1 << "].";
+            return false;
         }
     }
 
-    status = createParamsBlob(&d->configUpdate, s.configUpdate);
-    if (status != Status::OK) {
-        return status;
+    if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
+        LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
+        return false;
     }
 
     d->infoBuffers.resize(s.infoBuffers.size());
@@ -845,17 +953,19 @@
     for (const std::shared_ptr<C2InfoBuffer>& sInfoBuffer : s.infoBuffers) {
         InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
         if (!sInfoBuffer) {
-            ALOGE("Null C2InfoBuffer");
-            return Status::BAD_VALUE;
+            LOG(ERROR) << "Null C2FrameData::infoBuffers["
+                       << i - 1 << "].";
+            return false;
         }
-        status = objcpy(&dInfoBuffer, *sInfoBuffer,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+        if (!objcpy(&dInfoBuffer, *sInfoBuffer,
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
+                       << i - 1 << "].";
+            return false;
         }
     }
 
-    return status;
+    return true;
 }
 
 } // unnamed namespace
@@ -885,7 +995,7 @@
         const std::shared_ptr<BufferPoolData>& bpData,
         BufferStatusMessage* bpMessage) {
     if (!mReceiverManager) {
-        ALOGE("No access to receiver's BufferPool.");
+        LOG(ERROR) << "No access to receiver's BufferPool.";
         return ResultStatus::NOT_FOUND;
     }
     ResultStatus rs;
@@ -893,7 +1003,7 @@
     if (!mSenderManager) {
         mSenderManager = ClientManager::getInstance();
         if (!mSenderManager) {
-            ALOGE("Failed to retrieve local BufferPool ClientManager.");
+            LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
             return ResultStatus::CRITICAL_ERROR;
         }
     }
@@ -915,11 +1025,11 @@
                                             connectionId,
                                             &receiverConnectionId);
         if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
-            ALOGW("registerSender -- returned error: %d.",
-                    static_cast<int>(rs));
+            LOG(WARNING) << "registerSender -- returned error: "
+                         << static_cast<int32_t>(rs)
+                         << ".";
             return rs;
         } else {
-            ALOGV("registerSender -- succeeded.");
             mReceiverConnectionId = receiverConnectionId;
         }
     }
@@ -929,12 +1039,13 @@
     rs = mSenderManager->postSend(
             mReceiverConnectionId, bpData, &transactionId, &timestampUs);
     if (rs != ResultStatus::OK) {
-        ALOGE("ClientManager::postSend -- returned error: %d.",
-                static_cast<int>(rs));
+        LOG(ERROR) << "ClientManager::postSend -- returned error: "
+                   << static_cast<int32_t>(rs)
+                   << ".";
         return rs;
     }
     if (!bpMessage) {
-        ALOGE("Null output parameter for BufferStatusMessage.");
+        LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
         return ResultStatus::CRITICAL_ERROR;
     }
     bpMessage->connectionId = mReceiverConnectionId;
@@ -946,12 +1057,10 @@
 }
 
 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
-Status objcpy(
+bool objcpy(
         WorkBundle* d,
         const std::list<std::unique_ptr<C2Work>>& s,
         BufferPoolSender* bufferPoolSender) {
-    Status status = Status::OK;
-
     // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
     std::list<BaseBlock> baseBlocks;
 
@@ -971,63 +1080,80 @@
     for (const std::unique_ptr<C2Work>& sWork : s) {
         Work &dWork = d->works[i++];
         if (!sWork) {
-            ALOGW("Null C2Work encountered.");
+            LOG(WARNING) << "Null C2Work encountered.";
             continue;
         }
-        status = objcpy(&dWork.input, sWork->input,
-                bufferPoolSender, &baseBlocks, &baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+
+        // chain info is not in use currently.
+
+        // input
+        if (!objcpy(&dWork.input, sWork->input,
+                bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2Work::input.";
+            return false;
         }
+
+        // worklets
         if (sWork->worklets.size() == 0) {
-            ALOGW("Work with no worklets.");
+            LOG(DEBUG) << "Work with no worklets.";
         } else {
-            if (sWork->worklets.size() > 1) {
-                ALOGW("Work with multiple worklets. "
-                        "Only the first worklet will be marshalled.");
-            }
-            if (!sWork->worklets.front()) {
-                ALOGE("Null worklet encountered.");
-                return Status::BAD_VALUE;
-            }
-
-            // Parcel the first worklet.
-            const C2Worklet &sWorklet = *sWork->worklets.front();
-            Worklet &dWorklet = dWork.worklet;
-
-            dWorklet.tunings.resize(sWorklet.tunings.size());
+            // Parcel the worklets.
+            hidl_vec<Worklet> &dWorklets = dWork.worklets;
+            dWorklets.resize(sWork->worklets.size());
             size_t j = 0;
-            for (const std::unique_ptr<C2Tuning>& sTuning : sWorklet.tunings) {
-                status = createParamsBlob(
-                        &dWorklet.tunings[j++],
-                        std::vector<C2Param*>
-                        { reinterpret_cast<C2Param*>(sTuning.get()) });
-                if (status != Status::OK) {
-                    return status;
+            for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
+            {
+                if (!sWorklet) {
+                    LOG(WARNING) << "Null C2Work::worklets["
+                                 << j << "].";
+                    continue;
                 }
-            }
+                Worklet &dWorklet = dWorklets[j++];
 
-            dWorklet.failures.resize(sWorklet.failures.size());
-            j = 0;
-            for (const std::unique_ptr<C2SettingResult>& sFailure :
-                    sWorklet.failures) {
-                if (!sFailure) {
-                    ALOGE("Null C2SettingResult");
-                    return Status::BAD_VALUE;
-                }
-                status = objcpy(&dWorklet.failures[j++], *sFailure);
-                if (status != Status::OK) {
-                    return status;
-                }
-            }
+                // component id
+                dWorklet.componentId = static_cast<uint32_t>(
+                        sWorklet->component);
 
-            status = objcpy(&dWorklet.output, sWorklet.output,
-                    bufferPoolSender, &baseBlocks, &baseBlockIndices);
-            if (status != Status::OK) {
-                return status;
+                // tunings
+                if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
+                    LOG(ERROR) << "Invalid C2Work::worklets["
+                               << j - 1 << "]->tunings.";
+                    return false;
+                }
+
+                // failures
+                dWorklet.failures.resize(sWorklet->failures.size());
+                size_t k = 0;
+                for (const std::unique_ptr<C2SettingResult>& sFailure :
+                        sWorklet->failures) {
+                    if (!sFailure) {
+                        LOG(WARNING) << "Null C2Work::worklets["
+                                     << j - 1 << "]->failures["
+                                     << k << "].";
+                        continue;
+                    }
+                    if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
+                        LOG(ERROR) << "Invalid C2Work::worklets["
+                                   << j - 1 << "]->failures["
+                                   << k - 1 << "].";
+                        return false;
+                    }
+                }
+
+                // output
+                if (!objcpy(&dWorklet.output, sWorklet->output,
+                        bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+                    LOG(ERROR) << "Invalid C2Work::worklets["
+                               << j - 1 << "]->output.";
+                    return false;
+                }
             }
         }
-        dWork.workletProcessed = sWork->workletsProcessed > 0;
+
+        // worklets processed
+        dWork.workletsProcessed = sWork->workletsProcessed;
+
+        // result
         dWork.result = static_cast<Status>(sWork->result);
     }
 
@@ -1040,7 +1166,7 @@
         }
     }
 
-    return Status::OK;
+    return true;
 }
 
 namespace /* unnamed */ {
@@ -1058,15 +1184,15 @@
 // hidl_handle -> C2Fence
 // Note: File descriptors are not duplicated. The original file descriptor must
 // not be closed before the transaction is complete.
-c2_status_t objcpy(C2Fence* d, const hidl_handle& s) {
+bool objcpy(C2Fence* d, const hidl_handle& s) {
     // TODO: Implement.
     (void)s;
     *d = C2Fence();
-    return C2_OK;
+    return true;
 }
 
 // C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
-c2_status_t createLinearBuffer(
+bool createLinearBuffer(
         std::shared_ptr<C2Buffer>* buffer,
         const std::shared_ptr<C2LinearBlock>& block,
         const std::vector<C2Param*>& meta,
@@ -1074,12 +1200,12 @@
     // Check the block meta. It should have exactly 1 C2Info:
     // C2Hidl_RangeInfo.
     if ((meta.size() != 1) || !meta[0]) {
-        ALOGE("Invalid block metadata for ion block.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid C2LinearBlock::meta.";
+        return false;
     }
     if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
-        ALOGE("Invalid block metadata for ion block: range.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid range info in C2LinearBlock.";
+        return false;
     }
     C2Hidl_RangeInfo *rangeInfo =
             reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
@@ -1089,14 +1215,14 @@
             rangeInfo->offset, rangeInfo->length,
             fence));
     if (!(*buffer)) {
-        ALOGE("Cannot create a linear buffer.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "CreateLinearBuffer failed.";
+        return false;
     }
-    return C2_OK;
+    return true;
 }
 
 // C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
-c2_status_t createGraphicBuffer(
+bool createGraphicBuffer(
         std::shared_ptr<C2Buffer>* buffer,
         const std::shared_ptr<C2GraphicBlock>& block,
         const std::vector<C2Param*>& meta,
@@ -1104,12 +1230,12 @@
     // Check the block meta. It should have exactly 1 C2Info:
     // C2Hidl_RectInfo.
     if ((meta.size() != 1) || !meta[0]) {
-        ALOGE("Invalid block metadata for graphic block.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
+        return false;
     }
     if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
-        ALOGE("Invalid block metadata for graphic block: crop rect.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
+        return false;
     }
     C2Hidl_RectInfo *rectInfo =
             reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
@@ -1120,136 +1246,144 @@
             at(rectInfo->left, rectInfo->top),
             fence));
     if (!(*buffer)) {
-        ALOGE("Cannot create a graphic buffer.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "CreateGraphicBuffer failed.";
+        return false;
     }
-    return C2_OK;
+    return true;
 }
 
 // Buffer -> C2Buffer
 // Note: The native handles will be cloned.
-c2_status_t objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
         const std::vector<C2BaseBlock>& baseBlocks) {
-    c2_status_t status;
     *d = nullptr;
 
     // Currently, a non-null C2Buffer must contain exactly 1 block.
     if (s.blocks.size() == 0) {
-        return C2_OK;
+        return true;
     } else if (s.blocks.size() != 1) {
-        ALOGE("Currently, a C2Buffer must contain exactly 1 block.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid Buffer: "
+                      "Currently, a C2Buffer must contain exactly 1 block.";
+        return false;
     }
 
     const Block &sBlock = s.blocks[0];
     if (sBlock.index >= baseBlocks.size()) {
-        ALOGE("Index into baseBlocks is out of range.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
+                      "Array index out of range.";
+        return false;
     }
     const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
 
     // Parse meta.
     std::vector<C2Param*> sBlockMeta;
-    status = parseParamsBlob(&sBlockMeta, sBlock.meta);
-    if (status != C2_OK) {
-        ALOGE("Invalid block params blob.");
-        return C2_BAD_VALUE;
+    if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+        LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
+        return false;
     }
 
     // Copy fence.
     C2Fence dFence;
-    status = objcpy(&dFence, sBlock.fence);
+    if (!objcpy(&dFence, sBlock.fence)) {
+        LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
+        return false;
+    }
 
     // Construct a block.
     switch (baseBlock.type) {
     case C2BaseBlock::LINEAR:
-        status = createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence);
+        if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
+            LOG(ERROR) << "Invalid C2BaseBlock::linear.";
+            return false;
+        }
         break;
     case C2BaseBlock::GRAPHIC:
-        status = createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence);
+        if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
+            LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
+            return false;
+        }
         break;
     default:
-        ALOGE("Invalid BaseBlock type.");
-        return C2_BAD_VALUE;
-    }
-    if (status != C2_OK) {
-        return status;
+        LOG(ERROR) << "Invalid C2BaseBlock::type.";
+        return false;
     }
 
     // Parse info
     std::vector<C2Param*> params;
-    status = parseParamsBlob(&params, s.info);
-    if (status != C2_OK) {
-        ALOGE("Invalid buffer params blob.");
-        return status;
+    if (!parseParamsBlob(&params, s.info)) {
+        LOG(ERROR) << "Invalid Buffer::info.";
+        return false;
     }
     for (C2Param* param : params) {
         if (param == nullptr) {
-            ALOGE("Null buffer param encountered.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Null param in Buffer::info.";
+            return false;
         }
-        std::shared_ptr<C2Param> c2param(
-                C2Param::Copy(*param).release());
+        std::shared_ptr<C2Param> c2param{
+                C2Param::Copy(*param).release()};
         if (!c2param) {
-            ALOGE("Invalid buffer param inside a blob.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Invalid param in Buffer::info.";
+            return false;
         }
-        status = (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+        c2_status_t status =
+                (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
         if (status != C2_OK) {
-            ALOGE("C2Buffer::setInfo failed().");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "C2Buffer::setInfo failed.";
+            return false;
         }
     }
 
-    return C2_OK;
+    return true;
 }
 
 // FrameData -> C2FrameData
-c2_status_t objcpy(C2FrameData* d, const FrameData& s,
+bool objcpy(C2FrameData* d, const FrameData& s,
         const std::vector<C2BaseBlock>& baseBlocks) {
-    c2_status_t status;
     d->flags = static_cast<C2FrameData::flags_t>(s.flags);
-    objcpy(&d->ordinal, s.ordinal);
+    if (!objcpy(&d->ordinal, s.ordinal)) {
+        LOG(ERROR) << "Invalid FrameData::ordinal.";
+        return false;
+    }
     d->buffers.clear();
     d->buffers.reserve(s.buffers.size());
     for (const Buffer& sBuffer : s.buffers) {
         std::shared_ptr<C2Buffer> dBuffer;
-        status = objcpy(&dBuffer, sBuffer, baseBlocks);
-        if (status != C2_OK) {
-            return status;
+        if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
+            LOG(ERROR) << "Invalid FrameData::buffers.";
+            return false;
         }
         d->buffers.emplace_back(dBuffer);
     }
 
     std::vector<C2Param*> params;
-    status = parseParamsBlob(&params, s.configUpdate);
-    if (status != C2_OK) {
-        ALOGE("Failed to parse frame data params.");
-        return status;
+    if (!parseParamsBlob(&params, s.configUpdate)) {
+        LOG(ERROR) << "Invalid FrameData::configUpdate.";
+        return false;
     }
     d->configUpdate.clear();
     for (C2Param* param : params) {
         d->configUpdate.emplace_back(C2Param::Copy(*param));
         if (!d->configUpdate.back()) {
-            ALOGE("Unexpected error while parsing frame data params.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Unexpected error while parsing "
+                          "FrameData::configUpdate.";
+            return false;
         }
     }
 
     // TODO: Implement this once C2InfoBuffer has constructors.
     d->infoBuffers.clear();
-    return C2_OK;
+    return true;
 }
 
 // BaseBlock -> C2BaseBlock
-c2_status_t objcpy(C2BaseBlock* d, const BaseBlock& s) {
-    switch (s.type) {
-    case BaseBlock::Type::NATIVE: {
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+    switch (s.getDiscriminator()) {
+    case BaseBlock::hidl_discriminator::nativeBlock: {
             native_handle_t* sHandle =
-                    native_handle_clone(s.nativeBlock);
+                    native_handle_clone(s.nativeBlock());
             if (sHandle == nullptr) {
-                ALOGE("Null native handle in a block.");
-                return C2_BAD_VALUE;
+                LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+                return false;
             }
             const C2Handle *sC2Handle =
                     reinterpret_cast<const C2Handle*>(sHandle);
@@ -1257,25 +1391,25 @@
             d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
             if (d->linear) {
                 d->type = C2BaseBlock::LINEAR;
-                return C2_OK;
+                return true;
             }
 
             d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
             if (d->graphic) {
                 d->type = C2BaseBlock::GRAPHIC;
-                return C2_OK;
+                return true;
             }
 
-            ALOGE("Unknown handle type in native BaseBlock.");
+            LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
             if (sHandle) {
                 native_handle_close(sHandle);
                 native_handle_delete(sHandle);
             }
-            return C2_BAD_VALUE;
+            return false;
         }
-    case BaseBlock::Type::POOLED: {
+    case BaseBlock::hidl_discriminator::pooledBlock: {
             const BufferStatusMessage &bpMessage =
-                    s.pooledBlock;
+                    s.pooledBlock();
             sp<ClientManager> bp = ClientManager::getInstance();
             std::shared_ptr<BufferPoolData> bpData;
             native_handle_t *cHandle;
@@ -1287,48 +1421,49 @@
                     &cHandle,
                     &bpData);
             if (bpStatus != ResultStatus::OK) {
-                ALOGE("Failed to receive buffer from bufferpool -- "
-                        "resultStatus = %d",
-                        static_cast<int>(bpStatus));
-                return toC2Status(bpStatus);
+                LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+                           << "resultStatus = " << underlying_value(bpStatus)
+                           << ".";
+                return false;
             } else if (!bpData) {
-                ALOGE("No data in bufferpool transaction.");
-                return C2_BAD_VALUE;
+                LOG(ERROR) << "No data in bufferpool transaction.";
+                return false;
             }
 
             d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
             if (d->linear) {
                 d->type = C2BaseBlock::LINEAR;
-                return C2_OK;
+                return true;
             }
 
             d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
             if (d->graphic) {
                 d->type = C2BaseBlock::GRAPHIC;
-                return C2_OK;
+                return true;
             }
 
-            ALOGE("Unknown handle type in pooled BaseBlock.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+            return false;
         }
     default:
-        ALOGE("Corrupted BaseBlock type: %d", static_cast<int>(s.type));
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+                   << "underlying value "
+                   << underlying_value(s.getDiscriminator()) << ".";
+        return false;
     }
 }
 
 } // unnamed namespace
 
 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
-c2_status_t objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
-    c2_status_t status;
-
+bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
     // Convert BaseBlocks to C2BaseBlocks.
     std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
     for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
-        status = objcpy(&dBaseBlocks[i], s.baseBlocks[i]);
-        if (status != C2_OK) {
-            return status;
+        if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
+            LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
+                       << i << "].";
+            return false;
         }
     }
 
@@ -1337,74 +1472,58 @@
         d->emplace_back(std::make_unique<C2Work>());
         C2Work& dWork = *d->back();
 
+        // chain info is not in use currently.
+
         // input
-        status = objcpy(&dWork.input, sWork.input, dBaseBlocks);
-        if (status != C2_OK) {
-            ALOGE("Error constructing C2Work's input.");
-            return C2_BAD_VALUE;
+        if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
+            LOG(ERROR) << "Invalid Work::input.";
+            return false;
         }
 
         // worklet(s)
         dWork.worklets.clear();
-        // TODO: Currently, tunneling is not supported.
-        if (sWork.workletProcessed) {
-            dWork.workletsProcessed = 1;
-
-            const Worklet &sWorklet = sWork.worklet;
+        for (const Worklet& sWorklet : sWork.worklets) {
             std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
 
+            // component id
+            dWorklet->component = static_cast<c2_node_id_t>(
+                    sWorklet.componentId);
+
             // tunings
-            dWorklet->tunings.clear();
-            dWorklet->tunings.reserve(sWorklet.tunings.size());
-            for (const Params& sTuning : sWorklet.tunings) {
-                std::vector<C2Param*> dParams;
-                status = parseParamsBlob(&dParams, sTuning);
-                if (status != C2_OK) {
-                    ALOGE("Failed to parse C2Tuning in C2Worklet.");
-                    return C2_BAD_VALUE;
-                }
-                for (C2Param* param : dParams) {
-                    std::unique_ptr<C2Param> dParam = C2Param::Copy(*param);
-                    if (!dParam) {
-                        ALOGE("Null C2Tuning encountered while "
-                                "parsing C2Worklet.");
-                        return C2_BAD_VALUE;
-                    }
-                    dWorklet->tunings.emplace_back(
-                            std::unique_ptr<C2Tuning>(
-                            reinterpret_cast<C2Tuning*>(
-                            dParam.release())));
-                }
+            if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
+                LOG(ERROR) << "Invalid Worklet::tunings";
+                return false;
             }
+
             // failures
             dWorklet->failures.clear();
             dWorklet->failures.reserve(sWorklet.failures.size());
             for (const SettingResult& sFailure : sWorklet.failures) {
                 std::unique_ptr<C2SettingResult> dFailure;
-                status = objcpy(&dFailure, sFailure);
-                if (status != C2_OK) {
-                    ALOGE("Failed to create C2SettingResult in C2Worklet.");
-                    return C2_BAD_VALUE;
+                if (!objcpy(&dFailure, sFailure)) {
+                    LOG(ERROR) << "Invalid Worklet::failures.";
+                    return false;
                 }
                 dWorklet->failures.emplace_back(std::move(dFailure));
             }
+
             // output
-            status = objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks);
-            if (status != C2_OK) {
-                ALOGE("Failed to create output C2FrameData.");
-                return C2_BAD_VALUE;
+            if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
+                LOG(ERROR) << "Invalid Worklet::output.";
+                return false;
             }
+
             dWork.worklets.emplace_back(std::move(dWorklet));
-        } else {
-            dWork.worklets.emplace_back(std::make_unique<C2Worklet>());
-            dWork.workletsProcessed = 0;
         }
 
+        // workletsProcessed
+        dWork.workletsProcessed = sWork.workletsProcessed;
+
         // result
         dWork.result = static_cast<c2_status_t>(sWork.result);
     }
 
-    return C2_OK;
+    return true;
 }
 
 constexpr size_t PARAMS_ALIGNMENT = 8;  // 64-bit alignment
@@ -1413,7 +1532,7 @@
 static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
 
 // Params -> std::vector<C2Param*>
-c2_status_t parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
     // assuming blob is const here
     size_t size = blob.size();
     size_t ix = 0;
@@ -1429,21 +1548,27 @@
         }
     } while (p);
 
-    return ix == size ? C2_OK : C2_BAD_VALUE;
+    if (ix != size) {
+        LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+        return false;
+    }
+    return true;
 }
 
 namespace /* unnamed */ {
 
 /**
- * Concatenates a list of C2Params into a params blob.
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
  * \param[out] blob target blob
  * \param[in] params parameters to concatenate
  * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- *         not const)
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ *         happens if the parameters were not const)
  */
-template<typename T>
-Status _createParamsBlob(hidl_vec<uint8_t> *blob, const T &params) {
+template <typename T>
+bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T &params) {
     // assuming the parameter values are const
     size_t size = 0;
     for (const auto &p : params) {
@@ -1469,77 +1594,106 @@
         ix = align(ix, PARAMS_ALIGNMENT);
     }
     blob->resize(ix);
-    return ix == size ? Status::OK : Status::CORRUPTED;
+    if (ix != size) {
+        LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+        return false;
+    }
+    return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename T>
+bool _copyParamsFromBlob(
+        std::vector<std::unique_ptr<T>>* params,
+        Params blob) {
+
+    std::vector<C2Param*> paramPointers;
+    if (!parseParamsBlob(&paramPointers, blob)) {
+        LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+        return false;
+    }
+
+    params->resize(paramPointers.size());
+    size_t i = 0;
+    for (C2Param* const& paramPointer : paramPointers) {
+        if (!paramPointer) {
+            LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+            return false;
+        }
+        (*params)[i++].reset(reinterpret_cast<T*>(
+                C2Param::Copy(*paramPointer).release()));
+    }
+    return true;
 }
 
 } // unnamed namespace
 
 // std::vector<const C2Param*> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<const C2Param*> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<C2Param*> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<C2Param*> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<std::unique_ptr<C2Param>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Param>> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<std::unique_ptr<C2Tuning>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Tuning>> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<std::shared_ptr<const C2Info>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::shared_ptr<const C2Info>> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // Params -> std::vector<std::unique_ptr<C2Param>>
-c2_status_t copyParamsFromBlob(
+bool copyParamsFromBlob(
         std::vector<std::unique_ptr<C2Param>>* params,
         Params blob) {
-    std::vector<C2Param*> paramPointers;
-    c2_status_t status = parseParamsBlob(&paramPointers, blob);
-    if (status != C2_OK) {
-        ALOGE("copyParamsFromBlob -- blob parsing failed.");
-        return status;
-    }
-    params->resize(paramPointers.size());
-    size_t i = 0;
-    for (C2Param* const& paramPointer : paramPointers) {
-        if (!paramPointer) {
-            ALOGE("copyParamsFromBlob -- corrupted params blob.");
-            return C2_BAD_VALUE;
-        }
-        (*params)[i++] = C2Param::Copy(*paramPointer);
-    }
-    return C2_OK;
+    return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool copyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Tuning>>* params,
+        Params blob) {
+    return _copyParamsFromBlob(params, blob);
 }
 
 // Params -> update std::vector<std::unique_ptr<C2Param>>
-c2_status_t updateParamsFromBlob(
+bool updateParamsFromBlob(
         const std::vector<C2Param*>& params,
         const Params& blob) {
     std::unordered_map<uint32_t, C2Param*> index2param;
     for (C2Param* const& param : params) {
         if (!param) {
-            ALOGE("updateParamsFromBlob -- corrupted input params.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+            return false;
         }
         if (index2param.find(param->index()) == index2param.end()) {
             index2param.emplace(param->index(), param);
@@ -1547,33 +1701,31 @@
     }
 
     std::vector<C2Param*> paramPointers;
-    c2_status_t status = parseParamsBlob(&paramPointers, blob);
-    if (status != C2_OK) {
-        ALOGE("updateParamsFromBlob -- blob parsing failed.");
-        return status;
+    if (!parseParamsBlob(&paramPointers, blob)) {
+        LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+        return false;
     }
 
     for (C2Param* const& paramPointer : paramPointers) {
         if (!paramPointer) {
-            ALOGE("updateParamsFromBlob -- corrupted param in blob.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+            return false;
         }
         decltype(index2param)::iterator i = index2param.find(
                 paramPointer->index());
         if (i == index2param.end()) {
-            ALOGW("updateParamsFromBlob -- unseen param index.");
+            LOG(DEBUG) << "updateParamsFromBlob -- index "
+                       << paramPointer->index() << " not found. Skipping...";
             continue;
         }
         if (!i->second->updateFrom(*paramPointer)) {
-            ALOGE("updateParamsFromBlob -- mismatching sizes: "
-                    "%u vs %u (index = %u).",
-                    static_cast<unsigned>(params.size()),
-                    static_cast<unsigned>(paramPointer->size()),
-                    static_cast<unsigned>(i->first));
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+                       << params.size() << " vs " << paramPointer->size()
+                       << " (index = " << i->first << ").";
+            return false;
         }
     }
-    return C2_OK;
+    return true;
 }
 
 // Convert BufferPool ResultStatus to c2_status_t.
@@ -1590,7 +1742,8 @@
     case ResultStatus::CRITICAL_ERROR:
         return C2_CORRUPTED;
     default:
-        ALOGW("Unrecognized BufferPool ResultStatus: %d", static_cast<int>(rs));
+        LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
+                     << static_cast<int32_t>(rs) << ".";
         return C2_CORRUPTED;
     }
 }
@@ -1669,34 +1822,33 @@
                              uint32_t generation,
                              int32_t* bqSlot) {
     if (!igbp) {
-        ALOGW("attachToBufferQueue -- null producer.");
+        LOG(WARNING) << "attachToBufferQueue -- null producer.";
         return NO_INIT;
     }
 
     sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
     graphicBuffer->setGenerationNumber(generation);
 
-    ALOGV("attachToBufferQueue -- attaching buffer: "
-            "block dimension %ux%u, "
-            "graphicBuffer dimension %ux%u, "
-            "format %#x, usage %#llx, stride %u, generation %u.",
-            static_cast<unsigned>(block.width()),
-            static_cast<unsigned>(block.height()),
-            static_cast<unsigned>(graphicBuffer->getWidth()),
-            static_cast<unsigned>(graphicBuffer->getHeight()),
-            static_cast<unsigned>(graphicBuffer->getPixelFormat()),
-            static_cast<unsigned long long>(graphicBuffer->getUsage()),
-            static_cast<unsigned>(graphicBuffer->getStride()),
-            static_cast<unsigned>(graphicBuffer->getGenerationNumber()));
+    LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
+            << " block dimension " << block.width() << "x"
+                                   << block.height()
+            << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
+                                           << graphicBuffer->getHeight()
+            << std::hex << std::setfill('0')
+            << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
+            << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
+            << std::dec << std::setfill(' ')
+            << ", stride " << graphicBuffer->getStride()
+            << ", generation " << graphicBuffer->getGenerationNumber();
 
     status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
     if (result != OK) {
-        ALOGW("attachToBufferQueue -- attachBuffer failed. Error code = %d",
-                static_cast<int>(result));
+        LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+                        "status = " << result << ".";
         return result;
     }
-    ALOGV("attachToBufferQueue -- attachBuffer returned slot %d",
-            static_cast<int>(*bqSlot));
+    LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+                 << *bqSlot << ".";
     return OK;
 }
 
@@ -1747,11 +1899,11 @@
 
     // If the block's bqId is the same as the desired bqId, just hold.
     if ((oldId == bqId) && (oldGeneration == generation)) {
-        ALOGV("holdBufferQueueBlock -- import without attaching: "
-                "bqId %llu, bqSlot %d, generation %u.",
-                static_cast<long long unsigned>(oldId),
-                static_cast<int>(oldSlot),
-                static_cast<unsigned>(generation));
+        LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
+                     << " bqId " << oldId
+                     << ", bqSlot " << oldSlot
+                     << ", generation " << generation
+                     << ".";
         _C2BlockFactory::HoldBlockFromBufferQueue(data, getHgbp(igbp));
         return true;
     }
@@ -1765,19 +1917,18 @@
     status_t result = attachToBufferQueue(block, igbp, generation, &bqSlot);
 
     if (result != OK) {
-        ALOGE("holdBufferQueueBlock -- fail to attach: "
-                "target bqId %llu, generation %u.",
-                static_cast<long long unsigned>(bqId),
-                static_cast<unsigned>(generation));
-
+        LOG(ERROR) << "holdBufferQueueBlock -- fail to attach:"
+                   << " target bqId " << bqId
+                   << ", generation " << generation
+                   << ".";
         return false;
     }
 
-    ALOGV("holdBufferQueueBlock -- attached: "
-            "bqId %llu, bqSlot %d, generation %u.",
-            static_cast<long long unsigned>(bqId),
-            static_cast<int>(bqSlot),
-            static_cast<unsigned>(generation));
+    LOG(VERBOSE) << "holdBufferQueueBlock -- attached:"
+                 << " bqId " << bqId
+                 << ", bqSlot " << bqSlot
+                 << ", generation " << generation
+                 << ".";
     _C2BlockFactory::AssignBlockToBufferQueue(
             data, getHgbp(igbp), generation, bqId, bqSlot, true);
     return true;
diff --git a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h b/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h
index a688530..d1557cb 100644
--- a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h
@@ -94,10 +94,14 @@
         (void)buffer;
     }
 
-    virtual void onFramesRendered(
-        const std::vector<RenderedFrame>& renderedFrames) override {
+    virtual void onFrameRendered(
+        uint64_t bufferQueueId,
+        int32_t slotId,
+        int64_t timestampNs) override {
         /* TODO */
-        (void)renderedFrames;
+        (void)bufferQueueId;
+        (void)slotId;
+        (void)timestampNs;
     }
     // std::mutex mQueueLock;
     // std::condition_variable mQueueCondition;
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index cd374b0..5b52fcd 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,7 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2Client"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/client.h>
 
@@ -32,7 +32,6 @@
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <hidl/HidlSupport.h>
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
-#undef LOG
 
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
 #include <android/hardware/media/c2/1.0/IComponent.h>
@@ -99,19 +98,17 @@
     return mName;
 }
 
-Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
 Codec2ConfigurableClient::Codec2ConfigurableClient(
-        const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
-    Return<void> transStatus = base->getName(
-            [this](const hidl_string& name) {
-                mName = name.c_str();
-            });
-    if (!transStatus.isOk()) {
-        ALOGE("Cannot obtain name from IConfigurable.");
-    }
+        const sp<IConfigurable>& base)
+      : mBase{base},
+        mName{[base]() -> C2String {
+                C2String outName;
+                Return<void> transStatus = base->getName(
+                        [&outName](const hidl_string& name) {
+                            outName = name.c_str();
+                        });
+                return transStatus.isOk() ? outName : "";
+            }()} {
 }
 
 c2_status_t Codec2ConfigurableClient::query(
@@ -124,7 +121,7 @@
     size_t numIndices = 0;
     for (C2Param* const& stackParam : stackParams) {
         if (!stackParam) {
-            ALOGW("query -- null stack param encountered.");
+            LOG(WARNING) << "query -- null stack param encountered.";
             continue;
         }
         indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
@@ -139,32 +136,31 @@
         heapParams->reserve(heapParams->size() + numIndices);
     }
     c2_status_t status;
-    Return<void> transStatus = base()->query(
+    Return<void> transStatus = mBase->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) {
-                    ALOGE("query -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "query -- call failed: "
+                               << status << ".";
                     return;
                 }
                 std::vector<C2Param*> paramPointers;
-                c2_status_t parseStatus = parseParamsBlob(&paramPointers, p);
-                if (parseStatus != C2_OK) {
-                    ALOGE("query -- error while parsing params. "
-                            "Error code = %d", static_cast<int>(status));
-                    status = parseStatus;
+                if (!parseParamsBlob(&paramPointers, p)) {
+                    LOG(ERROR) << "query -- error while parsing params.";
+                    status = C2_CORRUPTED;
                     return;
                 }
                 size_t i = 0;
-                for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
+                for (auto it = paramPointers.begin();
+                        it != paramPointers.end(); ) {
                     C2Param* paramPointer = *it;
                     if (numStackIndices > 0) {
                         --numStackIndices;
                         if (!paramPointer) {
-                            ALOGW("query -- null stack param.");
+                            LOG(WARNING) << "query -- null stack param.";
                             ++it;
                             continue;
                         }
@@ -172,37 +168,41 @@
                             ++i;
                         }
                         if (i >= stackParams.size()) {
-                            ALOGE("query -- unexpected error.");
+                            LOG(ERROR) << "query -- unexpected error.";
                             status = C2_CORRUPTED;
                             return;
                         }
                         if (stackParams[i]->index() != paramPointer->index()) {
-                            ALOGW("query -- param skipped. index = %d",
-                                    static_cast<int>(stackParams[i]->index()));
+                            LOG(WARNING) << "query -- param skipped: "
+                                            "index = "
+                                         << stackParams[i]->index() << ".";
                             stackParams[i++]->invalidate();
                             continue;
                         }
                         if (!stackParams[i++]->updateFrom(*paramPointer)) {
-                            ALOGW("query -- param update failed. index = %d",
-                                    static_cast<int>(paramPointer->index()));
+                            LOG(WARNING) << "query -- param update failed: "
+                                            "index = "
+                                         << paramPointer->index() << ".";
                         }
                     } else {
                         if (!paramPointer) {
-                            ALOGW("query -- null heap param.");
+                            LOG(WARNING) << "query -- null heap param.";
                             ++it;
                             continue;
                         }
                         if (!heapParams) {
-                            ALOGW("query -- unexpected extra stack param.");
+                            LOG(WARNING) << "query -- "
+                                            "unexpected extra stack param.";
                         } else {
-                            heapParams->emplace_back(C2Param::Copy(*paramPointer));
+                            heapParams->emplace_back(
+                                    C2Param::Copy(*paramPointer));
                         }
                     }
                     ++it;
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("query -- transaction failed.");
+        LOG(ERROR) << "query -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -213,13 +213,12 @@
         c2_blocking_t mayBlock,
         std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
     Params hidlParams;
-    Status hidlStatus = createParamsBlob(&hidlParams, params);
-    if (hidlStatus != Status::OK) {
-        ALOGE("config -- bad input.");
+    if (!createParamsBlob(&hidlParams, params)) {
+        LOG(ERROR) << "config -- bad input.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status;
-    Return<void> transStatus = base()->config(
+    Return<void> transStatus = mBase->config(
             hidlParams,
             mayBlock == C2_MAY_BLOCK,
             [&status, &params, failures](
@@ -227,24 +226,27 @@
                     const hidl_vec<SettingResult> f,
                     const Params& o) {
                 status = static_cast<c2_status_t>(s);
-                if (status != C2_OK) {
-                    ALOGD("config -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                if (status != C2_OK && status != C2_BAD_INDEX) {
+                    LOG(DEBUG) << "config -- call failed: "
+                               << status << ".";
                 }
                 size_t i = failures->size();
                 failures->resize(i + f.size());
                 for (const SettingResult& sf : f) {
-                    status = objcpy(&(*failures)[i++], sf);
-                    if (status != C2_OK) {
-                        ALOGE("config -- invalid returned SettingResult. "
-                                "Error code = %d", static_cast<int>(status));
+                    if (!objcpy(&(*failures)[i++], sf)) {
+                        LOG(ERROR) << "config -- "
+                                   << "invalid SettingResult returned.";
                         return;
                     }
                 }
-                status = updateParamsFromBlob(params, o);
+                if (!updateParamsFromBlob(params, o)) {
+                    LOG(ERROR) << "config -- "
+                               << "failed to parse returned params.";
+                    status = C2_CORRUPTED;
+                }
             });
     if (!transStatus.isOk()) {
-        ALOGE("config -- transaction failed.");
+        LOG(ERROR) << "config -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -254,7 +256,7 @@
         std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
     // TODO: Cache and query properly!
     c2_status_t status;
-    Return<void> transStatus = base()->querySupportedParams(
+    Return<void> transStatus = mBase->querySupportedParams(
             std::numeric_limits<uint32_t>::min(),
             std::numeric_limits<uint32_t>::max(),
             [&status, params](
@@ -262,24 +264,22 @@
                     const hidl_vec<ParamDescriptor>& p) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("querySupportedParams -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "querySupportedParams -- call failed: "
+                               << status << ".";
                     return;
                 }
                 size_t i = params->size();
                 params->resize(i + p.size());
                 for (const ParamDescriptor& sp : p) {
-                    status = objcpy(&(*params)[i++], sp);
-                    if (status != C2_OK) {
-                        ALOGE("querySupportedParams -- "
-                                "invalid returned ParamDescriptor. "
-                                "Error code = %d", static_cast<int>(status));
+                    if (!objcpy(&(*params)[i++], sp)) {
+                        LOG(ERROR) << "querySupportedParams -- "
+                                   << "invalid returned ParamDescriptor.";
                         return;
                     }
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("querySupportedParams -- transaction failed.");
+        LOG(ERROR) << "querySupportedParams -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -290,15 +290,14 @@
         c2_blocking_t mayBlock) const {
     hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
     for (size_t i = 0; i < fields.size(); ++i) {
-        Status hidlStatus = objcpy(&inFields[i], fields[i]);
-        if (hidlStatus != Status::OK) {
-            ALOGE("querySupportedValues -- bad input");
+        if (!objcpy(&inFields[i], fields[i])) {
+            LOG(ERROR) << "querySupportedValues -- bad input";
             return C2_TRANSACTION_FAILED;
         }
     }
 
     c2_status_t status;
-    Return<void> transStatus = base()->querySupportedValues(
+    Return<void> transStatus = mBase->querySupportedValues(
             inFields,
             mayBlock == C2_MAY_BLOCK,
             [&status, &inFields, &fields](
@@ -306,27 +305,28 @@
                     const hidl_vec<FieldSupportedValuesQueryResult>& r) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("querySupportedValues -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "querySupportedValues -- call failed: "
+                               << status << ".";
                     return;
                 }
                 if (r.size() != fields.size()) {
-                    ALOGE("querySupportedValues -- input and output lists "
-                            "have different sizes.");
+                    LOG(ERROR) << "querySupportedValues -- "
+                                  "input and output lists "
+                                  "have different sizes.";
                     status = C2_CORRUPTED;
                     return;
                 }
                 for (size_t i = 0; i < fields.size(); ++i) {
-                    status = objcpy(&fields[i], inFields[i], r[i]);
-                    if (status != C2_OK) {
-                        ALOGE("querySupportedValues -- invalid returned value. "
-                                "Error code = %d", static_cast<int>(status));
+                    if (!objcpy(&fields[i], inFields[i], r[i])) {
+                        LOG(ERROR) << "querySupportedValues -- "
+                                      "invalid returned value.";
+                        status = C2_CORRUPTED;
                         return;
                     }
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("querySupportedValues -- transaction failed.");
+        LOG(ERROR) << "querySupportedValues -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -339,22 +339,24 @@
 
     virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
         std::list<std::unique_ptr<C2Work>> workItems;
-        c2_status_t status = objcpy(&workItems, workBundle);
-        if (status != C2_OK) {
-            ALOGI("onWorkDone -- received corrupted WorkBundle. "
-                    "status = %d.", static_cast<int>(status));
+        if (!objcpy(&workItems, workBundle)) {
+            LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
             return Void();
         }
         // release input buffers potentially held by the component from queue
         size_t numDiscardedInputBuffers = 0;
-        std::shared_ptr<Codec2Client::Component> strongComponent = component.lock();
+        std::shared_ptr<Codec2Client::Component> strongComponent =
+                component.lock();
         if (strongComponent) {
-            numDiscardedInputBuffers = strongComponent->handleOnWorkDone(workItems);
+            numDiscardedInputBuffers =
+                    strongComponent->handleOnWorkDone(workItems);
         }
         if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
-            listener->onWorkDone(component, workItems, numDiscardedInputBuffers);
+            listener->onWorkDone(component,
+                                 workItems,
+                                 numDiscardedInputBuffers);
         } else {
-            ALOGD("onWorkDone -- listener died.");
+            LOG(DEBUG) << "onWorkDone -- listener died.";
         }
         return Void();
     }
@@ -363,13 +365,10 @@
             const hidl_vec<SettingResult>& settingResults) override {
         std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
                 settingResults.size());
-        c2_status_t status;
         for (size_t i = 0; i < settingResults.size(); ++i) {
             std::unique_ptr<C2SettingResult> c2SettingResult;
-            status = objcpy(&c2SettingResult, settingResults[i]);
-            if (status != C2_OK) {
-                ALOGI("onTripped -- received corrupted SettingResult. "
-                        "status = %d.", static_cast<int>(status));
+            if (!objcpy(&c2SettingResult, settingResults[i])) {
+                LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
                 return Void();
             }
             c2SettingResults[i] = std::move(c2SettingResult);
@@ -377,20 +376,21 @@
         if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
             listener->onTripped(component, c2SettingResults);
         } else {
-            ALOGD("onTripped -- listener died.");
+            LOG(DEBUG) << "onTripped -- listener died.";
         }
         return Void();
     }
 
     virtual Return<void> onError(Status s, uint32_t errorCode) override {
-        ALOGD("onError -- status = %d, errorCode = %u.",
-                static_cast<int>(s),
-                static_cast<unsigned>(errorCode));
+        LOG(DEBUG) << "onError --"
+                   << " status = " << s
+                   << ", errorCode = " << errorCode
+                   << ".";
         if (std::shared_ptr<Listener> listener = base.lock()) {
             listener->onError(component, s == Status::OK ?
                     errorCode : static_cast<c2_status_t>(s));
         } else {
-            ALOGD("onError -- listener died.");
+            LOG(DEBUG) << "onError -- listener died.";
         }
         return Void();
     }
@@ -398,55 +398,70 @@
     virtual Return<void> onFramesRendered(
             const hidl_vec<RenderedFrame>& renderedFrames) override {
         std::shared_ptr<Listener> listener = base.lock();
-        std::vector<Codec2Client::Listener::RenderedFrame> rfs;
-        rfs.reserve(renderedFrames.size());
-        for (const RenderedFrame& rf : renderedFrames) {
-            if (rf.slotId >= 0) {
-                if (listener) {
-                    rfs.emplace_back(rf.bufferQueueId,
-                                     rf.slotId,
-                                     rf.timestampNs);
-                }
-            } else {
-                std::shared_ptr<Codec2Client::Component> strongComponent =
-                        component.lock();
-                if (strongComponent) {
-                    uint64_t frameIndex = rf.bufferQueueId;
-                    size_t bufferIndex = static_cast<size_t>(~rf.slotId);
-                    ALOGV("Received death notification of input buffer: "
-                          "frameIndex = %llu, bufferIndex = %zu.",
-                          static_cast<long long unsigned>(frameIndex),
-                          bufferIndex);
-                    std::shared_ptr<C2Buffer> buffer =
-                            strongComponent->freeInputBuffer(
-                                frameIndex, bufferIndex);
-                    if (buffer) {
-                        listener->onInputBufferDone(buffer);
-                    }
-                }
-            }
+        if (!listener) {
+            LOG(DEBUG) << "onFramesRendered -- listener died.";
+            return Void();
         }
-        if (!rfs.empty()) {
-            if (listener) {
-                listener->onFramesRendered(rfs);
-            } else {
-                ALOGD("onFramesRendered -- listener died.");
+        for (const RenderedFrame& renderedFrame : renderedFrames) {
+            listener->onFrameRendered(
+                    renderedFrame.bufferQueueId,
+                    renderedFrame.slotId,
+                    renderedFrame.timestampNs);
+        }
+        return Void();
+    }
+
+    virtual Return<void> onInputBuffersReleased(
+            const hidl_vec<InputBuffer>& inputBuffers) override {
+        std::shared_ptr<Listener> listener = base.lock();
+        if (!listener) {
+            LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
+            return Void();
+        }
+        std::shared_ptr<Codec2Client::Component> strongComponent =
+                component.lock();
+        if (!strongComponent) {
+            LOG(DEBUG) << "onInputBuffersReleased -- component died.";
+            return Void();
+        }
+        for (const InputBuffer& inputBuffer : inputBuffers) {
+            std::shared_ptr<C2Buffer> buffer =
+                    strongComponent->freeInputBuffer(
+                        inputBuffer.frameIndex,
+                        inputBuffer.arrayIndex);
+            LOG(VERBOSE) << "onInputBuffersReleased --"
+                            " received death notification of"
+                            " input buffer:"
+                            " frameIndex = " << inputBuffer.frameIndex
+                         << ", bufferIndex = " << inputBuffer.arrayIndex
+                         << ".";
+            if (buffer) {
+                listener->onInputBufferDone(buffer);
             }
         }
         return Void();
     }
+
 };
 
 // Codec2Client
-Codec2Client::Base* Codec2Client::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base, std::string instanceName) :
-    Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) {
+Codec2Client::Codec2Client(const sp<IComponentStore>& base,
+                           std::string serviceName)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base},
+        mListed{false},
+        mServiceName{serviceName} {
     Return<sp<IClientManager>> transResult = base->getPoolClientManager();
     if (!transResult.isOk()) {
-        ALOGE("getPoolClientManager -- failed transaction.");
+        LOG(ERROR) << "getPoolClientManager -- transaction failed.";
     } else {
         mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
     }
@@ -457,13 +472,10 @@
         const std::shared_ptr<Codec2Client::Listener>& listener,
         std::shared_ptr<Codec2Client::Component>* const component) {
 
-    // TODO: Add support for Bufferpool
-
-
     c2_status_t status;
-    sp<Component::HidlListener> hidlListener = new Component::HidlListener();
+    sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
     hidlListener->base = listener;
-    Return<void> transStatus = base()->createComponent(
+    Return<void> transStatus = mBase->createComponent(
             name,
             hidlListener,
             ClientManager::getInstance(),
@@ -478,23 +490,24 @@
                 hidlListener->component = *component;
             });
     if (!transStatus.isOk()) {
-        ALOGE("createComponent -- failed transaction.");
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- transaction failed.";
         return C2_TRANSACTION_FAILED;
-    }
-
-    if (status != C2_OK) {
+    } else if (status != C2_OK) {
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- call failed: " << status << ".";
         return status;
-    }
-
-    if (!*component) {
-        ALOGE("createComponent -- null component.");
+    } else if (!*component) {
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- null component.";
         return C2_CORRUPTED;
     }
 
     status = (*component)->setDeathListener(*component, listener);
     if (status != C2_OK) {
-        ALOGE("createComponent -- setDeathListener returned error: %d.",
-                static_cast<int>(status));
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- failed to set up death listener: "
+                   << status << ".";
     }
 
     (*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
@@ -505,44 +518,51 @@
         const C2String& name,
         std::shared_ptr<Codec2Client::Interface>* const interface) {
     c2_status_t status;
-    Return<void> transStatus = base()->createInterface(
+    Return<void> transStatus = mBase->createInterface(
             name,
             [&status, interface](
                     Status s,
                     const sp<IComponentInterface>& i) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("createInterface -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
                     return;
                 }
-                *interface = std::make_shared<Codec2Client::Interface>(i);
+                *interface = std::make_shared<Interface>(i);
             });
     if (!transStatus.isOk()) {
-        ALOGE("createInterface -- failed transaction.");
+        LOG(ERROR) << "createInterface(" << name.c_str()
+                   << ") -- transaction failed.";
         return C2_TRANSACTION_FAILED;
+    } else if (status != C2_OK) {
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- call failed: " << status << ".";
+        return status;
     }
+
     return status;
 }
 
 c2_status_t Codec2Client::createInputSurface(
-        std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) {
-    Return<sp<IInputSurface>> transResult = base()->createInputSurface();
-    if (!transResult.isOk()) {
-        ALOGE("createInputSurface -- failed transaction.");
+        std::shared_ptr<InputSurface>* const inputSurface) {
+    c2_status_t status;
+    Return<void> transStatus = mBase->createInputSurface(
+            [&status, inputSurface](
+                    Status s,
+                    const sp<IInputSurface>& i) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                *inputSurface = std::make_shared<InputSurface>(i);
+            });
+    if (!transStatus.isOk()) {
+        LOG(ERROR) << "createInputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
+    } else if (status != C2_OK) {
+        LOG(DEBUG) << "createInputSurface -- call failed: "
+                   << status << ".";
     }
-    sp<IInputSurface> result = static_cast<sp<IInputSurface>>(transResult);
-    if (!result) {
-        *inputSurface = nullptr;
-        return C2_OK;
-    }
-    *inputSurface = std::make_shared<InputSurface>(result);
-    if (!*inputSurface) {
-        ALOGE("createInputSurface -- unknown error.");
-        return C2_CORRUPTED;
-    }
-    return C2_OK;
+    return status;
 }
 
 const std::vector<C2Component::Traits>& Codec2Client::listComponents() const {
@@ -550,22 +570,26 @@
     if (mListed) {
         return mTraitsList;
     }
-    Return<void> transStatus = base()->listComponents(
-            [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
+    Return<void> transStatus = mBase->listComponents(
+            [this](Status s,
+                   const hidl_vec<IComponentStore::ComponentTraits>& t) {
+                if (s != Status::OK) {
+                    LOG(DEBUG) << "listComponents -- call failed: "
+                               << static_cast<c2_status_t>(s) << ".";
+                    return;
+                }
                 mTraitsList.resize(t.size());
                 mAliasesBuffer.resize(t.size());
                 for (size_t i = 0; i < t.size(); ++i) {
-                    c2_status_t status = objcpy(
-                            &mTraitsList[i], &mAliasesBuffer[i], t[i]);
-                    mTraitsList[i].owner = mInstanceName;
-                    if (status != C2_OK) {
-                        ALOGE("listComponents -- corrupted output.");
+                    if (!objcpy(&mTraitsList[i], &mAliasesBuffer[i], t[i])) {
+                        LOG(ERROR) << "listComponents -- corrupted output.";
                         return;
                     }
+                    mTraitsList[i].owner = mServiceName;
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("listComponents -- failed transaction.");
+        LOG(ERROR) << "listComponents -- transaction failed.";
     }
     mListed = true;
     return mTraitsList;
@@ -577,7 +601,7 @@
     // TODO: Implement?
     (void)src;
     (void)dst;
-    ALOGE("copyBuffer not implemented");
+    LOG(ERROR) << "copyBuffer not implemented";
     return C2_OMITTED;
 }
 
@@ -597,21 +621,25 @@
                             const hidl_vec<StructDescriptor>& sd) {
                         c2_status_t status = static_cast<c2_status_t>(s);
                         if (status != C2_OK) {
-                            ALOGE("getStructDescriptors -- call failed. "
-                                    "Error code = %d", static_cast<int>(status));
+                            LOG(DEBUG) << "SimpleParamReflector -- "
+                                          "getStructDescriptors() failed: "
+                                       << status << ".";
                             descriptor.reset();
                             return;
                         }
                         if (sd.size() != 1) {
-                            ALOGD("getStructDescriptors -- returned vector of size %zu.",
-                                    sd.size());
+                            LOG(DEBUG) << "SimpleParamReflector -- "
+                                          "getStructDescriptors() "
+                                          "returned vector of size "
+                                       << sd.size() << ". "
+                                          "It should be 1.";
                             descriptor.reset();
                             return;
                         }
-                        status = objcpy(&descriptor, sd[0]);
-                        if (status != C2_OK) {
-                            ALOGD("getStructDescriptors -- failed to convert. "
-                                    "Error code = %d", static_cast<int>(status));
+                        if (!objcpy(&descriptor, sd[0])) {
+                            LOG(DEBUG) << "SimpleParamReflector -- "
+                                          "getStructDescriptors() returned "
+                                          "corrupted data.";
                             descriptor.reset();
                             return;
                         }
@@ -625,44 +653,44 @@
         sp<Base> mBase;
     };
 
-    return std::make_shared<SimpleParamReflector>(base());
+    return std::make_shared<SimpleParamReflector>(mBase);
 };
 
 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
-        const char* instanceName, bool waitForService) {
-    if (!instanceName) {
+        const char* serviceName, bool waitForService) {
+    if (!serviceName) {
         return nullptr;
     }
     sp<Base> baseStore = waitForService ?
-            Base::getService(instanceName) :
-            Base::tryGetService(instanceName);
+            Base::getService(serviceName) :
+            Base::tryGetService(serviceName);
     if (!baseStore) {
         if (waitForService) {
-            ALOGW("Codec2.0 service \"%s\" inaccessible. "
-                  "Check the device manifest.",
-                  instanceName);
+            LOG(WARNING) << "Codec2.0 service \"" << serviceName << "\""
+                            " inaccessible. Check the device manifest.";
         } else {
-            ALOGD("Codec2.0 service \"%s\" unavailable right now. "
-                  "Try again later.",
-                  instanceName);
+            LOG(DEBUG) << "Codec2.0 service \"" << serviceName << "\""
+                          " unavailable at the moment. "
+                          " Wait or check the device manifest.";
         }
         return nullptr;
     }
-    return std::make_shared<Codec2Client>(baseStore, instanceName);
+    return std::make_shared<Codec2Client>(baseStore, serviceName);
 }
 
 c2_status_t Codec2Client::ForAllStores(
         const std::string &key,
-        std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) {
+        std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
+            predicate) {
     c2_status_t status = C2_NO_INIT;  // no IComponentStores present
 
     // Cache the mapping key -> index of Codec2Client in getClient().
     static std::mutex key2IndexMutex;
     static std::map<std::string, size_t> key2Index;
 
-    // By default try all stores. However, try the last known client first. If the last known
-    // client fails, retry once. We do this by pushing the last known client in front of the
-    // list of all clients.
+    // By default try all stores. However, try the last known client first. If
+    // the last known client fails, retry once. We do this by pushing the last
+    // known client in front of the list of all clients.
     std::deque<size_t> indices;
     for (size_t index = kNumClients; index > 0; ) {
         indices.push_front(--index);
@@ -688,7 +716,8 @@
             }
         }
         if (wasMapped) {
-            ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str());
+            LOG(INFO) << "Could not find \"" << key << "\""
+                         " in the last instance. Retrying...";
             wasMapped = false;
         }
     }
@@ -704,20 +733,27 @@
     c2_status_t status = ForAllStores(
             componentName,
             [owner, &component, componentName, &listener](
-                    const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
-                c2_status_t status = client->createComponent(componentName, listener, &component);
+                    const std::shared_ptr<Codec2Client> &client)
+                        -> c2_status_t {
+                c2_status_t status = client->createComponent(componentName,
+                                                             listener,
+                                                             &component);
                 if (status == C2_OK) {
                     if (owner) {
                         *owner = client;
                     }
                 } else if (status != C2_NOT_FOUND) {
-                    ALOGD("IComponentStore(%s)::createComponent('%s') returned %s",
-                            client->getInstanceName().c_str(), componentName, asString(status));
+                    LOG(DEBUG) << "IComponentStore("
+                                   << client->getServiceName()
+                               << ")::createComponent(\"" << componentName
+                               << "\") returned status = "
+                               << status << ".";
                 }
                 return status;
             });
     if (status != C2_OK) {
-        ALOGI("Could not create component '%s' (%s)", componentName, asString(status));
+        LOG(DEBUG) << "Could not create component \"" << componentName << "\". "
+                      "Status = " << status << ".";
     }
     return component;
 }
@@ -730,20 +766,26 @@
     c2_status_t status = ForAllStores(
             interfaceName,
             [owner, &interface, interfaceName](
-                    const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
-                c2_status_t status = client->createInterface(interfaceName, &interface);
+                    const std::shared_ptr<Codec2Client> &client)
+                        -> c2_status_t {
+                c2_status_t status = client->createInterface(interfaceName,
+                                                             &interface);
                 if (status == C2_OK) {
                     if (owner) {
                         *owner = client;
                     }
                 } else if (status != C2_NOT_FOUND) {
-                    ALOGD("IComponentStore(%s)::createInterface('%s') returned %s",
-                            client->getInstanceName().c_str(), interfaceName, asString(status));
+                    LOG(DEBUG) << "IComponentStore("
+                                   << client->getServiceName()
+                               << ")::createInterface(\"" << interfaceName
+                               << "\") returned status = "
+                               << status << ".";
                 }
                 return status;
             });
     if (status != C2_OK) {
-        ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status));
+        LOG(DEBUG) << "Could not create interface \"" << interfaceName << "\". "
+                      "Status = " << status << ".";
     }
     return interface;
 }
@@ -762,7 +804,8 @@
             }
         }
     }
-    ALOGW("Could not create an input surface from any Codec2.0 services.");
+    LOG(INFO) << "Could not create an input surface "
+                 "from any Codec2.0 services.";
     return nullptr;
 }
 
@@ -798,15 +841,39 @@
 Codec2Client::Listener::~Listener() {
 }
 
-// Codec2Client::Component
-
-Codec2Client::Component::Base* Codec2Client::Component::base() const {
-    return static_cast<Base*>(mBase.get());
+// Codec2Client::Interface
+Codec2Client::Interface::Interface(const sp<Base>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base} {
 }
 
-Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
-    Codec2Client::Configurable(base),
-    mBufferPoolSender(nullptr) {
+// Codec2Client::Component
+Codec2Client::Component::Component(const sp<Base>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IComponentInterface>> transResult1 =
+                        base->getInterface();
+                if (!transResult1.isOk()) {
+                    return nullptr;
+                }
+                Return<sp<IConfigurable>> transResult2 =
+                        static_cast<sp<IComponentInterface>>(transResult1)->
+                        getConfigurable();
+                return transResult2.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult2) :
+                        nullptr;
+            }()
+        },
+        mBase{base},
+        mBufferPoolSender{nullptr} {
 }
 
 Codec2Client::Component::~Component() {
@@ -817,7 +884,7 @@
         C2BlockPool::local_id_t* blockPoolId,
         std::shared_ptr<Codec2Client::Configurable>* configurable) {
     c2_status_t status;
-    Return<void> transStatus = base()->createBlockPool(
+    Return<void> transStatus = mBase->createBlockPool(
             static_cast<uint32_t>(id),
             [&status, blockPoolId, configurable](
                     Status s,
@@ -826,15 +893,15 @@
                 status = static_cast<c2_status_t>(s);
                 configurable->reset();
                 if (status != C2_OK) {
-                    ALOGE("createBlockPool -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "createBlockPool -- call failed: "
+                               << status << ".";
                     return;
                 }
                 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
-                *configurable = std::make_shared<Codec2Client::Configurable>(c);
+                *configurable = std::make_shared<Configurable>(c);
             });
     if (!transStatus.isOk()) {
-        ALOGE("createBlockPool -- transaction failed.");
+        LOG(ERROR) << "createBlockPool -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -842,10 +909,10 @@
 
 c2_status_t Codec2Client::Component::destroyBlockPool(
         C2BlockPool::local_id_t localId) {
-    Return<Status> transResult = base()->destroyBlockPool(
+    Return<Status> transResult = mBase->destroyBlockPool(
             static_cast<uint64_t>(localId));
     if (!transResult.isOk()) {
-        ALOGE("destroyBlockPool -- transaction failed.");
+        LOG(ERROR) << "destroyBlockPool -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return static_cast<c2_status_t>(static_cast<Status>(transResult));
@@ -859,7 +926,8 @@
         if (work) {
             if (work->worklets.empty()
                     || !work->worklets.back()
-                    || (work->worklets.back()->output.flags & C2FrameData::FLAG_INCOMPLETE) == 0) {
+                    || (work->worklets.back()->output.flags &
+                        C2FrameData::FLAG_INCOMPLETE) == 0) {
                 // input is complete
                 inputDone.emplace_back(work->input.ordinal.frameIndex.peeku());
             }
@@ -872,13 +940,14 @@
         for (uint64_t inputIndex : inputDone) {
             auto it = mInputBuffers.find(inputIndex);
             if (it == mInputBuffers.end()) {
-                ALOGV("onWorkDone -- returned consumed/unknown "
-                      "input frame: index %llu",
-                        (long long)inputIndex);
+                LOG(VERBOSE) << "onWorkDone -- returned consumed/unknown "
+                                "input frame: index = "
+                             << inputIndex << ".";
             } else {
-                ALOGV("onWorkDone -- processed input frame: "
-                      "index %llu (containing %zu buffers)",
-                        (long long)inputIndex, it->second.size());
+                LOG(VERBOSE) << "onWorkDone -- processed input frame: "
+                             << inputIndex
+                             << " (containing " << it->second.size()
+                                 << " buffers).";
                 mInputBuffers.erase(it);
                 mInputBufferCount.erase(inputIndex);
                 ++numDiscardedInputBuffers;
@@ -906,21 +975,21 @@
     std::lock_guard<std::mutex> lock(mInputBuffersMutex);
     auto it = mInputBuffers.find(frameIndex);
     if (it == mInputBuffers.end()) {
-        ALOGI("freeInputBuffer -- Unrecognized input frame index %llu.",
-              static_cast<long long unsigned>(frameIndex));
+        LOG(INFO) << "freeInputBuffer -- Unrecognized input frame index "
+                  << frameIndex << ".";
         return nullptr;
     }
     if (bufferIndex >= it->second.size()) {
-        ALOGI("freeInputBuffer -- Input buffer no. %zu is invalid in "
-              "input frame index %llu.",
-              bufferIndex, static_cast<long long unsigned>(frameIndex));
+        LOG(INFO) << "freeInputBuffer -- Input buffer number " << bufferIndex
+                  << " is not valid in input with frame index " << frameIndex
+                  << ".";
         return nullptr;
     }
     buffer = it->second[bufferIndex];
     if (!buffer) {
-        ALOGI("freeInputBuffer -- Input buffer no. %zu in "
-              "input frame index %llu has already been freed.",
-              bufferIndex, static_cast<long long unsigned>(frameIndex));
+        LOG(INFO) << "freeInputBuffer -- Input buffer number " << bufferIndex
+                  << " in input with frame index " << frameIndex
+                  << " has already been freed.";
         return nullptr;
     }
     it->second[bufferIndex] = nullptr;
@@ -949,33 +1018,33 @@
             if (!res.second) {
                 // TODO: append? - for now we are replacing
                 res.first->second = work->input.buffers;
-                ALOGI("queue -- duplicate input frame: index %llu. "
-                      "Discarding the old input frame...",
-                        (long long)inputIndex);
+                LOG(INFO) << "queue -- duplicate input frame index: "
+                          << inputIndex
+                          << ". Discarding the old input frame...";
             }
             mInputBufferCount[inputIndex] = work->input.buffers.size();
-            ALOGV("queue -- queueing input frame: "
-                  "index %llu (containing %zu buffers)",
-                    (long long)inputIndex, work->input.buffers.size());
+            LOG(VERBOSE) << "queue -- queuing input frame: "
+                         << "index = " << inputIndex
+                         << ", number of buffers = "
+                             << work->input.buffers.size()
+                         << ".";
         }
     }
 
     WorkBundle workBundle;
-    Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender);
-    if (hidlStatus != Status::OK) {
-        ALOGE("queue -- bad input.");
+    if (!objcpy(&workBundle, *items, &mBufferPoolSender)) {
+        LOG(ERROR) << "queue -- bad input.";
         return C2_TRANSACTION_FAILED;
     }
-    Return<Status> transStatus = base()->queue(workBundle);
+    Return<Status> transStatus = mBase->queue(workBundle);
     if (!transStatus.isOk()) {
-        ALOGE("queue -- transaction failed.");
+        LOG(ERROR) << "queue -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("queue -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "queue -- call failed: " << status << ".";
     }
     return status;
 }
@@ -985,19 +1054,22 @@
         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 = base()->flush(
+    Return<void> transStatus = mBase->flush(
             [&status, flushedWork](
                     Status s, const WorkBundle& wb) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("flush -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "flush -- call failed: " << status << ".";
                     return;
                 }
-                status = objcpy(flushedWork, wb);
+                if (!objcpy(flushedWork, wb)) {
+                    status = C2_CORRUPTED;
+                } else {
+                    status = C2_OK;
+                }
             });
     if (!transStatus.isOk()) {
-        ALOGE("flush -- transaction failed.");
+        LOG(ERROR) << "flush -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
 
@@ -1021,13 +1093,14 @@
         std::lock_guard<std::mutex> lock(mInputBuffersMutex);
         auto it = mInputBuffers.find(flushedIndex);
         if (it == mInputBuffers.end()) {
-            ALOGV("flush -- returned consumed/unknown input frame: "
-                  "index %llu",
-                    (long long)flushedIndex);
+            LOG(VERBOSE) << "flush -- returned consumed/unknown input frame: "
+                            "index = " << flushedIndex << ".";
         } else {
-            ALOGV("flush -- returned unprocessed input frame: "
-                  "index %llu (containing %zu buffers)",
-                    (long long)flushedIndex, mInputBufferCount[flushedIndex]);
+            LOG(VERBOSE) << "flush -- returned unprocessed input frame: "
+                            "index = " << flushedIndex
+                         << ", number of buffers = "
+                             << mInputBufferCount[flushedIndex]
+                         << ".";
             mInputBuffers.erase(it);
             mInputBufferCount.erase(flushedIndex);
         }
@@ -1048,47 +1121,44 @@
 }
 
 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
-    Return<Status> transStatus = base()->drain(
+    Return<Status> transStatus = mBase->drain(
             mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
     if (!transStatus.isOk()) {
-        ALOGE("drain -- transaction failed.");
+        LOG(ERROR) << "drain -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("drain -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "drain -- call failed: " << status << ".";
     }
     return status;
 }
 
 c2_status_t Codec2Client::Component::start() {
-    Return<Status> transStatus = base()->start();
+    Return<Status> transStatus = mBase->start();
     if (!transStatus.isOk()) {
-        ALOGE("start -- transaction failed.");
+        LOG(ERROR) << "start -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("start -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "start -- call failed: " << status << ".";
     }
     return status;
 }
 
 c2_status_t Codec2Client::Component::stop() {
-    Return<Status> transStatus = base()->stop();
+    Return<Status> transStatus = mBase->stop();
     if (!transStatus.isOk()) {
-        ALOGE("stop -- transaction failed.");
+        LOG(ERROR) << "stop -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("stop -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "stop -- call failed: " << status << ".";
     }
     mInputBuffersMutex.lock();
     mInputBuffers.clear();
@@ -1098,16 +1168,15 @@
 }
 
 c2_status_t Codec2Client::Component::reset() {
-    Return<Status> transStatus = base()->reset();
+    Return<Status> transStatus = mBase->reset();
     if (!transStatus.isOk()) {
-        ALOGE("reset -- transaction failed.");
+        LOG(ERROR) << "reset -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("reset -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "reset -- call failed: " << status << ".";
     }
     mInputBuffersMutex.lock();
     mInputBuffers.clear();
@@ -1117,16 +1186,15 @@
 }
 
 c2_status_t Codec2Client::Component::release() {
-    Return<Status> transStatus = base()->release();
+    Return<Status> transStatus = mBase->release();
     if (!transStatus.isOk()) {
-        ALOGE("release -- transaction failed.");
+        LOG(ERROR) << "release -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("release -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "release -- call failed: " << status << ".";
     }
     mInputBuffersMutex.lock();
     mInputBuffers.clear();
@@ -1144,17 +1212,16 @@
         igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface);
     }
 
-    Return<Status> transStatus = base()->setOutputSurface(
+    Return<Status> transStatus = mBase->setOutputSurface(
             static_cast<uint64_t>(blockPoolId), igbp);
     if (!transStatus.isOk()) {
-        ALOGE("setOutputSurface -- transaction failed.");
+        LOG(ERROR) << "setOutputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("setOutputSurface -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
     } else {
         std::lock_guard<std::mutex> lock(mOutputBufferQueueMutex);
         if (mOutputIgbp != surface) {
@@ -1162,7 +1229,8 @@
             if (!surface) {
                 mOutputBqId = 0;
             } else if (surface->getUniqueId(&mOutputBqId) != OK) {
-                ALOGE("setOutputSurface -- cannot obtain bufferqueue id.");
+                LOG(ERROR) << "setOutputSurface -- "
+                              "cannot obtain bufferqueue id.";
             }
         }
         mOutputGeneration = generation;
@@ -1191,17 +1259,16 @@
                                                outputGeneration,
                                                &bqSlot);
         if (status != OK) {
-            ALOGW("queueToOutputSurface -- attaching failed.");
+            LOG(WARNING) << "queueToOutputSurface -- attaching failed.";
             return INVALID_OPERATION;
         }
 
         status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                          input, output);
         if (status != OK) {
-            ALOGE("queueToOutputSurface -- queueBuffer() failed "
-                    "on non-bufferqueue-based block. "
-                    "Error code = %d.",
-                    static_cast<int>(status));
+            LOG(ERROR) << "queueToOutputSurface -- queueBuffer() failed "
+                          "on non-bufferqueue-based block. "
+                          "Error = " << status << ".";
             return status;
         }
         return OK;
@@ -1214,17 +1281,17 @@
     mOutputBufferQueueMutex.unlock();
 
     if (!outputIgbp) {
-        ALOGV("queueToOutputSurface -- output surface is null.");
+        LOG(VERBOSE) << "queueToOutputSurface -- output surface is null.";
         return NO_INIT;
     }
 
     if (bqId != outputBqId || generation != outputGeneration) {
         if (!holdBufferQueueBlock(block, mOutputIgbp, mOutputBqId, mOutputGeneration)) {
-            ALOGE("queueToOutputSurface -- migration fialed");
+            LOG(ERROR) << "queueToOutputSurface -- migration failed.";
             return DEAD_OBJECT;
         }
         if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot)) {
-            ALOGE("queueToOutputSurface -- corrupted bq assignment");
+            LOG(ERROR) << "queueToOutputSurface -- corrupted bufferqueue assignment.";
             return UNKNOWN_ERROR;
         }
     }
@@ -1232,49 +1299,77 @@
     status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                               input, output);
     if (status != OK) {
-        ALOGD("queueToOutputSurface -- queueBuffer() failed "
-                "on bufferqueue-based block. "
-                "Error code = %d.",
-                static_cast<int>(status));
+        LOG(DEBUG) << "queueToOutputSurface -- queueBuffer() failed "
+                      "on bufferqueue-based block. "
+                      "Error = " << status << ".";
         return status;
     }
     if (!yieldBufferQueueBlock(block)) {
-        ALOGD("queueToOutputSurface -- cannot yield bufferqueue-based block "
-                "to the bufferqueue.");
+        LOG(DEBUG) << "queueToOutputSurface -- cannot yield "
+                      "bufferqueue-based block to the bufferqueue.";
         return UNKNOWN_ERROR;
     }
     return OK;
 }
 
-c2_status_t Codec2Client::Component::connectToOmxInputSurface(
-        const sp<HGraphicBufferProducer>& producer,
-        const sp<HGraphicBufferSource>& source) {
-    Return<Status> transStatus = base()->connectToOmxInputSurface(
-            producer, source);
+c2_status_t Codec2Client::Component::connectToInputSurface(
+        const std::shared_ptr<InputSurface>& inputSurface,
+        std::shared_ptr<InputSurfaceConnection>* connection) {
+    c2_status_t status;
+    Return<void> transStatus = mBase->connectToInputSurface(
+            inputSurface->mBase,
+            [&status, connection](
+                    Status s, const sp<IInputSurfaceConnection>& c) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    LOG(DEBUG) << "connectToInputSurface -- call failed: "
+                               << status << ".";
+                    return;
+                }
+                *connection = std::make_shared<InputSurfaceConnection>(c);
+            });
     if (!transStatus.isOk()) {
-        ALOGE("connectToOmxInputSurface -- transaction failed.");
+        LOG(ERROR) << "connectToInputSurface -- transaction failed";
         return C2_TRANSACTION_FAILED;
     }
-    c2_status_t status =
-            static_cast<c2_status_t>(static_cast<Status>(transStatus));
-    if (status != C2_OK) {
-        ALOGE("connectToOmxInputSurface -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+    return status;
+}
+
+c2_status_t Codec2Client::Component::connectToOmxInputSurface(
+        const sp<HGraphicBufferProducer>& producer,
+        const sp<HGraphicBufferSource>& source,
+        std::shared_ptr<InputSurfaceConnection>* connection) {
+    c2_status_t status;
+    Return<void> transStatus = mBase->connectToOmxInputSurface(
+            producer, source,
+            [&status, connection](
+                    Status s, const sp<IInputSurfaceConnection>& c) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    LOG(DEBUG) << "connectToOmxInputSurface -- call failed: "
+                               << status << ".";
+                    return;
+                }
+                *connection = std::make_shared<InputSurfaceConnection>(c);
+            });
+    if (!transStatus.isOk()) {
+        LOG(ERROR) << "connectToOmxInputSurface -- transaction failed.";
+        return C2_TRANSACTION_FAILED;
     }
     return status;
 }
 
 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
-    Return<Status> transStatus = base()->disconnectFromInputSurface();
+    Return<Status> transStatus = mBase->disconnectFromInputSurface();
     if (!transStatus.isOk()) {
-        ALOGE("disconnectToInputSurface -- transaction failed.");
+        LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("disconnectFromInputSurface -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "disconnectFromInputSurface -- call failed: "
+                   << status << ".";
     }
     return status;
 }
@@ -1294,7 +1389,7 @@
             if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
                 listener->onDeath(component);
             } else {
-                ALOGW("onDeath -- listener died.");
+                LOG(DEBUG) << "onDeath -- listener died.";
             }
         }
     };
@@ -1304,93 +1399,68 @@
     deathRecipient->component = component;
 
     component->mDeathRecipient = deathRecipient;
-    Return<bool> transResult = component->base()->linkToDeath(
+    Return<bool> transResult = component->mBase->linkToDeath(
             component->mDeathRecipient, 0);
     if (!transResult.isOk()) {
-        ALOGE("setDeathListener -- failed transaction: linkToDeath.");
+        LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     if (!static_cast<bool>(transResult)) {
-        ALOGE("setDeathListener -- linkToDeath call failed.");
+        LOG(DEBUG) << "setDeathListener -- linkToDeath() call failed.";
         return C2_CORRUPTED;
     }
     return C2_OK;
 }
 
 // Codec2Client::InputSurface
-
-Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) :
-    mBase(base),
-    mGraphicBufferProducer(new
+Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base},
+        mGraphicBufferProducer{new
             ::android::hardware::graphics::bufferqueue::V1_0::utils::
-            H2BGraphicBufferProducer(base)) {
+            H2BGraphicBufferProducer([base]() -> sp<HGraphicBufferProducer> {
+                Return<sp<HGraphicBufferProducer>> transResult =
+                        base->getGraphicBufferProducer();
+                return transResult.isOk() ?
+                        static_cast<sp<HGraphicBufferProducer>>(transResult) :
+                        nullptr;
+            }())} {
 }
 
-c2_status_t Codec2Client::InputSurface::connectToComponent(
-        const std::shared_ptr<Codec2Client::Component>& component,
-        std::shared_ptr<Connection>* connection) {
-    c2_status_t status;
-    Return<void> transStatus = base()->connectToComponent(
-        component->base(),
-        [&status, connection](
-                Status s,
-                const sp<IInputSurfaceConnection>& c) {
-            status = static_cast<c2_status_t>(s);
-            if (status != C2_OK) {
-                ALOGE("connectToComponent -- call failed. "
-                        "Error code = %d", static_cast<int>(status));
-                return;
-            }
-            *connection = std::make_shared<Connection>(c);
-        });
-    if (!transStatus.isOk()) {
-        ALOGE("connect -- transaction failed.");
-        return C2_TRANSACTION_FAILED;
-    }
-    return status;
-}
-
-std::shared_ptr<Codec2Client::Configurable>
-        Codec2Client::InputSurface::getConfigurable() const {
-    Return<sp<IConfigurable>> transResult = base()->getConfigurable();
-    if (!transResult.isOk()) {
-        ALOGW("getConfigurable -- transaction failed.");
-        return nullptr;
-    }
-    if (!static_cast<sp<IConfigurable>>(transResult)) {
-        ALOGW("getConfigurable -- null pointer.");
-        return nullptr;
-    }
-    return std::make_shared<Configurable>(transResult);
-}
-
-const sp<IGraphicBufferProducer>&
+sp<IGraphicBufferProducer>
         Codec2Client::InputSurface::getGraphicBufferProducer() const {
     return mGraphicBufferProducer;
 }
 
-const sp<IInputSurface>& Codec2Client::InputSurface::getHalInterface() const {
+sp<IInputSurface> Codec2Client::InputSurface::getHalInterface() const {
     return mBase;
 }
 
 // Codec2Client::InputSurfaceConnection
-
-Codec2Client::InputSurfaceConnection::Base*
-        Codec2Client::InputSurfaceConnection::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
-        const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
-    mBase(base) {
+        const sp<IInputSurfaceConnection>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base} {
 }
 
 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
-    Return<Status> transResult = base()->disconnect();
+    Return<Status> transResult = mBase->disconnect();
     return static_cast<c2_status_t>(static_cast<Status>(transResult));
 }
 
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index c48bf0c..f320ef3 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef CODEC2_HIDL_CLIENT_H_
-#define CODEC2_HIDL_CLIENT_H_
+#ifndef CODEC2_HIDL_CLIENT_H
+#define CODEC2_HIDL_CLIENT_H
 
 #include <gui/IGraphicBufferProducer.h>
 #include <codec2/hidl/1.0/types.h>
@@ -70,8 +70,8 @@
 namespace c2 {
 namespace V1_0 {
 struct IConfigurable;
-struct IComponentInterface;
 struct IComponent;
+struct IComponentInterface;
 struct IComponentStore;
 struct IInputSurface;
 struct IInputSurfaceConnection;
@@ -146,10 +146,8 @@
     Codec2ConfigurableClient(const sp<Base>& base);
 
 protected:
-    C2String mName;
     sp<Base> mBase;
-
-    Base* base() const;
+    C2String mName;
 
     friend struct Codec2Client;
 };
@@ -162,17 +160,17 @@
 
     typedef Codec2ConfigurableClient Configurable;
 
-    typedef Configurable Interface; // These two types may diverge in the future.
-
     struct Component;
 
+    struct Interface;
+
     struct InputSurface;
 
     struct InputSurfaceConnection;
 
     typedef Codec2Client Store;
 
-    std::string getInstanceName() const { return mInstanceName; }
+    std::string getServiceName() const { return mServiceName; }
 
     c2_status_t createComponent(
             const C2String& name,
@@ -195,7 +193,7 @@
     std::shared_ptr<C2ParamReflector> getParamReflector();
 
     static std::shared_ptr<Codec2Client> CreateFromService(
-            const char* instanceName,
+            const char* serviceName,
             bool waitForService = true);
 
     // Try to create a component with a given name from all known
@@ -218,10 +216,10 @@
     static std::shared_ptr<InputSurface> CreateInputSurface();
 
     // base cannot be null.
-    Codec2Client(const sp<Base>& base, std::string instanceName);
+    Codec2Client(const sp<Base>& base, std::string serviceName);
 
 protected:
-    Base* base() const;
+    sp<Base> mBase;
 
     // Finds the first store where the predicate returns OK, and returns the last
     // predicate result. Uses key to remember the last store found, and if cached,
@@ -232,7 +230,7 @@
 
     mutable std::mutex mMutex;
     mutable bool mListed;
-    std::string mInstanceName;
+    std::string mServiceName;
     mutable std::vector<C2Component::Traits> mTraitsList;
     mutable std::vector<std::unique_ptr<std::vector<std::string>>>
             mAliasesBuffer;
@@ -241,6 +239,16 @@
             mHostPoolManager;
 };
 
+struct Codec2Client::Interface : public Codec2Client::Configurable {
+
+    typedef ::android::hardware::media::c2::V1_0::IComponentInterface Base;
+
+    Interface(const sp<Base>& base);
+
+protected:
+    sp<Base> mBase;
+};
+
 struct Codec2Client::Listener {
 
     // This is called when the component produces some output.
@@ -277,28 +285,12 @@
     virtual void onInputBufferDone(
             const std::shared_ptr<C2Buffer>& buffer) = 0;
 
-    // This structure is used for transporting onFramesRendered() event to the
-    // client in the case where the output buffers are obtained from a
-    // bufferqueue.
-    struct RenderedFrame {
-        // The id of the bufferqueue.
-        uint64_t bufferQueueId;
-        // The slot of the buffer inside the bufferqueue.
-        int32_t slotId;
-        // The timestamp.
-        int64_t timestampNs;
-
-        RenderedFrame(uint64_t bufferQueueId, int32_t slotId,
-                      int64_t timestampNs)
-              : bufferQueueId(bufferQueueId),
-                slotId(slotId),
-                timestampNs(timestampNs) {}
-        RenderedFrame(const RenderedFrame&) = default;
-    };
-
-    // This is called when the component becomes aware of frames being rendered.
-    virtual void onFramesRendered(
-            const std::vector<RenderedFrame>& renderedFrames) = 0;
+    // This is called when the component becomes aware of a frame being
+    // rendered.
+    virtual void onFrameRendered(
+            uint64_t bufferQueueId,
+            int32_t slotId,
+            int64_t timestampNs) = 0;
 
     virtual ~Listener();
 
@@ -373,9 +365,15 @@
             const QueueBufferInput& input,
             QueueBufferOutput* output);
 
+    // Connect to a given InputSurface.
+    c2_status_t connectToInputSurface(
+            const std::shared_ptr<InputSurface>& inputSurface,
+            std::shared_ptr<InputSurfaceConnection>* connection);
+
     c2_status_t connectToOmxInputSurface(
             const sp<HGraphicBufferProducer>& producer,
-            const sp<HGraphicBufferSource>& source);
+            const sp<HGraphicBufferSource>& source,
+            std::shared_ptr<InputSurfaceConnection>* connection);
 
     c2_status_t disconnectFromInputSurface();
 
@@ -385,7 +383,7 @@
     ~Component();
 
 protected:
-    Base* base() const;
+    sp<Base> mBase;
 
     // Mutex for mInputBuffers and mInputBufferCount.
     mutable std::mutex mInputBuffersMutex;
@@ -428,7 +426,7 @@
 
 };
 
-struct Codec2Client::InputSurface {
+struct Codec2Client::InputSurface : public Codec2Client::Configurable {
 public:
     typedef ::android::hardware::media::c2::V1_0::IInputSurface Base;
 
@@ -439,22 +437,15 @@
 
     typedef ::android::IGraphicBufferProducer IGraphicBufferProducer;
 
-    c2_status_t connectToComponent(
-            const std::shared_ptr<Component>& component,
-            std::shared_ptr<Connection>* connection);
-
-    std::shared_ptr<Configurable> getConfigurable() const;
-
-    const sp<IGraphicBufferProducer>& getGraphicBufferProducer() const;
+    sp<IGraphicBufferProducer> getGraphicBufferProducer() const;
 
     // Return the underlying IInputSurface.
-    const sp<Base>& getHalInterface() const;
+    sp<Base> getHalInterface() const;
 
     // base cannot be null.
     InputSurface(const sp<Base>& base);
 
 protected:
-    Base* base() const;
     sp<Base> mBase;
 
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
@@ -463,7 +454,7 @@
     friend struct Component;
 };
 
-struct Codec2Client::InputSurfaceConnection {
+struct Codec2Client::InputSurfaceConnection : public Codec2Client::Configurable {
 
     typedef ::android::hardware::media::c2::V1_0::IInputSurfaceConnection Base;
 
@@ -473,7 +464,6 @@
     InputSurfaceConnection(const sp<Base>& base);
 
 protected:
-    Base* base() const;
     sp<Base> mBase;
 
     friend struct Codec2Client::InputSurface;
@@ -481,5 +471,5 @@
 
 }  // namespace android
 
-#endif  // CODEC2_HIDL_CLIENT_H_
+#endif  // CODEC2_HIDL_CLIENT_H
 
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 852d6d6..2527b00 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -143,8 +143,7 @@
         if (mConnection != nullptr) {
             return ALREADY_EXISTS;
         }
-        return toStatusT(mSurface->connectToComponent(comp, &mConnection),
-                         C2_OPERATION_InputSurface_connectToComponent);
+        return toStatusT(comp->connectToInputSurface(mSurface, &mConnection));
     }
 
     void disconnect() override {
@@ -162,7 +161,7 @@
     status_t signalEndOfInputStream() override {
         C2InputSurfaceEosTuning eos(true);
         std::vector<std::unique_ptr<C2SettingResult>> failures;
-        c2_status_t err = mSurface->getConfigurable()->config({&eos}, C2_MAY_BLOCK, &failures);
+        c2_status_t err = mSurface->config({&eos}, C2_MAY_BLOCK, &failures);
         if (err != C2_OK) {
             return UNKNOWN_ERROR;
         }
@@ -495,10 +494,13 @@
         codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL);
     }
 
-    virtual void onFramesRendered(
-            const std::vector<RenderedFrame>& renderedFrames) override {
-        // TODO
-        (void)renderedFrames;
+    virtual void onFrameRendered(uint64_t bufferQueueId,
+                                 int32_t slotId,
+                                 int64_t timestampNs) override {
+        // TODO: implement
+        (void)bufferQueueId;
+        (void)slotId;
+        (void)timestampNs;
     }
 
     virtual void onInputBufferDone(
@@ -599,7 +601,7 @@
     // set up preferred component store to access vendor store parameters
     client = Codec2Client::CreateFromService("default", false);
     if (client) {
-        ALOGI("setting up '%s' as default (vendor) store", client->getInstanceName().c_str());
+        ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str());
         SetPreferredCodec2ComponentStore(
                 std::make_shared<Codec2ClientInterfaceWrapper>(client));
     }
@@ -956,16 +958,18 @@
     std::shared_ptr<PersistentSurface> persistentSurface(CreateInputSurface());
 
     if (persistentSurface->getHidlTarget()) {
-        sp<IInputSurface> inputSurface = IInputSurface::castFrom(
+        sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
                 persistentSurface->getHidlTarget());
-        if (!inputSurface) {
+        if (!hidlInputSurface) {
             ALOGE("Corrupted input surface");
             mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
             return;
         }
+        std::shared_ptr<Codec2Client::InputSurface> inputSurface =
+                std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
         err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
-                std::make_shared<Codec2Client::InputSurface>(inputSurface)));
-        bufferProducer = new H2BGraphicBufferProducer(inputSurface);
+                inputSurface));
+        bufferProducer = inputSurface->getGraphicBufferProducer();
     } else {
         int32_t width = 0;
         (void)outputFormat->findInt32("width", &width);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index b529cbc..577aff3 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1645,6 +1645,7 @@
         work->input.ordinal.customOrdinal = timeUs;
         work->input.buffers.clear();
         work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
+        work->worklets.emplace_back(new C2Worklet);
 
         items.clear();
         items.push_back(std::move(work));