Merge "Revert "Update plugin to use cas@1.1 hal""
diff --git a/apex/Android.bp b/apex/Android.bp
index 39997d2..c077a77 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -16,21 +16,31 @@
     name: "com.android.media",
     manifest: "manifest.json",
     java_libs: ["updatable-media"],
-    native_shared_libs: [
-        // Extractor plugins
-        "libaacextractor",
-        "libamrextractor",
-        "libflacextractor",
-        "libmidiextractor",
-        "libmkvextractor",
-        "libmp3extractor",
-        "libmp4extractor",
-        "libmpeg2extractor",
-        "liboggextractor",
-        "libwavextractor",
-        // MediaPlayer2
-        "libmedia2_jni",
-    ],
+    compile_multilib: "both",
+    multilib: {
+        first: {
+            // Extractor process runs only with the primary ABI.
+            native_shared_libs: [
+                // Extractor plugins
+                "libaacextractor",
+                "libamrextractor",
+                "libflacextractor",
+                "libmidiextractor",
+                "libmkvextractor",
+                "libmp3extractor",
+                "libmp4extractor",
+                "libmpeg2extractor",
+                "liboggextractor",
+                "libwavextractor",
+            ],
+        },
+        both: {
+            native_shared_libs: [
+                // MediaPlayer2
+                "libmedia2_jni",
+            ],
+        },
+    },
     key: "com.android.media.key",
 }
 
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 641816f..c1efa5f 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -5549,6 +5549,73 @@
     ACAMERA_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = 
                                                                 // int32[n*5]
             ACAMERA_DEPTH_START + 5,
+    /**
+     * <p>The available dynamic depth dataspace stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     *
+     * <p>Type: int32[n*4] (acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_t)</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>These are output stream configurations for use with
+     * dataSpace DYNAMIC_DEPTH. The configurations are
+     * listed as <code>(format, width, height, input?)</code> tuples.</p>
+     * <p>Only devices that support depth output for at least
+     * the HAL_PIXEL_FORMAT_Y16 dense depth map along with
+     * HAL_PIXEL_FORMAT_BLOB with the same size or size with
+     * the same aspect ratio can have dynamic depth dataspace
+     * stream configuration. ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE also
+     * needs to be set to FALSE.</p>
+     *
+     * @see ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE
+     */
+    ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS = 
+                                                                // int32[n*4] (acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_t)
+            ACAMERA_DEPTH_START + 6,
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for dynamic depth output streams.</p>
+     *
+     * <p>Type: int64[4*n]</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>The minimum frame duration of a stream (of a particular format, size)
+     * is the same regardless of whether the stream is input or output.</p>
+     */
+    ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS = // int64[4*n]
+            ACAMERA_DEPTH_START + 7,
+    /**
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for dynamic depth streams.</p>
+     *
+     * <p>Type: int64[4*n]</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>All dynamic depth output streams may have a nonzero stall
+     * duration.</p>
+     */
+    ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS =     // int64[4*n]
+            ACAMERA_DEPTH_START + 8,
     ACAMERA_DEPTH_END,
 
     /**
@@ -8246,6 +8313,16 @@
 
 } acamera_metadata_enum_android_depth_depth_is_exclusive_t;
 
+// ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_depth_available_dynamic_depth_stream_configurations {
+    ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_OUTPUT
+                                                                      = 0,
+
+    ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_INPUT
+                                                                      = 1,
+
+} acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_t;
+
 
 // ACAMERA_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
 typedef enum acamera_metadata_enum_acamera_logical_multi_camera_sensor_sync_type {
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 480c7cd..84713c1 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -586,51 +586,57 @@
     return Void();
 }
 
-bool DrmHal::matchMimeTypeAndSecurityLevel(sp<IDrmFactory> &factory,
-                                           const uint8_t uuid[16],
-                                           const String8 &mimeType,
-                                           DrmPlugin::SecurityLevel level) {
-    if (mimeType == "") {
-        return true;
-    } else if (!factory->isContentTypeSupported(mimeType.string())) {
-        return false;
+status_t DrmHal::matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+                                               const uint8_t uuid[16],
+                                               const String8 &mimeType,
+                                               DrmPlugin::SecurityLevel level,
+                                               bool *isSupported) {
+    *isSupported = false;
+
+    // handle default value cases
+    if (level == DrmPlugin::kSecurityLevelUnknown) {
+        if (mimeType == "") {
+            // isCryptoSchemeSupported(uuid)
+            *isSupported = true;
+        } else {
+            // isCryptoSchemeSupported(uuid, mimeType)
+            *isSupported = factory->isContentTypeSupported(mimeType.string());
+        }
+        return OK;
+    } else if (mimeType == "") {
+        return BAD_VALUE;
     }
 
-    if (level == DrmPlugin::kSecurityLevelUnknown) {
-        return true;
+    sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
+    if (factoryV1_2 == NULL) {
+        return ERROR_UNSUPPORTED;
     } else {
-        sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
-        if (factoryV1_2 == NULL) {
-            return true;
-        } else if (factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
-                        mimeType.string(), toHidlSecurityLevel(level))) {
-            return true;
-        }
+        *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
+                mimeType.string(), toHidlSecurityLevel(level));
+        return OK;
     }
-    return false;
 }
 
-bool DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
-                                     const String8 &mimeType,
-                                     DrmPlugin::SecurityLevel level) {
+status_t DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
+                                         const String8 &mimeType,
+                                         DrmPlugin::SecurityLevel level,
+                                         bool *isSupported) {
     Mutex::Autolock autoLock(mLock);
-
-    for (size_t i = 0; i < mFactories.size(); i++) {
-        sp<IDrmFactory> factory = mFactories[i];
-        if (factory->isCryptoSchemeSupported(uuid)) {
-            if (matchMimeTypeAndSecurityLevel(factory, uuid, mimeType, level)) {
-                return true;
-            }
+    *isSupported = false;
+    for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+        if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+            return matchMimeTypeAndSecurityLevel(mFactories[i],
+                    uuid, mimeType, level, isSupported);
         }
     }
-    return false;
+    return OK;
 }
 
 status_t DrmHal::createPlugin(const uint8_t uuid[16],
         const String8& appPackageName) {
     Mutex::Autolock autoLock(mLock);
 
-    for (size_t i = mFactories.size() - 1; i >= 0; i--) {
+    for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
         if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
             auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
             if (plugin != NULL) {
@@ -1213,7 +1219,7 @@
     }
 
     if (mPluginV1_2 == NULL) {
-        return ERROR_DRM_CANNOT_HANDLE;
+        return ERROR_UNSUPPORTED;
     }
 
     status_t err = UNKNOWN_ERROR;
@@ -1238,7 +1244,7 @@
     }
 
     if (mPluginV1_2 == NULL) {
-        return ERROR_DRM_CANNOT_HANDLE;
+        return ERROR_UNSUPPORTED;
     }
 
     Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
@@ -1254,7 +1260,7 @@
     }
 
     if (mPluginV1_2 == NULL) {
-        return ERROR_DRM_CANNOT_HANDLE;
+        return ERROR_UNSUPPORTED;
     }
     *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
 
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 0f34315..51274d1 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -83,8 +83,8 @@
         return reply.readInt32();
     }
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
-            DrmPlugin::SecurityLevel level) {
+    virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
+            DrmPlugin::SecurityLevel level, bool *isSupported) {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
         data.write(uuid, 16);
@@ -94,10 +94,11 @@
         status_t status = remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
         if (status != OK) {
             ALOGE("isCryptoSchemeSupported: binder call failed: %d", status);
-            return false;
+            return status;
         }
+        *isSupported = static_cast<bool>(reply.readInt32());
 
-        return reply.readInt32() != 0;
+        return reply.readInt32();
     }
 
     virtual status_t createPlugin(const uint8_t uuid[16],
@@ -773,7 +774,10 @@
             String8 mimeType = data.readString8();
             DrmPlugin::SecurityLevel level =
                     static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
-            reply->writeInt32(isCryptoSchemeSupported(uuid, mimeType, level));
+            bool isSupported = false;
+            status_t result = isCryptoSchemeSupported(uuid, mimeType, level, &isSupported);
+            reply->writeInt32(isSupported);
+            reply->writeInt32(result);
             return OK;
         }
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index b44a6c7..e91e918 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -14,8 +14,8 @@
 // limitations under the License.
 //
 
-cc_binary {
-    name: "android.hardware.drm@1.2-service.clearkey",
+cc_defaults {
+    name: "clearkey_service_defaults",
     vendor: true,
 
     srcs: [
@@ -33,13 +33,11 @@
         "MemoryFileSystem.cpp",
         "Session.cpp",
         "SessionLibrary.cpp",
-        "service.cpp",
     ],
 
     relative_install_path: "hw",
 
     cflags: ["-Wall", "-Werror"],
-    init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
 
     shared_libs: [
         "android.hardware.drm@1.0",
@@ -80,3 +78,16 @@
     },
     srcs: ["protos/DeviceFiles.proto"],
 }
+cc_binary {
+    name: "android.hardware.drm@1.2-service.clearkey",
+    defaults: ["clearkey_service_defaults"],
+    srcs: ["service.cpp"],
+    init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
+}
+cc_binary {
+    name: "android.hardware.drm@1.2-service-lazy.clearkey",
+    overrides: ["android.hardware.drm@1.2-service.clearkey"],
+    defaults: ["clearkey_service_defaults"],
+    srcs: ["serviceLazy.cpp"],
+    init_rc: ["android.hardware.drm@1.2-service-lazy.clearkey.rc"],
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
new file mode 100644
index 0000000..9afd3d7
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
@@ -0,0 +1,14 @@
+service vendor.drm-clearkey-hal-1-2 /vendor/bin/hw/android.hardware.drm@1.2-service-lazy.clearkey
+    interface android.hardware.drm@1.0::ICryptoFactory clearkey
+    interface android.hardware.drm@1.0::IDrmFactory clearkey
+    interface android.hardware.drm@1.1::ICryptoFactory clearkey
+    interface android.hardware.drm@1.1::IDrmFactory clearkey
+    interface android.hardware.drm@1.2::ICryptoFactory clearkey
+    interface android.hardware.drm@1.2::IDrmFactory clearkey
+    disabled
+    oneshot
+    class hal
+    user media
+    group media mediadrm
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
index ac184f7..5ba669d 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
@@ -1,4 +1,10 @@
 service vendor.drm-clearkey-hal-1-2 /vendor/bin/hw/android.hardware.drm@1.2-service.clearkey
+    interface android.hardware.drm@1.0::ICryptoFactory clearkey
+    interface android.hardware.drm@1.0::IDrmFactory clearkey
+    interface android.hardware.drm@1.1::ICryptoFactory clearkey
+    interface android.hardware.drm@1.1::IDrmFactory clearkey
+    interface android.hardware.drm@1.2::ICryptoFactory clearkey
+    interface android.hardware.drm@1.2::IDrmFactory clearkey
     class hal
     user media
     group media mediadrm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/service.cpp b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
index 4ca31f3..b39ea01 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/service.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
@@ -13,13 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "android.hardware.drm@1.2-service.clearkey"
-
 #include <CryptoFactory.h>
 #include <DrmFactory.h>
 
 #include <android-base/logging.h>
 #include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
 #include <hidl/HidlTransportSupport.h>
 
 using ::android::hardware::configureRpcThreadpool;
@@ -31,14 +30,7 @@
 using android::hardware::drm::V1_2::clearkey::CryptoFactory;
 using android::hardware::drm::V1_2::clearkey::DrmFactory;
 
-
 int main(int /* argc */, char** /* argv */) {
-    ALOGD("android.hardware.drm@1.2-service.clearkey starting...");
-
-    // The DRM HAL may communicate to other vendor components via
-    // /dev/vndbinder
-    android::ProcessState::initWithDriver("/dev/vndbinder");
-
     sp<IDrmFactory> drmFactory = new DrmFactory;
     sp<ICryptoFactory> cryptoFactory = new CryptoFactory;
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
new file mode 100644
index 0000000..99fd883
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+#include <CryptoFactory.h>
+#include <DrmFactory.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+using android::hardware::drm::V1_2::ICryptoFactory;
+using android::hardware::drm::V1_2::IDrmFactory;
+using android::hardware::drm::V1_2::clearkey::CryptoFactory;
+using android::hardware::drm::V1_2::clearkey::DrmFactory;
+using android::hardware::LazyServiceRegistrar;
+
+int main(int /* argc */, char** /* argv */) {
+    sp<IDrmFactory> drmFactory = new DrmFactory;
+    sp<ICryptoFactory> cryptoFactory = new CryptoFactory;
+
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    LazyServiceRegistrar serviceRegistrar;
+
+    // Setup hwbinder service
+    CHECK_EQ(serviceRegistrar.registerService(drmFactory, "clearkey"), android::NO_ERROR)
+        << "Failed to register Clearkey Factory HAL";
+    CHECK_EQ(serviceRegistrar.registerService(cryptoFactory, "clearkey"), android::NO_ERROR)
+        << "Failed to register Clearkey Crypto  HAL";
+
+    joinRpcThreadpool();
+}
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index 87730ae..d1bdf0d 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -151,6 +151,7 @@
       mNumBytesPerInputFrame(0u),
       mOutBufferSize(0u),
       mSentCodecSpecificData(false),
+      mInputTimeSet(false),
       mInputSize(0),
       mInputTimeUs(-1ll),
       mSignalledError(false),
@@ -176,6 +177,7 @@
 
 c2_status_t C2SoftAacEnc::onStop() {
     mSentCodecSpecificData = false;
+    mInputTimeSet = false;
     mInputSize = 0u;
     mInputTimeUs = -1ll;
     mSignalledError = false;
@@ -193,6 +195,7 @@
 
 c2_status_t C2SoftAacEnc::onFlush_sm() {
     mSentCodecSpecificData = false;
+    mInputTimeSet = false;
     mInputSize = 0u;
     return C2_OK;
 }
@@ -337,7 +340,6 @@
 
         mOutBufferSize = encInfo.maxOutBufBytes;
         mNumBytesPerInputFrame = encInfo.frameLength * channelCount * sizeof(int16_t);
-        mInputTimeUs = work->input.ordinal.timestamp;
 
         mSentCodecSpecificData = true;
     }
@@ -351,6 +353,10 @@
         data = view.data();
         capacity = view.capacity();
     }
+    if (!mInputTimeSet && capacity > 0) {
+        mInputTimeUs = work->input.ordinal.timestamp;
+        mInputTimeSet = true;
+    }
 
     size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
             / mNumBytesPerInputFrame;
@@ -550,6 +556,7 @@
 
     (void)pool;
     mSentCodecSpecificData = false;
+    mInputTimeSet = false;
     mInputSize = 0u;
 
     // TODO: we don't have any pending work at this time to drain.
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index 82fb438..779365b 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -57,6 +57,7 @@
     UINT mOutBufferSize;
 
     bool mSentCodecSpecificData;
+    bool mInputTimeSet;
     size_t mInputSize;
     c2_cntr64_t mInputTimeUs;
 
diff --git a/media/codec2/components/amr_nb_wb/C2SoftAmrNbEnc.cpp b/media/codec2/components/amr_nb_wb/C2SoftAmrNbEnc.cpp
index ca21480..8c03257 100644
--- a/media/codec2/components/amr_nb_wb/C2SoftAmrNbEnc.cpp
+++ b/media/codec2/components/amr_nb_wb/C2SoftAmrNbEnc.cpp
@@ -271,7 +271,7 @@
         mFilledLen = 0;
     }
     ALOGV("causal sample size %d", mFilledLen);
-    if (mIsFirst) {
+    if (mIsFirst && outPos != 0) {
         mIsFirst = false;
         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
     }
diff --git a/media/codec2/components/amr_nb_wb/C2SoftAmrWbEnc.cpp b/media/codec2/components/amr_nb_wb/C2SoftAmrWbEnc.cpp
index be3892f..074493c 100644
--- a/media/codec2/components/amr_nb_wb/C2SoftAmrWbEnc.cpp
+++ b/media/codec2/components/amr_nb_wb/C2SoftAmrWbEnc.cpp
@@ -347,7 +347,7 @@
         mFilledLen = 0;
     }
     ALOGV("causal sample size %d", mFilledLen);
-    if (mIsFirst) {
+    if (mIsFirst && outPos != 0) {
         mIsFirst = false;
         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
     }
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index cf06623..6ddb9ff 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -216,7 +216,7 @@
         };
 
         uint64_t mbs = uint64_t((size.v.width + 15) / 16) * ((size.v.height + 15) / 16);
-        float mbsPerSec = float(mbs) / frameRate.v.value;
+        float mbsPerSec = float(mbs) * frameRate.v.value;
 
         // Check if the supplied level meets the MB / bitrate requirements. If
         // not, update the level with the lowest level meeting the requirements.
diff --git a/media/codec2/components/opus/C2SoftOpusEnc.cpp b/media/codec2/components/opus/C2SoftOpusEnc.cpp
index d6ed5ff..68fcea1 100644
--- a/media/codec2/components/opus/C2SoftOpusEnc.cpp
+++ b/media/codec2/components/opus/C2SoftOpusEnc.cpp
@@ -350,7 +350,7 @@
             return;
         }
     }
-    if (mIsFirstFrame) {
+    if (mIsFirstFrame && inSize > 0) {
         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
         mIsFirstFrame = false;
     }
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 ba7c2d6..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,13 +188,13 @@
             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;
 
         std::shared_ptr<C2GraphicAllocation> alloc;
         C2Handle* handle = WrapNativeCodec2GrallocHandle(
-                native_handle_clone(buffer->handle),
+                buffer->handle,
                 buffer->width, buffer->height,
                 buffer->format, buffer->usage, buffer->stride);
         mAllocatorMutex.lock();
@@ -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 c053bc1..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,35 +1822,34 @@
                              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));
-        return false;
+        LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+                        "status = " << result << ".";
+        return result;
     }
-    ALOGV("attachToBufferQueue -- attachBuffer returned slot %d",
-            static_cast<int>(*bqSlot));
-    return true;
+    LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+                 << *bqSlot << ".";
+    return OK;
 }
 
 bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
@@ -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,21 +1917,20 @@
     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), bqId, bqSlot, true);
+            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 f5cc9ff..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;
@@ -1186,22 +1254,21 @@
         uint32_t outputGeneration = mOutputGeneration;
         mOutputBufferQueueMutex.unlock();
 
-        status_t status = !attachToBufferQueue(block,
+        status_t status = attachToBufferQueue(block,
                                                outputIgbp,
                                                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,66 +1281,95 @@
     mOutputBufferQueueMutex.unlock();
 
     if (!outputIgbp) {
-        ALOGV("queueToOutputSurface -- output surface is null.");
+        LOG(VERBOSE) << "queueToOutputSurface -- output surface is null.";
         return NO_INIT;
     }
 
-    if (bqId != outputBqId) {
-        ALOGV("queueToOutputSurface -- bufferqueue ids mismatch.");
-        return DEAD_OBJECT;
-    }
-
-    if (generation != outputGeneration) {
-        ALOGV("queueToOutputSurface -- generation numbers mismatch.");
-        return DEAD_OBJECT;
+    if (bqId != outputBqId || generation != outputGeneration) {
+        if (!holdBufferQueueBlock(block, mOutputIgbp, mOutputBqId, mOutputGeneration)) {
+            LOG(ERROR) << "queueToOutputSurface -- migration failed.";
+            return DEAD_OBJECT;
+        }
+        if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot)) {
+            LOG(ERROR) << "queueToOutputSurface -- corrupted bufferqueue assignment.";
+            return UNKNOWN_ERROR;
+        }
     }
 
     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;
 }
@@ -1293,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.";
             }
         }
     };
@@ -1303,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/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index 9500aed..03d859a 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -225,18 +225,14 @@
     if (omxBuf.mBufferType == OMXBuffer::kBufferTypeANWBuffer
             && omxBuf.mGraphicBuffer != nullptr) {
         std::shared_ptr<C2GraphicAllocation> alloc;
-        native_handle_t *clonedHandle = native_handle_clone(omxBuf.mGraphicBuffer->handle);
         handle = WrapNativeCodec2GrallocHandle(
-                clonedHandle,
+                omxBuf.mGraphicBuffer->handle,
                 omxBuf.mGraphicBuffer->width,
                 omxBuf.mGraphicBuffer->height,
                 omxBuf.mGraphicBuffer->format,
                 omxBuf.mGraphicBuffer->usage,
                 omxBuf.mGraphicBuffer->stride);
         c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
-        if (clonedHandle) {
-            native_handle_delete(clonedHandle);
-        }
         if (err != OK) {
             return UNKNOWN_ERROR;
         }
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 852d6d6..10263de 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);
@@ -1020,7 +1024,7 @@
         ALOGD("ISConfig: no configuration");
     }
 
-    return surface->start();
+    return OK;
 }
 
 void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
@@ -1107,12 +1111,20 @@
     }
     sp<AMessage> inputFormat;
     sp<AMessage> outputFormat;
+    status_t err2 = OK;
     {
         Mutexed<Config>::Locked config(mConfig);
         inputFormat = config->mInputFormat;
         outputFormat = config->mOutputFormat;
+        if (config->mInputSurface) {
+            err2 = config->mInputSurface->start();
+        }
     }
-    status_t err2 = mChannel->start(inputFormat, outputFormat);
+    if (err2 != OK) {
+        mCallback->onError(err2, ACTION_CODE_FATAL);
+        return;
+    }
+    err2 = mChannel->start(inputFormat, outputFormat);
     if (err2 != OK) {
         mCallback->onError(err2, ACTION_CODE_FATAL);
         return;
@@ -1187,6 +1199,13 @@
     }
 
     {
+        Mutexed<Config>::Locked config(mConfig);
+        if (config->mInputSurface) {
+            config->mInputSurface->disconnect();
+            config->mInputSurface = nullptr;
+        }
+    }
+    {
         Mutexed<State>::Locked state(mState);
         if (state->get() == STOPPING) {
             state->set(ALLOCATED);
@@ -1196,6 +1215,7 @@
 }
 
 void CCodec::initiateRelease(bool sendCallback /* = true */) {
+    bool clearInputSurfaceIfNeeded = false;
     {
         Mutexed<State>::Locked state(mState);
         if (state->get() == RELEASED || state->get() == RELEASING) {
@@ -1217,9 +1237,23 @@
             }
             return;
         }
+        if (state->get() == STARTING
+                || state->get() == RUNNING
+                || state->get() == STOPPING) {
+            // Input surface may have been started, so clean up is needed.
+            clearInputSurfaceIfNeeded = true;
+        }
         state->set(RELEASING);
     }
 
+    if (clearInputSurfaceIfNeeded) {
+        Mutexed<Config>::Locked config(mConfig);
+        if (config->mInputSurface) {
+            config->mInputSurface->disconnect();
+            config->mInputSurface = nullptr;
+        }
+    }
+
     mChannel->stop();
     // thiz holds strong ref to this while the thread is running.
     sp<CCodec> thiz(this);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index b529cbc..9616e47 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -128,7 +128,9 @@
      * and released successfully.
      */
     virtual bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) = 0;
 
     /**
      * Release the buffer that is no longer used by the codec process. Return
@@ -455,13 +457,18 @@
      * \return  true  if the buffer is successfully released from a slot
      *          false otherwise
      */
-    bool releaseSlot(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+    bool releaseSlot(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) {
         sp<Codec2Buffer> clientBuffer;
         size_t index = mBuffers.size();
         for (size_t i = 0; i < mBuffers.size(); ++i) {
             if (mBuffers[i].clientBuffer == buffer) {
                 clientBuffer = mBuffers[i].clientBuffer;
-                mBuffers[i].clientBuffer.clear();
+                if (release) {
+                    mBuffers[i].clientBuffer.clear();
+                }
                 index = i;
                 break;
             }
@@ -470,8 +477,11 @@
             ALOGV("[%s] %s: No matching buffer found", mName, __func__);
             return false;
         }
-        std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
-        mBuffers[index].compBuffer = result;
+        std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+        if (!result) {
+            result = clientBuffer->asC2Buffer();
+            mBuffers[index].compBuffer = result;
+        }
         if (c2buffer) {
             *c2buffer = result;
         }
@@ -485,8 +495,8 @@
             if (!compBuffer || compBuffer != c2buffer) {
                 continue;
             }
-            mBuffers[i].clientBuffer = nullptr;
             mBuffers[i].compBuffer.reset();
+            ALOGV("[%s] codec released buffer #%zu", mName, i);
             return true;
         }
         ALOGV("[%s] codec released an unknown buffer", mName);
@@ -597,7 +607,10 @@
      * \return  true  if the buffer is successfully returned
      *          false otherwise
      */
-    bool returnBuffer(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+    bool returnBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) {
         sp<Codec2Buffer> clientBuffer;
         size_t index = mBuffers.size();
         for (size_t i = 0; i < mBuffers.size(); ++i) {
@@ -606,7 +619,9 @@
                     ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", mName, i);
                 }
                 clientBuffer = mBuffers[i].clientBuffer;
-                mBuffers[i].ownedByClient = false;
+                if (release) {
+                    mBuffers[i].ownedByClient = false;
+                }
                 index = i;
                 break;
             }
@@ -616,8 +631,11 @@
             return false;
         }
         ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
-        std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
-        mBuffers[index].compBuffer = result;
+        std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+        if (!result) {
+            result = clientBuffer->asC2Buffer();
+            mBuffers[index].compBuffer = result;
+        }
         if (c2buffer) {
             *c2buffer = result;
         }
@@ -636,9 +654,9 @@
                     // This should not happen.
                     ALOGD("[%s] codec released a buffer owned by client "
                           "(index %zu)", mName, i);
-                    mBuffers[i].ownedByClient = false;
                 }
                 mBuffers[i].compBuffer.reset();
+                ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
                 return true;
             }
         }
@@ -723,8 +741,10 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.returnBuffer(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.returnBuffer(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
@@ -765,8 +785,10 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.releaseSlot(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
@@ -801,7 +823,7 @@
         return std::move(array);
     }
 
-    virtual sp<Codec2Buffer> alloc(size_t size) const {
+    virtual sp<Codec2Buffer> alloc(size_t size) {
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
         std::shared_ptr<C2LinearBlock> block;
 
@@ -850,11 +872,12 @@
     ~EncryptedLinearInputBuffers() override {
     }
 
-    sp<Codec2Buffer> alloc(size_t size) const override {
+    sp<Codec2Buffer> alloc(size_t size) override {
         sp<IMemory> memory;
-        for (const Entry &entry : mMemoryVector) {
-            if (entry.block.expired()) {
-                memory = entry.memory;
+        size_t slot = 0;
+        for (; slot < mMemoryVector.size(); ++slot) {
+            if (mMemoryVector[slot].block.expired()) {
+                memory = mMemoryVector[slot].memory;
                 break;
             }
         }
@@ -864,10 +887,11 @@
 
         std::shared_ptr<C2LinearBlock> block;
         c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
-        if (err != C2_OK) {
+        if (err != C2_OK || block == nullptr) {
             return nullptr;
         }
 
+        mMemoryVector[slot].block = block;
         return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
     }
 
@@ -907,8 +931,10 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.releaseSlot(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
@@ -971,14 +997,17 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.releaseSlot(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
             const std::shared_ptr<C2Buffer> &c2buffer) override {
         return mImpl.expireComponentBuffer(c2buffer);
     }
+
     void flush() override {
         // This is no-op by default unless we're in array mode where we need to keep
         // track of the flushed work.
@@ -1016,7 +1045,7 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *) override {
+            const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
         return false;
     }
 
@@ -1111,7 +1140,7 @@
 
     bool releaseBuffer(
             const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.returnBuffer(buffer, c2buffer);
+        return mImpl.returnBuffer(buffer, c2buffer, true);
     }
 
     void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
@@ -1171,6 +1200,9 @@
             size_t *index,
             sp<MediaCodecBuffer> *clientBuffer) override {
         sp<Codec2Buffer> newBuffer = wrap(buffer);
+        if (newBuffer == nullptr) {
+            return NO_MEMORY;
+        }
         newBuffer->setFormat(mFormat);
         *index = mImpl.assignSlot(newBuffer);
         *clientBuffer = newBuffer;
@@ -1190,8 +1222,9 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer) override {
+        return mImpl.releaseSlot(buffer, c2buffer, true);
     }
 
     void flush(
@@ -1263,6 +1296,10 @@
             return nullptr;
         }
         sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
+        if (clientBuffer == nullptr) {
+            ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
+            return nullptr;
+        }
         submit(clientBuffer);
         return clientBuffer;
     }
@@ -1303,6 +1340,10 @@
                     [lbp = mLocalBufferPool](size_t capacity) {
                         return lbp->newBuffer(capacity);
                     });
+            if (c2buffer == nullptr) {
+                ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
+                return nullptr;
+            }
             c2buffer->setRange(0, 0);
             return c2buffer;
         } else {
@@ -1478,6 +1519,11 @@
     mKey = C2Config::ORDINAL;
 }
 
+void CCodecBufferChannel::ReorderStash::flush() {
+    mPending.clear();
+    mStash.clear();
+}
+
 void CCodecBufferChannel::ReorderStash::setDepth(uint32_t depth) {
     mPending.splice(mPending.end(), mStash);
     mDepth = depth;
@@ -1615,7 +1661,7 @@
     if (buffer->size() > 0u) {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
         std::shared_ptr<C2Buffer> c2buffer;
-        if (!(*buffers)->releaseBuffer(buffer, &c2buffer)) {
+        if (!(*buffers)->releaseBuffer(buffer, &c2buffer, false)) {
             return -ENOENT;
         }
         work->input.buffers.push_back(c2buffer);
@@ -1645,6 +1691,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));
@@ -1652,6 +1699,10 @@
     }
     if (err == C2_OK) {
         mCCodecCallback->onWorkQueued(eos);
+
+        Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
+        bool released = (*buffers)->releaseBuffer(buffer, nullptr, true);
+        ALOGV("[%s] queueInputBuffer: buffer %sreleased", mName, released ? "" : "not ");
     }
 
     feedInputBufferIfAvailableInternal();
@@ -1980,7 +2031,7 @@
     bool released = false;
     {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
-        if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) {
+        if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr, true)) {
             buffers.unlock();
             released = true;
             mAvailablePipelineCapacity.freeInputSlots(1, "discardBuffer");
@@ -2445,7 +2496,6 @@
     mSync.stop();
     mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
     if (mInputSurface != nullptr) {
-        mInputSurface->disconnect();
         mInputSurface.reset();
     }
 }
@@ -2481,6 +2531,7 @@
         Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
         (*buffers)->flush(flushedWork);
     }
+    mReorderStash.lock()->flush();
 }
 
 void CCodecBufferChannel::onWorkDone(
@@ -2708,6 +2759,9 @@
         status_t err = (*buffers)->registerBuffer(entry.buffer, &index, &outBuffer);
         if (err != OK) {
             if (err != WOULD_BLOCK) {
+                if (!(*buffers)->isArrayMode()) {
+                    *buffers = (*buffers)->toArrayMode(mNumOutputSlots);
+                }
                 OutputBuffersArray *array = (OutputBuffersArray *)buffers->get();
                 array->realloc(entry.buffer);
                 mCCodecCallback->onOutputBuffersChanged();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index fd806b7..ebc1491 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -359,6 +359,7 @@
         ReorderStash();
 
         void clear();
+        void flush();
         void setDepth(uint32_t depth);
         void setKey(C2Config::ordinal_key_t key);
         bool pop(Entry *entry);
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 1113ae8..2dec42e 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -451,6 +451,9 @@
     }
 
     bool setBackBuffer(const sp<ABuffer> &backBuffer) {
+        if (backBuffer == nullptr) {
+            return false;
+        }
         if (backBuffer->capacity() < mBackBufferSize) {
             return false;
         }
@@ -578,7 +581,7 @@
 
     ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
     C2Handle *handle = WrapNativeCodec2GrallocHandle(
-            native_handle_clone(buffer->handle),
+            buffer->handle,
             buffer->width,
             buffer->height,
             buffer->format,
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index a8cc62d..5f0dd0b 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -44,6 +44,7 @@
 #include <cutils/native_handle.h>
 #include <media/omx/1.0/WOmxNode.h>
 #include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/foundation/ALookup.h>
 #include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/omx/OMXUtils.h>
 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
@@ -299,7 +300,6 @@
         // OMX components don't have aliases
         for (const MediaCodecsXmlParser::Type &type : properties.typeMap) {
             const std::string &mediaType = type.first;
-
             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
                     info->addMediaType(mediaType.c_str());
             const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
@@ -376,7 +376,7 @@
     }
 
     bool surfaceTest(Codec2Client::CreateInputSurface());
-    if (option == 0 || !surfaceTest) {
+    if (option == 0 || (option != 4 && !surfaceTest)) {
         buildOmxInfo(parser, writer);
     }
 
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index eb6c3e9..8c8f025 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -26,6 +26,10 @@
         "libutils",
     ],
 
+    static_libs: [
+        "libyuv_static",
+    ],
+
     sanitize: {
         cfi: true,
         misc_undefined: [
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 84d22a3..6b8663f 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "Codec2BufferUtils"
 #include <utils/Log.h>
 
+#include <libyuv.h>
+
 #include <list>
 #include <mutex>
 
@@ -62,14 +64,10 @@
  */
 template<bool ToMediaImage, typename View, typename ImagePixel>
 static status_t _ImageCopy(View &view, const MediaImage2 *img, ImagePixel *imgBase) {
-    // TODO: more efficient copying --- e.g. one row at a time, copying
-    //       interleaved planes together, etc.
+    // TODO: more efficient copying --- e.g. copy interleaved planes together, etc.
     const C2PlanarLayout &layout = view.layout();
     const size_t bpp = divUp(img->mBitDepthAllocated, 8u);
-    if (view.width() != img->mWidth
-            || view.height() != img->mHeight) {
-        return BAD_VALUE;
-    }
+
     for (uint32_t i = 0; i < layout.numPlanes; ++i) {
         typename std::conditional<ToMediaImage, uint8_t, const uint8_t>::type *imgRow =
             imgBase + img->mPlane[i].mOffset;
@@ -120,10 +118,72 @@
 }  // namespace
 
 status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
+    if (view.width() != img->mWidth || view.height() != img->mHeight) {
+        return BAD_VALUE;
+    }
+    if ((IsNV12(view) && IsI420(img)) || (IsI420(view) && IsNV12(img))) {
+        // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+        const uint8_t* src_y = view.data()[0];
+        const uint8_t* src_u = view.data()[1];
+        const uint8_t* src_v = view.data()[2];
+        int32_t src_stride_y = view.layout().planes[0].rowInc;
+        int32_t src_stride_u = view.layout().planes[1].rowInc;
+        int32_t src_stride_v = view.layout().planes[2].rowInc;
+        uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
+        uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
+        uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
+        int32_t dst_stride_y = img->mPlane[0].mRowInc;
+        int32_t dst_stride_u = img->mPlane[1].mRowInc;
+        int32_t dst_stride_v = img->mPlane[2].mRowInc;
+        if (IsNV12(view) && IsI420(img)) {
+            if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+                                    dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        } else {
+            if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+                                    dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        }
+    }
     return _ImageCopy<true>(view, img, imgBase);
 }
 
 status_t ImageCopy(C2GraphicView &view, const uint8_t *imgBase, const MediaImage2 *img) {
+    if (view.width() != img->mWidth || view.height() != img->mHeight) {
+        return BAD_VALUE;
+    }
+    if ((IsNV12(img) && IsI420(view)) || (IsI420(img) && IsNV12(view))) {
+        // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+        const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
+        const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
+        const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
+        int32_t src_stride_y = img->mPlane[0].mRowInc;
+        int32_t src_stride_u = img->mPlane[1].mRowInc;
+        int32_t src_stride_v = img->mPlane[2].mRowInc;
+        uint8_t* dst_y = view.data()[0];
+        uint8_t* dst_u = view.data()[1];
+        uint8_t* dst_v = view.data()[2];
+        int32_t dst_stride_y = view.layout().planes[0].rowInc;
+        int32_t dst_stride_u = view.layout().planes[1].rowInc;
+        int32_t dst_stride_v = view.layout().planes[2].rowInc;
+        if (IsNV12(img) && IsI420(view)) {
+            if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+                                    dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        } else {
+            if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+                                    dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        }
+    }
     return _ImageCopy<false>(view, img, imgBase);
 }
 
@@ -151,6 +211,65 @@
             && layout.planes[layout.PLANE_V].rowSampling == 2);
 }
 
+bool IsNV12(const C2GraphicView &view) {
+    if (!IsYUV420(view)) {
+        return false;
+    }
+    const C2PlanarLayout &layout = view.layout();
+    return (layout.rootPlanes == 2
+            && layout.planes[layout.PLANE_U].colInc == 2
+            && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+            && layout.planes[layout.PLANE_U].offset == 0
+            && layout.planes[layout.PLANE_V].colInc == 2
+            && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_U
+            && layout.planes[layout.PLANE_V].offset == 1);
+}
+
+bool IsI420(const C2GraphicView &view) {
+    if (!IsYUV420(view)) {
+        return false;
+    }
+    const C2PlanarLayout &layout = view.layout();
+    return (layout.rootPlanes == 3
+            && layout.planes[layout.PLANE_U].colInc == 1
+            && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+            && layout.planes[layout.PLANE_U].offset == 0
+            && layout.planes[layout.PLANE_V].colInc == 1
+            && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_V
+            && layout.planes[layout.PLANE_V].offset == 0);
+}
+
+bool IsYUV420(const MediaImage2 *img) {
+    return (img->mType == MediaImage2::MEDIA_IMAGE_TYPE_YUV
+            && img->mNumPlanes == 3
+            && img->mBitDepth == 8
+            && img->mBitDepthAllocated == 8
+            && img->mPlane[0].mHorizSubsampling == 1
+            && img->mPlane[0].mVertSubsampling == 1
+            && img->mPlane[1].mHorizSubsampling == 2
+            && img->mPlane[1].mVertSubsampling == 2
+            && img->mPlane[2].mHorizSubsampling == 2
+            && img->mPlane[2].mVertSubsampling == 2);
+}
+
+bool IsNV12(const MediaImage2 *img) {
+    if (!IsYUV420(img)) {
+        return false;
+    }
+    return (img->mPlane[1].mColInc == 2
+            && img->mPlane[2].mColInc == 2
+            && (img->mPlane[2].mOffset - img->mPlane[1].mOffset == 1));
+}
+
+bool IsI420(const MediaImage2 *img) {
+    if (!IsYUV420(img)) {
+        return false;
+    }
+    return (img->mPlane[1].mColInc == 1
+            && img->mPlane[2].mColInc == 1
+            && img->mPlane[2].mOffset > img->mPlane[1].mOffset);
+}
+
 MediaImage2 CreateYUV420PlanarMediaImage2(
         uint32_t width, uint32_t height, uint32_t stride, uint32_t vstride) {
     return MediaImage2 {
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index eaf6776..afadf00 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -91,6 +91,31 @@
 bool IsYUV420(const C2GraphicView &view);
 
 /**
+ * Returns true iff a view has a NV12 layout.
+ */
+bool IsNV12(const C2GraphicView &view);
+
+/**
+ * Returns true iff a view has a I420 layout.
+ */
+bool IsI420(const C2GraphicView &view);
+
+/**
+ * Returns true iff a MediaImage2 has a YUV 420 888 layout.
+ */
+bool IsYUV420(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a NV12 layout.
+ */
+bool IsNV12(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a I420 layout.
+ */
+bool IsI420(const MediaImage2 *img);
+
+/**
  * A raw memory block to use for internal buffers.
  *
  * TODO: replace this with C2LinearBlocks from a private C2BlockPool
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 18f2430..e698bf4 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -159,7 +159,7 @@
         return xd != nullptr && xd->magic == MAGIC;
     }
 
-    static C2HandleGralloc* WrapNativeHandle(
+    static C2HandleGralloc* WrapAndMoveNativeHandle(
             const native_handle_t *const handle,
             uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
             uint32_t stride, uint32_t generation, uint64_t igbp_id = 0, uint32_t igbp_slot = 0) {
@@ -181,6 +181,26 @@
         return reinterpret_cast<C2HandleGralloc *>(res);
     }
 
+    static C2HandleGralloc* WrapNativeHandle(
+            const native_handle_t *const handle,
+            uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
+            uint32_t stride, uint32_t generation, uint64_t igbp_id = 0, uint32_t igbp_slot = 0) {
+        if (handle == nullptr) {
+            return nullptr;
+        }
+        native_handle_t *clone = native_handle_clone(handle);
+        if (clone == nullptr) {
+            return nullptr;
+        }
+        C2HandleGralloc *res = WrapAndMoveNativeHandle(
+                clone, width, height, format, usage, stride, generation, igbp_id, igbp_slot);
+        if (res == nullptr) {
+            native_handle_close(clone);
+        }
+        native_handle_delete(clone);
+        return res;
+    }
+
     static native_handle_t* UnwrapNativeHandle(
             const C2Handle *const handle) {
         const ExtraData *xd = getExtraData(handle);
@@ -366,7 +386,7 @@
         if (mHandle) {
             mHandle->getIgbpData(&generation, &igbp_id, &igbp_slot);
         }
-        mLockedHandle = C2HandleGralloc::WrapNativeHandle(
+        mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
                 mBuffer, mInfo.mapperInfo.width, mInfo.mapperInfo.height,
                 (uint32_t)mInfo.mapperInfo.format, mInfo.mapperInfo.usage, mInfo.stride,
                 generation, igbp_id, igbp_slot);
@@ -743,7 +763,7 @@
                     return;
                 }
                 info.stride = stride;
-                buffer = std::move(buffers[0]);
+                buffer = buffers[0];
             });
     if (err != C2_OK) {
         return err;
@@ -752,7 +772,7 @@
 
     allocation->reset(new C2AllocationGralloc(
             info, mMapper, buffer,
-            C2HandleGralloc::WrapNativeHandle(
+            C2HandleGralloc::WrapAndMoveNativeHandle(
                     buffer.getNativeHandle(),
                     info.mapperInfo.width, info.mapperInfo.height,
                     (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride,
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 7a26035..7bf3d64 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -192,7 +192,7 @@
         int slot;
         ALOGV("tries to dequeue buffer");
         Return<void> transStatus = mProducer->dequeueBuffer(
-                width, height, pixelFormat, androidUsage.asGrallocUsage(), true,
+                width, height, pixelFormat, androidUsage.asGrallocUsage(), false,
                 [&status, &slot, &fence](
                         int32_t tStatus, int32_t tSlot, hidl_handle const& tFence,
                         HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
@@ -269,36 +269,28 @@
             }
         }
         if (slotBuffer) {
-            native_handle_t *grallocHandle = native_handle_clone(slotBuffer->handle);
-
-            if (grallocHandle) {
-                ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
-                C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle(
-                        grallocHandle,
-                        slotBuffer->width,
-                        slotBuffer->height,
-                        slotBuffer->format,
-                        slotBuffer->usage,
-                        slotBuffer->stride,
-                        slotBuffer->getGenerationNumber(),
-                        mProducerId, slot);
-                if (c2Handle) {
-                    // Moved everything to c2Handle.
-                    native_handle_delete(grallocHandle);
-                    std::shared_ptr<C2GraphicAllocation> alloc;
-                    c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
-                    if (err != C2_OK) {
-                        return err;
-                    }
-                    std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
-                            std::make_shared<C2BufferQueueBlockPoolData>(
-                                    slotBuffer->getGenerationNumber(),
-                                    mProducerId, slot, shared_from_this());
-                    *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
-                    return C2_OK;
+            ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
+            C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle(
+                    slotBuffer->handle,
+                    slotBuffer->width,
+                    slotBuffer->height,
+                    slotBuffer->format,
+                    slotBuffer->usage,
+                    slotBuffer->stride,
+                    slotBuffer->getGenerationNumber(),
+                    mProducerId, slot);
+            if (c2Handle) {
+                std::shared_ptr<C2GraphicAllocation> alloc;
+                c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
+                if (err != C2_OK) {
+                    return err;
                 }
-                native_handle_close(grallocHandle);
-                native_handle_delete(grallocHandle);
+                std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+                        std::make_shared<C2BufferQueueBlockPoolData>(
+                                slotBuffer->getGenerationNumber(),
+                                mProducerId, slot, shared_from_this());
+                *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+                return C2_OK;
             }
             // Block was not created. call requestBuffer# again next time.
             slotBuffer.clear();
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
old mode 100644
new mode 100755
index d0efddd..ac54116
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -345,6 +345,9 @@
 
         case FOURCC("av01"):
             return MEDIA_MIMETYPE_VIDEO_AV1;
+        case FOURCC(".mp3"):
+        case 0x6D730055: // "ms U" mp3 audio
+            return MEDIA_MIMETYPE_AUDIO_MPEG;
         default:
             ALOGW("Unknown fourcc: %c%c%c%c",
                    (fourcc >> 24) & 0xff,
@@ -1629,10 +1632,11 @@
         case FOURCC("twos"):
         case FOURCC("sowt"):
         case FOURCC("alac"):
+        case FOURCC(".mp3"):
+        case 0x6D730055: // "ms U" mp3 audio
         {
-            if (mIsQT && chunk_type == FOURCC("mp4a")
-                    && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
-                // Ignore mp4a embedded in QT wave atom
+            if (mIsQT && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
+                // Ignore all atoms embedded in QT wave atom
                 *offset += chunk_size;
                 break;
             }
@@ -1661,7 +1665,7 @@
             off64_t stop_offset = *offset + chunk_size;
             *offset = data_offset + sizeof(buffer);
 
-            if (mIsQT && chunk_type == FOURCC("mp4a")) {
+            if (mIsQT) {
                 if (version == 1) {
                     if (mDataSource->readAt(*offset, buffer, 16) < 16) {
                         return ERROR_IO;
@@ -1990,6 +1994,13 @@
 
             *offset += chunk_size;
 
+            if (depth >= 1 && mPath[depth - 1] != FOURCC("stbl")) {
+                char chunk[5];
+                MakeFourCCString(mPath[depth - 1], chunk);
+                ALOGW("stts's parent box (%s) is not stbl, skip it.", chunk);
+                break;
+            }
+
             status_t err =
                 mLastTrack->sampleTable->setTimeToSampleParams(
                         data_offset, chunk_data_size);
@@ -2096,9 +2107,10 @@
                 return ERROR_MALFORMED;
             }
 
-            uint8_t buffer[256];
-            if (chunk_data_size > (off64_t)sizeof(buffer)) {
-                return ERROR_BUFFER_TOO_SMALL;
+            auto tmp = heapbuffer<uint8_t>(chunk_data_size);
+            uint8_t *buffer = tmp.get();
+            if (buffer == NULL) {
+                return -ENOMEM;
             }
 
             if (mDataSource->readAt(
@@ -4085,12 +4097,10 @@
         return OK;
     }
 
-    if (objectTypeIndication  == 0x6b) {
-        // The media subtype is MP3 audio
-        // Our software MP3 audio decoder may not be able to handle
-        // packetized MP3 audio; for now, lets just return ERROR_UNSUPPORTED
-        ALOGE("MP3 track in MP4/3GPP file is not supported");
-        return ERROR_UNSUPPORTED;
+    if (objectTypeIndication == 0x6B || objectTypeIndication == 0x69) {
+        // mp3 audio
+        AMediaFormat_setString(mLastTrack->meta,AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
+        return OK;
     }
 
     if (mLastTrack != NULL) {
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index ec12130..2890b26 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -111,8 +111,15 @@
             if ((err = getSampleSizeDirect(
                             firstChunkSampleIndex + i, &sampleSize)) != OK) {
                 ALOGE("getSampleSizeDirect return error");
-                mCurrentChunkSampleSizes.clear();
-                return err;
+                // stsc sample count is not sync with stsz sample count
+                if (err == ERROR_OUT_OF_RANGE) {
+                    ALOGW("stsc samples(%d) not sync with stsz samples(%d)", mSamplesPerChunk, i);
+                    mSamplesPerChunk = i;
+                    break;
+                } else{
+                    mCurrentChunkSampleSizes.clear();
+                    return err;
+                }
             }
 
             mCurrentChunkSampleSizes.push(sampleSize);
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 596c1c8..ba40690 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -983,7 +983,7 @@
         size_t denom = numerator - kMaxNumTOCEntries;
 
         size_t accum = 0;
-        for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) {
+        for (ssize_t i = mTableOfContents.size(); i > 0; --i) {
             accum += denom;
             if (accum >= numerator) {
                 mTableOfContents.removeAt(i);
diff --git a/media/libmedia/BufferingSettings.cpp b/media/libmedia/BufferingSettings.cpp
index 271a238..1cc30c2 100644
--- a/media/libmedia/BufferingSettings.cpp
+++ b/media/libmedia/BufferingSettings.cpp
@@ -27,26 +27,6 @@
         : mInitialMarkMs(kNoMark),
           mResumePlaybackMarkMs(kNoMark) { }
 
-status_t BufferingSettings::readFromParcel(const Parcel* parcel) {
-    if (parcel == nullptr) {
-        return BAD_VALUE;
-    }
-    mInitialMarkMs = parcel->readInt32();
-    mResumePlaybackMarkMs = parcel->readInt32();
-
-    return OK;
-}
-
-status_t BufferingSettings::writeToParcel(Parcel* parcel) const {
-    if (parcel == nullptr) {
-        return BAD_VALUE;
-    }
-    parcel->writeInt32(mInitialMarkMs);
-    parcel->writeInt32(mResumePlaybackMarkMs);
-
-    return OK;
-}
-
 String8 BufferingSettings::toString() const {
     String8 s;
     s.appendFormat(
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index e2eccdd..ea06665 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -179,7 +179,8 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-        buffering.writeToParcel(&data);
+        data.writeInt32(buffering.mInitialMarkMs);
+        data.writeInt32(buffering.mResumePlaybackMarkMs);
         remote()->transact(SET_BUFFERING_SETTINGS, data, &reply);
         return reply.readInt32();
     }
@@ -194,7 +195,8 @@
         remote()->transact(GET_BUFFERING_SETTINGS, data, &reply);
         status_t err = reply.readInt32();
         if (err == OK) {
-            err = buffering->readFromParcel(&reply);
+            buffering->mInitialMarkMs = reply.readInt32();
+            buffering->mResumePlaybackMarkMs = reply.readInt32();
         }
         return err;
     }
@@ -696,7 +698,8 @@
         case SET_BUFFERING_SETTINGS: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             BufferingSettings buffering;
-            buffering.readFromParcel(&data);
+            buffering.mInitialMarkMs = data.readInt32();
+            buffering.mResumePlaybackMarkMs = data.readInt32();
             reply->writeInt32(setBufferingSettings(buffering));
             return NO_ERROR;
         } break;
@@ -706,7 +709,8 @@
             status_t err = getBufferingSettings(&buffering);
             reply->writeInt32(err);
             if (err == OK) {
-                buffering.writeToParcel(reply);
+                reply->writeInt32(buffering.mInitialMarkMs);
+                reply->writeInt32(buffering.mResumePlaybackMarkMs);
             }
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/include/media/BufferingSettings.h b/media/libmedia/include/media/BufferingSettings.h
index d2a3e40..d97cc00 100644
--- a/media/libmedia/include/media/BufferingSettings.h
+++ b/media/libmedia/include/media/BufferingSettings.h
@@ -17,11 +17,11 @@
 #ifndef ANDROID_BUFFERING_SETTINGS_H
 #define ANDROID_BUFFERING_SETTINGS_H
 
-#include <binder/Parcelable.h>
+#include <utils/String8.h>
 
 namespace android {
 
-struct BufferingSettings : public Parcelable {
+struct BufferingSettings {
     static const int kNoMark = -1;
 
     int mInitialMarkMs;
@@ -32,9 +32,6 @@
 
     BufferingSettings();
 
-    status_t writeToParcel(Parcel* parcel) const override;
-    status_t readFromParcel(const Parcel* parcel) override;
-
     String8 toString() const;
 };
 
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index 7be5cf2..a630bfd 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -63,9 +63,10 @@
 
     virtual status_t initCheck() const;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16],
-                                         const String8& mimeType,
-                                         DrmPlugin::SecurityLevel level);
+    virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+                                             const String8& mimeType,
+                                             DrmPlugin::SecurityLevel level,
+                                             bool *isSupported);
 
     virtual status_t createPlugin(const uint8_t uuid[16],
                                   const String8 &appPackageName);
@@ -226,10 +227,11 @@
     status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
     status_t getPropertyByteArrayInternal(String8 const &name,
                                           Vector<uint8_t> &value) const;
-    bool matchMimeTypeAndSecurityLevel(sp<IDrmFactory> &factory,
-                                       const uint8_t uuid[16],
-                                       const String8 &mimeType,
-                                       DrmPlugin::SecurityLevel level);
+    status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+                                           const uint8_t uuid[16],
+                                           const String8 &mimeType,
+                                           DrmPlugin::SecurityLevel level,
+                                           bool *isSupported);
 
     DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
 };
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
index a32756f..fbe80c6 100644
--- a/media/libmedia/include/media/IDrm.h
+++ b/media/libmedia/include/media/IDrm.h
@@ -34,9 +34,10 @@
 
     virtual status_t initCheck() const = 0;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16],
-                                         const String8 &mimeType,
-                                         DrmPlugin::SecurityLevel securityLevel) = 0;
+    virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+                                             const String8 &mimeType,
+                                             DrmPlugin::SecurityLevel securityLevel,
+                                             bool *result) = 0;
 
     virtual status_t createPlugin(const uint8_t uuid[16],
                                   const String8 &appPackageName) = 0;
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index b3f7404..00f537d 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -21,7 +21,6 @@
         "libgui",
         "liblog",
         "libmedia_omx",
-        "libstagefright_foundation",
         "libui",
         "libutils",
 
@@ -55,6 +54,7 @@
         "libmediaplayer2-protos",
         "libmedia_player2_util",
         "libprotobuf-cpp-lite",
+        "libstagefright_foundation_without_imemory",
         "libstagefright_nuplayer2",
         "libstagefright_player2",
         "libstagefright_rtsp",
diff --git a/media/libmediaplayer2/JMedia2HTTPConnection.cpp b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
index d264a7f..e1baa10 100644
--- a/media/libmediaplayer2/JMedia2HTTPConnection.cpp
+++ b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
@@ -21,11 +21,10 @@
 #include <mediaplayer2/JavaVMHelper.h>
 #include <mediaplayer2/JMedia2HTTPConnection.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/scoped_local_ref.h>
 
 #include "log/log.h"
 #include "jni.h"
-#include <nativehelper/JNIHelp.h>
 
 namespace android {
 
diff --git a/media/libmediaplayer2/JMedia2HTTPService.cpp b/media/libmediaplayer2/JMedia2HTTPService.cpp
index 264c15d..20e3573 100644
--- a/media/libmediaplayer2/JMedia2HTTPService.cpp
+++ b/media/libmediaplayer2/JMedia2HTTPService.cpp
@@ -25,8 +25,7 @@
 #include <mediaplayer2/JMedia2HTTPConnection.h>
 #include <media/stagefright/foundation/ADebug.h>
 
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/scoped_local_ref.h>
 
 namespace android {
 
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 53f2fb1..ae7ac59 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -1124,8 +1124,10 @@
     // completed) so the state change to "prepared" might not have happened yet (e.g., buffering).
     // Still, we can allow prepareDrm for the use case of being called in OnDrmInfoListener.
     if (!(mCurrentState & (MEDIA_PLAYER2_PREPARING | MEDIA_PLAYER2_PREPARED))) {
-        ALOGE("prepareDrm is called in the wrong state (%d).", mCurrentState);
-        return INVALID_OPERATION;
+        ALOGW("prepareDrm(%lld) called in non-prepare state(%d)", (long long)srcId, mCurrentState);
+        if (srcId == mSrcId) {
+            return INVALID_OPERATION;
+        }
     }
 
     if (drmSessionId.isEmpty()) {
diff --git a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
index bbd22bc..89703de 100644
--- a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
+++ b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
@@ -22,7 +22,6 @@
 
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/Utils.h>
-#include <nativehelper/JNIHelp.h>
 #include <utils/Log.h>
 
 #include "log/log.h"
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9bcfc83..96f79e0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1906,10 +1906,16 @@
         if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
             return NO_INIT;
         }
+        if (afSampleRate == 0) {
+            return NO_INIT;
+        }
         const size_t framesPerBuffer =
                 (unsigned long long)sampleRate * afFrameCount / afSampleRate;
 
         if (bufferCount == 0) {
+            if (framesPerBuffer == 0) {
+                return NO_INIT;
+            }
             // use suggestedFrameCount
             bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index df1ffde..6d69d50 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -678,7 +678,7 @@
         msg->setSize("buffer-ix", index);
 
         sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
-        ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
+        ALOGV("[%s] resubmitting CSD", mComponentName.c_str());
         msg->setBuffer("buffer", buffer);
         mCSDsToSubmit.removeAt(0);
         if (!onInputBufferFetched(msg)) {
@@ -749,7 +749,7 @@
     reply->setSize("size", size);
 
     if (eos) {
-        ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
+        ALOGV("[%s] saw output EOS", mIsAudio ? "audio" : "video");
 
         buffer->meta()->setInt32("eos", true);
         reply->setInt32("eos", true);
@@ -1029,7 +1029,7 @@
             int64_t resumeAtMediaTimeUs;
             if (extra->findInt64(
                         "resume-at-mediaTimeUs", &resumeAtMediaTimeUs)) {
-                ALOGI("[%s] suppressing rendering until %lld us",
+                ALOGV("[%s] suppressing rendering until %lld us",
                         mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
                 mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
             }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index ba3ebaa..a820445 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -329,7 +329,7 @@
 }
 
 status_t NuPlayerDriver::start() {
-    ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
+    ALOGV("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
     Mutex::Autolock autoLock(mLock);
     return start_l();
 }
@@ -471,7 +471,7 @@
 }
 
 status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) {
-    ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
+    ALOGV("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
     Mutex::Autolock autoLock(mLock);
 
     int64_t seekTimeUs = msec * 1000LL;
@@ -965,7 +965,7 @@
 
 void NuPlayerDriver::notifyListener_l(
         int msg, int ext1, int ext2, const Parcel *in) {
-    ALOGD("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
+    ALOGV("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
             this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
     switch (msg) {
         case MEDIA_PLAYBACK_COMPLETE:
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index 67a0f1e..2d0c9e0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -159,9 +159,12 @@
     if (drm != NULL) {
         for (size_t i = 0; i < psshDRMs.size(); i++) {
             DrmUUID uuid = psshDRMs[i];
-            if (drm->isCryptoSchemeSupported(uuid.ptr(), String8(),
-                            DrmPlugin::kSecurityLevelUnknown))
+            bool isSupported = false;
+            status = drm->isCryptoSchemeSupported(uuid.ptr(), String8(),
+                    DrmPlugin::kSecurityLevelUnknown, &isSupported);
+            if (status == OK && isSupported) {
                 supportedDRMs.add(uuid);
+            }
         }
 
         drm.clear();
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index c14983a..877cb5a 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -23,6 +23,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
+#define MAX_CHANNEL_COUNT            6  /* maximum number of audio channels that can be decoded */
+
 namespace android {
 
 template<class T>
@@ -184,7 +186,7 @@
                 return OMX_ErrorUndefined;
             }
 
-            if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
+            if (pcmParams->nChannels < 1 || pcmParams->nChannels > MAX_CHANNEL_COUNT) {
                 return OMX_ErrorUndefined;
             }
 
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 325084c..c581e9d 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -261,7 +261,7 @@
         return false;
     }
 
-    if (strncmp(value.c_str(), "npt=", 4)) {
+    if (strncmp(value.c_str(), "npt=", 4) && strncmp(value.c_str(), "npt:", 4)) {
         return false;
     }
 
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 1a0c3b1..010c1aa 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -308,6 +308,9 @@
         ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
         return AMEDIA_ERROR_UNKNOWN;
     }
+    if (mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
+        gbConsumer->setConsumerIsProtected(true);
+    }
 
     mSurface = new Surface(mProducer, /*controlledByApp*/true);
     if (mSurface == nullptr) {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 9082f62..2deb1a4 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -274,7 +274,10 @@
     }
 
     String8 mimeStr = mimeType ? String8(mimeType) : String8("");
-    return drm->isCryptoSchemeSupported(uuid, mimeStr, DrmPlugin::kSecurityLevelUnknown);
+    bool isSupported = false;
+    status_t status = drm->isCryptoSchemeSupported(uuid, mimeStr,
+            DrmPlugin::kSecurityLevelUnknown, &isSupported);
+    return (status == OK) && isSupported;
 }
 
 EXPORT
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 6ab6369..8455e54 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1136,7 +1136,8 @@
     // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
     if (isProcessEnabled() &&
             ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL ||
-            (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND)) {
+             (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND ||
+             (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_MONITOR)) {
         uint32_t volume[2];
         uint32_t *pVolume = NULL;
         uint32_t size = sizeof(volume);
@@ -1331,6 +1332,7 @@
     case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
     case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
     case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
+    case EFFECT_FLAG_VOLUME_MONITOR: s.append("monitors volume"); break;
     default: s.append("unknown/reserved"); break;
     }
     s.append(", ");
@@ -2277,7 +2279,7 @@
     }
     // then indicate volume to all other effects in chain.
     // Pass altered volume to effects before volume controller
-    // and requested volume to effects after controller
+    // and requested volume to effects after controller or with volume monitor flag
     uint32_t lVol = newLeft;
     uint32_t rVol = newRight;
 
@@ -2290,7 +2292,12 @@
             lVol = *left;
             rVol = *right;
         }
-        mEffects[i]->setVolume(&lVol, &rVol, false);
+        // Pass requested volume directly if this is volume monitor module
+        if (mEffects[i]->isVolumeMonitor()) {
+            mEffects[i]->setVolume(left, right, false);
+        } else {
+            mEffects[i]->setVolume(&lVol, &rVol, false);
+        }
     }
     *left = newLeft;
     *right = newRight;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 15a26ea..58ce351 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -134,6 +134,9 @@
     bool             isVolumeControl() const
                         { return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
                             == EFFECT_FLAG_VOLUME_CTRL; }
+    bool             isVolumeMonitor() const
+                        { return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
+                            == EFFECT_FLAG_VOLUME_MONITOR; }
     status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
     bool             isOffloaded() const;
     void             addEffectToHal_l();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 31a8c7d..9f838a3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5329,16 +5329,9 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
-    :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
-{
-}
-
-AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
+        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device,
         ThreadBase::type_t type, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
-        , mVolumeShaperActive(false)
 {
 }
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index aab7601..8b8222c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1205,7 +1205,9 @@
 public:
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                       audio_io_handle_t id, audio_devices_t device, bool systemReady);
+                       audio_io_handle_t id, audio_devices_t device, bool systemReady)
+        : DirectOutputThread(audioFlinger, output, id, device, DIRECT, systemReady) { }
+
     virtual                 ~DirectOutputThread();
 
                 status_t    selectPresentation(int presentationId, int programId);
@@ -1231,10 +1233,10 @@
 
     virtual     void        onAddNewTrack_l();
 
-    bool mVolumeShaperActive;
+    bool mVolumeShaperActive = false;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, uint32_t device, ThreadBase::type_t type,
+                        audio_io_handle_t id, audio_devices_t device, ThreadBase::type_t type,
                         bool systemReady);
     void processVolume_l(Track *track, bool lastTrack);
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index dc409a7..e0b56d4 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -121,6 +121,9 @@
 
     bool deviceSupportsEncodedFormats(audio_devices_t device) const
     {
+        if (device == AUDIO_DEVICE_NONE) {
+            return true; // required for isOffloadSupported() check
+        }
         DeviceVector deviceList =
             mSupportedDevices.getDevicesFromTypeMask(device);
         if (!deviceList.empty()) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 55d4db4..c880e67 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -257,15 +257,21 @@
 void AudioInputDescriptor::close()
 {
     if (mIoHandle != AUDIO_IO_HANDLE_NONE) {
+        // clean up active clients if any (can happen if close() is called to force
+        // clients to reconnect
+        for (const auto &client : getClientIterable()) {
+            if (client->active()) {
+                ALOGW("%s client with port ID %d still active on input %d",
+                    __func__, client->portId(), mId);
+                setClientActive(client, false);
+                stop();
+            }
+        }
+
         mClientInterface->closeInput(mIoHandle);
         LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
                             __FUNCTION__, mProfile->curOpenCount);
-        // do not call stop() here as stop() is supposed to be called after
-        //  setClientActive(client, false) and we don't know how many clients
-        // are still active at this time
-        if (isActive()) {
-            mProfile->curActiveCount--;
-        }
+
         mProfile->curOpenCount--;
         LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount <  mProfile->curActiveCount,
                 "%s(%d): mProfile->curOpenCount %d < mProfile->curActiveCount %d.",
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 57328f0..78b3f45 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -563,6 +563,17 @@
 void SwAudioOutputDescriptor::close()
 {
     if (mIoHandle != AUDIO_IO_HANDLE_NONE) {
+        // clean up active clients if any (can happen if close() is called to force
+        // clients to reconnect
+        for (const auto &client : getClientIterable()) {
+            if (client->active()) {
+                ALOGW("%s client with port ID %d still active on output %d",
+                      __func__, client->portId(), mId);
+                setClientActive(client, false);
+                stop();
+            }
+        }
+
         AudioParameter param;
         param.add(String8("closing"), String8("true"));
         mClientInterface->setParameters(mIoHandle, param.toString());
@@ -571,11 +582,6 @@
 
         LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
                             __FUNCTION__, mProfile->curOpenCount);
-        // do not call stop() here as stop() is supposed to be called after setClientActive(false)
-        // and we don't know how many streams are still active at this time
-        if (isActive()) {
-            mProfile->curActiveCount--;
-        }
         mProfile->curOpenCount--;
         mIoHandle = AUDIO_IO_HANDLE_NONE;
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 1bc4ec8..dc5b238 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -51,12 +51,6 @@
         mEncodedFormats.add(AUDIO_FORMAT_AC3);
         mEncodedFormats.add(AUDIO_FORMAT_IEC61937);
     }
-    // For backward compatibility always indicate support for SBC and AAC if no
-    // supported format is listed in the configuration file
-    if ((type & AUDIO_DEVICE_OUT_ALL_A2DP) != 0 && mEncodedFormats.isEmpty()) {
-        mEncodedFormats.add(AUDIO_FORMAT_SBC);
-        mEncodedFormats.add(AUDIO_FORMAT_AAC);
-    }
 }
 
 audio_port_handle_t DeviceDescriptor::getId() const
@@ -102,11 +96,19 @@
     if (!device_has_encoding_capability(type())) {
         return true;
     }
+    if (mEncodedFormats.isEmpty()) {
+        return true;
+    }
+
     return (mCurrentEncodedFormat != AUDIO_FORMAT_DEFAULT);
 }
 
 bool DeviceDescriptor::supportsFormat(audio_format_t format)
 {
+    if (mEncodedFormats.isEmpty()) {
+        return true;
+    }
+
     for (const auto& devFormat : mEncodedFormats) {
         if (devFormat == format) {
             return true;
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 85d9bce..e0b233d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -332,10 +332,8 @@
         if (moduleDevice) {
             if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
                 moduleDevice->setEncodedFormat(encodedFormat);
-                if (moduleDevice->address() != devAddress) {
-                    moduleDevice->setAddress(devAddress);
-                }
             }
+            moduleDevice->setAddress(devAddress);
             if (allowToCreate) {
                 moduleDevice->attach(hwModule);
             }
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 1934fa4..09faa4c 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -65,6 +65,8 @@
 
 const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
     "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
+const char *const ParameterManagerWrapper::mPolicyPfwVendorConfFileName =
+    "/vendor/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
 
 static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
 static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
@@ -96,7 +98,11 @@
     : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
 {
     // Connector
-    mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
+    if (access(mPolicyPfwVendorConfFileName, R_OK) == 0) {
+        mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwVendorConfFileName);
+    } else {
+        mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
+    }
 
     // Logger
     mPfwConnector->setLogger(mPfwConnectorLogger);
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 1a634a1..cd39b6f 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -199,6 +199,7 @@
     struct parameterManagerElementSupported;
 
     static const char *const mPolicyPfwDefaultConfFileName; /**< Default Policy PFW top file name.*/
+    static const char *const mPolicyPfwVendorConfFileName; /**< Vendor Policy PFW top file name.*/
 };
 
 } // namespace audio_policy
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index cf9c298..46f51e5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -555,7 +555,6 @@
         muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
     } else { // create RX path audio patch
         mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevices.itemAt(0), delayMs);
-        ALOG_ASSERT(createTxPatch, "No Tx Patch will be created, nor legacy routing done");
     }
     if (createTxPatch) { // create TX path audio patch
         mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 416817f..a39477d 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -880,9 +880,8 @@
         if (it == mA11yUids.end()) {
             continue;
         }
-        if (uid.second.second == ActivityManager::PROCESS_STATE_TOP ||
-            uid.second.second == ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE ||
-            uid.second.second == ActivityManager::PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+        if (uid.second.second >= ActivityManager::PROCESS_STATE_TOP
+                && uid.second.second <= ActivityManager::PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
             return true;
         }
     }
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 851dd69..a090479 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -39,6 +39,8 @@
         "api1/client2/CaptureSequencer.cpp",
         "api1/client2/ZslProcessor.cpp",
         "api2/CameraDeviceClient.cpp",
+        "api2/CompositeStream.cpp",
+        "api2/DepthCompositeStream.cpp",
         "device1/CameraHardwareInterface.cpp",
         "device3/Camera3Device.cpp",
         "device3/Camera3Stream.cpp",
@@ -65,6 +67,7 @@
     ],
 
     shared_libs: [
+        "libdl",
         "libui",
         "liblog",
         "libutilscallstack",
@@ -108,6 +111,8 @@
         "system/media/private/camera/include",
         "frameworks/native/include/media/openmax",
         "frameworks/av/media/ndk",
+        "external/dynamic_depth/includes",
+        "external/dynamic_depth/internal",
     ],
 
     export_include_dirs: ["."],
@@ -116,6 +121,42 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-Wno-ignored-qualifiers",
+    ],
+
+}
+
+cc_library_shared {
+    name: "libdepthphoto",
+
+    srcs: [
+        "common/DepthPhotoProcessor.cpp",
+    ],
+
+    shared_libs: [
+        "libimage_io",
+        "libdynamic_depth",
+        "libxml2",
+        "liblog",
+        "libutilscallstack",
+        "libutils",
+        "libcutils",
+        "libjpeg",
+        "libmemunreachable",
+    ],
+
+    include_dirs: [
+        "external/dynamic_depth/includes",
+        "external/dynamic_depth/internal",
+    ],
+
+    export_include_dirs: ["."],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wno-ignored-qualifiers",
     ],
 
 }
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index b7020fe..e6f75f4 100755
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -62,6 +62,10 @@
     }
 }
 
+void JpegProcessor::onBufferRequestForFrameNumber(uint64_t /*frameNumber*/, int /*streamId*/) {
+    // Intentionally left empty
+}
+
 void JpegProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
     // Intentionally left empty
 }
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index 7187ad9..2ee930e 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -25,6 +25,7 @@
 #include <gui/CpuConsumer.h>
 
 #include "camera/CameraMetadata.h"
+#include "device3/Camera3StreamBufferListener.h"
 
 namespace android {
 
@@ -53,12 +54,16 @@
     // Camera3StreamBufferListener implementation
     void onBufferAcquired(const BufferInfo& bufferInfo) override;
     void onBufferReleased(const BufferInfo& bufferInfo) override;
+    void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) override;
 
     status_t updateStream(const Parameters &params);
     status_t deleteStream();
     int getStreamId() const;
 
     void dump(int fd, const Vector<String16>& args) const;
+
+    static size_t findJpegSize(uint8_t* jpegBuffer, size_t maxSize);
+
   private:
     static const nsecs_t kWaitDuration = 10000000; // 10 ms
     wp<CameraDeviceBase> mDevice;
@@ -82,7 +87,6 @@
     virtual bool threadLoop();
 
     status_t processNewCapture(bool captureSuccess);
-    size_t findJpegSize(uint8_t* jpegBuffer, size_t maxSize);
 
 };
 
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 46fbc3e..9e203da 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -33,6 +33,8 @@
 
 #include <camera_metadata_hidden.h>
 
+#include "DepthCompositeStream.h"
+
 // Convenience methods for constructing binder::Status objects for error returns
 
 #define STATUS_ERROR(errorCode, errorString) \
@@ -143,6 +145,7 @@
 
 binder::Status CameraDeviceClient::insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
         SurfaceMap* outSurfaceMap, Vector<int32_t>* outputStreamIds, int32_t *currentStreamId) {
+    int compositeIdx;
     int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));
 
     // Trying to submit request with surface that wasn't created
@@ -152,6 +155,11 @@
                 __FUNCTION__, mCameraIdStr.string());
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                 "Request targets Surface that is not part of current capture session");
+    } else if ((compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp)))
+            != NAME_NOT_FOUND) {
+        mCompositeStreamMap.valueAt(compositeIdx)->insertGbp(outSurfaceMap, outputStreamIds,
+                currentStreamId);
+        return binder::Status::ok();
     }
 
     const StreamSurfaceId& streamSurfaceId = mStreamMap.valueAt(idx);
@@ -489,6 +497,17 @@
                 mCameraIdStr.string(), strerror(-err), err);
         ALOGE("%s: %s", __FUNCTION__, msg.string());
         res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+    } else {
+        for (size_t i = 0; i < mCompositeStreamMap.size(); ++i) {
+            err = mCompositeStreamMap.valueAt(i)->configureStream();
+            if (err != OK ) {
+                String8 msg = String8::format("Camera %s: Error configuring composite "
+                        "streams: %s (%d)", mCameraIdStr.string(), strerror(-err), err);
+                ALOGE("%s: %s", __FUNCTION__, msg.string());
+                res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+                break;
+            }
+        }
     }
 
     return res;
@@ -692,8 +711,35 @@
                 return res;
 
             if (!isStreamInfoValid) {
-                mapStreamInfo(streamInfo, static_cast<camera3_stream_rotation_t> (it.getRotation()),
-                        physicalCameraId, &streamConfiguration.streams[streamIdx++]);
+                if (camera3::DepthCompositeStream::isDepthCompositeStream(surface)) {
+                    // We need to take in to account that composite streams can have
+                    // additional internal camera streams.
+                    std::vector<OutputStreamInfo> compositeStreams;
+                    ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
+                            mDevice->info(), &compositeStreams);
+                    if (ret != OK) {
+                        String8 msg = String8::format(
+                                "Camera %s: Failed adding depth composite streams: %s (%d)",
+                                mCameraIdStr.string(), strerror(-ret), ret);
+                        ALOGE("%s: %s", __FUNCTION__, msg.string());
+                        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+                    }
+
+                    if (compositeStreams.size() > 1) {
+                        streamCount += compositeStreams.size() - 1;
+                        streamConfiguration.streams.resize(streamCount);
+                    }
+
+                    for (const auto& compositeStream : compositeStreams) {
+                        mapStreamInfo(compositeStream,
+                                static_cast<camera3_stream_rotation_t> (it.getRotation()),
+                                physicalCameraId, &streamConfiguration.streams[streamIdx++]);
+                    }
+                } else {
+                    mapStreamInfo(streamInfo,
+                            static_cast<camera3_stream_rotation_t> (it.getRotation()),
+                            physicalCameraId, &streamConfiguration.streams[streamIdx++]);
+                }
                 isStreamInfoValid = true;
             }
         }
@@ -743,6 +789,7 @@
     bool isInput = false;
     std::vector<sp<IBinder>> surfaces;
     ssize_t dIndex = NAME_NOT_FOUND;
+    ssize_t compositeIndex  = NAME_NOT_FOUND;
 
     if (mInputStream.configured && mInputStream.id == streamId) {
         isInput = true;
@@ -762,6 +809,13 @@
             }
         }
 
+        for (size_t i = 0; i < mCompositeStreamMap.size(); ++i) {
+            if (streamId == mCompositeStreamMap.valueAt(i)->getStreamId()) {
+                compositeIndex = i;
+                break;
+            }
+        }
+
         if (surfaces.empty() && dIndex == NAME_NOT_FOUND) {
             String8 msg = String8::format("Camera %s: Invalid stream ID (%d) specified, no such"
                     " stream created yet", mCameraIdStr.string(), streamId);
@@ -791,6 +845,19 @@
             if (dIndex != NAME_NOT_FOUND) {
                 mDeferredStreams.removeItemsAt(dIndex);
             }
+
+            if (compositeIndex != NAME_NOT_FOUND) {
+                status_t ret;
+                if ((ret = mCompositeStreamMap.valueAt(compositeIndex)->deleteStream())
+                        != OK) {
+                    String8 msg = String8::format("Camera %s: Unexpected error %s (%d) when "
+                            "deleting composite stream %d", mCameraIdStr.string(), strerror(-err), err,
+                            streamId);
+                    ALOGE("%s: %s", __FUNCTION__, msg.string());
+                    res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+                }
+                mCompositeStreamMap.removeItemsAt(compositeIndex);
+            }
         }
     }
 
@@ -870,11 +937,25 @@
 
     int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
     std::vector<int> surfaceIds;
-    err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
-            streamInfo.height, streamInfo.format, streamInfo.dataSpace,
-            static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
-            &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
-            isShared);
+    if (!camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0])) {
+        err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
+                streamInfo.height, streamInfo.format, streamInfo.dataSpace,
+                static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
+                &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
+                isShared);
+    } else {
+        sp<CompositeStream> compositeStream = new camera3::DepthCompositeStream(mDevice,
+                getRemoteCallback());
+        err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width,
+                streamInfo.height, streamInfo.format,
+                static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
+                &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
+                isShared);
+        if (err == OK) {
+            mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
+                    compositeStream);
+        }
+    }
 
     if (err != OK) {
         res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -1808,7 +1889,14 @@
     // Thread safe. Don't bother locking.
     sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
 
-    if (remoteCb != 0) {
+    // Composites can have multiple internal streams. Error notifications coming from such internal
+    // streams may need to remain within camera service.
+    bool skipClientNotification = false;
+    for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+        skipClientNotification |= mCompositeStreamMap.valueAt(i)->onError(errorCode, resultExtras);
+    }
+
+    if ((remoteCb != 0) && (!skipClientNotification)) {
         remoteCb->onDeviceError(errorCode, resultExtras);
     }
 }
@@ -1901,6 +1989,10 @@
         remoteCb->onResultReceived(result.mMetadata, result.mResultExtras,
                 result.mPhysicalMetadatas);
     }
+
+    for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+        mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
+    }
 }
 
 binder::Status CameraDeviceClient::checkPidStatus(const char* checkLocation) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 17a0983..1c5abb0 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -26,8 +26,10 @@
 #include "CameraService.h"
 #include "common/FrameProcessorBase.h"
 #include "common/Camera2ClientBase.h"
+#include "CompositeStream.h"
 
 using android::camera3::OutputStreamInfo;
+using android::camera3::CompositeStream;
 
 namespace android {
 
@@ -314,6 +316,8 @@
     // stream ID -> outputStreamInfo mapping
     std::unordered_map<int32_t, OutputStreamInfo> mStreamInfoMap;
 
+    KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
+
     static const int32_t MAX_SURFACES_PER_STREAM = 4;
     sp<CameraProviderManager> mProviderManager;
 };
diff --git a/services/camera/libcameraservice/api2/CompositeStream.cpp b/services/camera/libcameraservice/api2/CompositeStream.cpp
new file mode 100644
index 0000000..796bf42
--- /dev/null
+++ b/services/camera/libcameraservice/api2/CompositeStream.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera3-CompositeStream"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "common/CameraDeviceBase.h"
+#include "CameraDeviceClient.h"
+#include "CompositeStream.h"
+
+namespace android {
+namespace camera3 {
+
+CompositeStream::CompositeStream(wp<CameraDeviceBase> device,
+        wp<hardware::camera2::ICameraDeviceCallbacks> cb) :
+        mDevice(device),
+        mRemoteCallback(cb),
+        mNumPartialResults(1),
+        mErrorState(false) {
+    sp<CameraDeviceBase> cameraDevice = device.promote();
+    if (cameraDevice.get() != nullptr) {
+        CameraMetadata staticInfo = cameraDevice->info();
+        camera_metadata_entry_t entry = staticInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+        if (entry.count > 0) {
+            mNumPartialResults = entry.data.i32[0];
+        }
+    }
+}
+
+status_t CompositeStream::createStream(const std::vector<sp<Surface>>& consumers,
+        bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
+        camera3_stream_rotation_t rotation, int * id, const String8& physicalCameraId,
+        std::vector<int> * surfaceIds, int streamSetId, bool isShared) {
+    if (hasDeferredConsumer) {
+        ALOGE("%s: Deferred consumers not supported in case of composite streams!",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (streamSetId != camera3::CAMERA3_STREAM_ID_INVALID) {
+        ALOGE("%s: Surface groups not supported in case of composite streams!",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (isShared) {
+        ALOGE("%s: Shared surfaces not supported in case of composite streams!",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    return createInternalStreams(consumers, hasDeferredConsumer, width, height, format, rotation, id,
+            physicalCameraId, surfaceIds, streamSetId, isShared);
+}
+
+status_t CompositeStream::deleteStream() {
+    {
+        Mutex::Autolock l(mMutex);
+        mPendingCaptureResults.clear();
+        mCaptureResults.clear();
+        mFrameNumberMap.clear();
+        mErrorFrameNumbers.clear();
+    }
+
+    return deleteInternalStreams();
+}
+
+void CompositeStream::onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) {
+    Mutex::Autolock l(mMutex);
+    if (!mErrorState && (streamId == getStreamId())) {
+        mPendingCaptureResults.emplace(frameNumber, CameraMetadata());
+    }
+}
+
+void CompositeStream::onBufferReleased(const BufferInfo& bufferInfo) {
+    Mutex::Autolock l(mMutex);
+    if (!mErrorState && !bufferInfo.mError) {
+        mFrameNumberMap.emplace(bufferInfo.mFrameNumber, bufferInfo.mTimestamp);
+        mInputReadyCondition.signal();
+    }
+}
+
+void CompositeStream::eraseResult(int64_t frameNumber) {
+    Mutex::Autolock l(mMutex);
+
+    auto it = mPendingCaptureResults.find(frameNumber);
+    if (it == mPendingCaptureResults.end()) {
+        return;
+    }
+
+    it = mPendingCaptureResults.erase(it);
+}
+
+void CompositeStream::onResultAvailable(const CaptureResult& result) {
+    bool resultError = false;
+    {
+        Mutex::Autolock l(mMutex);
+
+        uint64_t frameNumber = result.mResultExtras.frameNumber;
+        bool resultReady = false;
+        auto it = mPendingCaptureResults.find(frameNumber);
+        if (it != mPendingCaptureResults.end()) {
+            it->second.append(result.mMetadata);
+            if (result.mResultExtras.partialResultCount >= mNumPartialResults) {
+                auto entry = it->second.find(ANDROID_SENSOR_TIMESTAMP);
+                if (entry.count == 1) {
+                    auto ts = entry.data.i64[0];
+                    mCaptureResults.emplace(ts, std::make_tuple(frameNumber, it->second));
+                    resultReady = true;
+                } else {
+                    ALOGE("%s: Timestamp metadata entry missing for frameNumber: %" PRIu64,
+                            __FUNCTION__, frameNumber);
+                    resultError = true;
+                }
+                mPendingCaptureResults.erase(it);
+            }
+        }
+
+        if (resultReady) {
+            mInputReadyCondition.signal();
+        }
+    }
+
+    if (resultError) {
+        onResultError(result.mResultExtras);
+    }
+}
+
+void CompositeStream::flagAnErrorFrameNumber(int64_t frameNumber) {
+    Mutex::Autolock l(mMutex);
+    mErrorFrameNumbers.emplace(frameNumber);
+    mInputReadyCondition.signal();
+}
+
+status_t CompositeStream::registerCompositeStreamListener(int32_t streamId) {
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device.get() == nullptr) {
+        return NO_INIT;
+    }
+
+    auto ret = device->addBufferListenerForStream(streamId, this);
+    if (ret != OK) {
+        ALOGE("%s: Failed to register composite stream listener!", __FUNCTION__);
+    }
+
+    return ret;
+}
+
+bool CompositeStream::onError(int32_t errorCode, const CaptureResultExtras& resultExtras) {
+    auto ret = false;
+    switch (errorCode) {
+        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
+            onResultError(resultExtras);
+            break;
+        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
+            ret = onStreamBufferError(resultExtras);
+            break;
+        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
+            // Invalid request, this shouldn't affect composite streams.
+            break;
+        default:
+            ALOGE("%s: Unrecoverable error: %d detected!", __FUNCTION__, errorCode);
+            Mutex::Autolock l(mMutex);
+            mErrorState = true;
+            break;
+    }
+
+    return ret;
+}
+
+void CompositeStream::notifyError(int64_t frameNumber) {
+    sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb =
+        mRemoteCallback.promote();
+
+    if ((frameNumber >= 0) && (remoteCb.get() != nullptr)) {
+        CaptureResultExtras extras;
+        extras.errorStreamId = getStreamId();
+        extras.frameNumber = frameNumber;
+        remoteCb->onDeviceError(
+                hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER,
+                extras);
+    }
+}
+
+}; // namespace camera3
+}; // namespace android
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
new file mode 100644
index 0000000..5837745
--- /dev/null
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -0,0 +1,120 @@
+/*
+ * 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 ANDROID_SERVERS_CAMERA_CAMERA3_COMPOSITE_STREAM_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3_COMPOSITE_STREAM_H
+
+#include <set>
+#include <unordered_map>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+#include <camera/CameraMetadata.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include "common/CameraDeviceBase.h"
+#include "device3/Camera3StreamInterface.h"
+
+namespace android {
+
+class CameraDeviceClient;
+class CameraMetadata;
+class Surface;
+
+namespace camera3 {
+
+class CompositeStream : public camera3::Camera3StreamBufferListener {
+
+public:
+    CompositeStream(wp<CameraDeviceBase> device, wp<hardware::camera2::ICameraDeviceCallbacks> cb);
+    virtual ~CompositeStream() {}
+
+    status_t createStream(const std::vector<sp<Surface>>& consumers,
+            bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
+            camera3_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+            std::vector<int> *surfaceIds, int streamSetId, bool isShared);
+
+    status_t deleteStream();
+
+    // Create and register all internal camera streams.
+    virtual status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+            bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
+            camera3_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+            std::vector<int> *surfaceIds, int streamSetId, bool isShared) = 0;
+
+    // Release all internal streams and corresponding resources.
+    virtual status_t deleteInternalStreams() = 0;
+
+    // Stream configuration completed.
+    virtual status_t configureStream() = 0;
+
+    // Insert the internal composite stream id in the user capture request.
+    virtual status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap,
+            Vector<int32_t>* /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) = 0;
+
+    // Return composite stream id.
+    virtual int getStreamId() = 0;
+
+    void onResultAvailable(const CaptureResult& result);
+    bool onError(int32_t errorCode, const CaptureResultExtras& resultExtras);
+
+    // Camera3StreamBufferListener implementation
+    void onBufferAcquired(const BufferInfo& /*bufferInfo*/) override { /*Empty for now */ }
+    void onBufferReleased(const BufferInfo& bufferInfo) override;
+    void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) override;
+
+protected:
+    status_t registerCompositeStreamListener(int32_t streamId);
+    void eraseResult(int64_t frameNumber);
+    void flagAnErrorFrameNumber(int64_t frameNumber);
+    void notifyError(int64_t frameNumber);
+
+    // Subclasses should check for buffer errors from internal streams and return 'true' in
+    // case the error notification should remain within camera service.
+    virtual bool onStreamBufferError(const CaptureResultExtras& resultExtras) = 0;
+
+    // Subclasses can decide how to handle result errors depending on whether or not the
+    // internal processing needs result data.
+    virtual void onResultError(const CaptureResultExtras& resultExtras) = 0;
+
+    // Device and/or service is in unrecoverable error state.
+    // Composite streams should behave accordingly.
+    void enableErrorState();
+
+    wp<CameraDeviceBase>   mDevice;
+    wp<hardware::camera2::ICameraDeviceCallbacks> mRemoteCallback;
+
+    mutable Mutex          mMutex;
+    Condition              mInputReadyCondition;
+    int32_t                mNumPartialResults;
+    bool                   mErrorState;
+
+    // Frame number to capture result map of partial pending request results.
+    std::unordered_map<uint64_t, CameraMetadata> mPendingCaptureResults;
+
+    // Timestamp to capture (frame number, result) map of completed pending request results.
+    std::unordered_map<int64_t, std::tuple<int64_t, CameraMetadata>> mCaptureResults;
+
+    // Frame number to timestamp map
+    std::unordered_map<int64_t, int64_t> mFrameNumberMap;
+
+    // Keeps a set buffer/result frame numbers for any errors detected during processing.
+    std::set<int64_t> mErrorFrameNumbers;
+
+};
+
+}; //namespace camera3
+}; //namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
new file mode 100644
index 0000000..f627b25
--- /dev/null
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -0,0 +1,802 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera3-DepthCompositeStream"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include "api1/client2/JpegProcessor.h"
+#include "common/CameraProviderManager.h"
+#include "dlfcn.h"
+#include <gui/Surface.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "DepthCompositeStream.h"
+
+namespace android {
+namespace camera3 {
+
+DepthCompositeStream::DepthCompositeStream(wp<CameraDeviceBase> device,
+        wp<hardware::camera2::ICameraDeviceCallbacks> cb) :
+        CompositeStream(device, cb),
+        mBlobStreamId(-1),
+        mBlobSurfaceId(-1),
+        mDepthStreamId(-1),
+        mDepthSurfaceId(-1),
+        mBlobWidth(0),
+        mBlobHeight(0),
+        mDepthBufferAcquired(false),
+        mBlobBufferAcquired(false),
+        mProducerListener(new ProducerListener()),
+        mMaxJpegSize(-1),
+        mIsLogicalCamera(false),
+        mDepthPhotoLibHandle(nullptr),
+        mDepthPhotoProcess(nullptr) {
+    sp<CameraDeviceBase> cameraDevice = device.promote();
+    if (cameraDevice.get() != nullptr) {
+        CameraMetadata staticInfo = cameraDevice->info();
+        auto entry = staticInfo.find(ANDROID_JPEG_MAX_SIZE);
+        if (entry.count > 0) {
+            mMaxJpegSize = entry.data.i32[0];
+        } else {
+            ALOGW("%s: Maximum jpeg size absent from camera characteristics", __FUNCTION__);
+        }
+
+        entry = staticInfo.find(ANDROID_LENS_INTRINSIC_CALIBRATION);
+        if (entry.count == 5) {
+            mInstrinsicCalibration.reserve(5);
+            mInstrinsicCalibration.insert(mInstrinsicCalibration.end(), entry.data.f,
+                    entry.data.f + 5);
+        } else {
+            ALOGW("%s: Intrinsic calibration absent from camera characteristics!", __FUNCTION__);
+        }
+
+        entry = staticInfo.find(ANDROID_LENS_DISTORTION);
+        if (entry.count == 5) {
+            mLensDistortion.reserve(5);
+            mLensDistortion.insert(mLensDistortion.end(), entry.data.f, entry.data.f + 5);
+        } else {
+            ALOGW("%s: Lens distortion absent from camera characteristics!", __FUNCTION__);
+        }
+
+        entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+        for (size_t i = 0; i < entry.count; ++i) {
+            uint8_t capability = entry.data.u8[i];
+            if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+                mIsLogicalCamera = true;
+                break;
+            }
+        }
+
+        getSupportedDepthSizes(staticInfo, &mSupportedDepthSizes);
+
+        mDepthPhotoLibHandle = dlopen(camera3::kDepthPhotoLibrary, RTLD_NOW | RTLD_LOCAL);
+        if (mDepthPhotoLibHandle != nullptr) {
+            mDepthPhotoProcess = reinterpret_cast<camera3::process_depth_photo_frame> (
+                    dlsym(mDepthPhotoLibHandle, camera3::kDepthPhotoProcessFunction));
+            if (mDepthPhotoProcess == nullptr) {
+                ALOGE("%s: Failed to link to depth photo process function: %s", __FUNCTION__,
+                        dlerror());
+            }
+        } else {
+            ALOGE("%s: Failed to link to depth photo library: %s", __FUNCTION__, dlerror());
+        }
+
+    }
+}
+
+DepthCompositeStream::~DepthCompositeStream() {
+    mBlobConsumer.clear(),
+    mBlobSurface.clear(),
+    mBlobStreamId = -1;
+    mBlobSurfaceId = -1;
+    mDepthConsumer.clear();
+    mDepthSurface.clear();
+    mDepthConsumer = nullptr;
+    mDepthSurface = nullptr;
+    if (mDepthPhotoLibHandle != nullptr) {
+        dlclose(mDepthPhotoLibHandle);
+        mDepthPhotoLibHandle = nullptr;
+    }
+    mDepthPhotoProcess = nullptr;
+}
+
+void DepthCompositeStream::compilePendingInputLocked() {
+    CpuConsumer::LockedBuffer imgBuffer;
+
+    while (!mInputJpegBuffers.empty() && !mBlobBufferAcquired) {
+        auto it = mInputJpegBuffers.begin();
+        auto res = mBlobConsumer->lockNextBuffer(&imgBuffer);
+        if (res == NOT_ENOUGH_DATA) {
+            // Can not lock any more buffers.
+            break;
+        } else if (res != OK) {
+            ALOGE("%s: Error locking blob image buffer: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            mPendingInputFrames[*it].error = true;
+            mInputJpegBuffers.erase(it);
+            continue;
+        }
+
+        if (*it != imgBuffer.timestamp) {
+            ALOGW("%s: Expecting jpeg buffer with time stamp: %" PRId64 " received buffer with "
+                    "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
+        }
+
+        if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
+                (mPendingInputFrames[imgBuffer.timestamp].error)) {
+            mBlobConsumer->unlockBuffer(imgBuffer);
+        } else {
+            mPendingInputFrames[imgBuffer.timestamp].jpegBuffer = imgBuffer;
+            mBlobBufferAcquired = true;
+        }
+        mInputJpegBuffers.erase(it);
+    }
+
+    while (!mInputDepthBuffers.empty() && !mDepthBufferAcquired) {
+        auto it = mInputDepthBuffers.begin();
+        auto res = mDepthConsumer->lockNextBuffer(&imgBuffer);
+        if (res == NOT_ENOUGH_DATA) {
+            // Can not lock any more buffers.
+            break;
+        } else if (res != OK) {
+            ALOGE("%s: Error receiving depth image buffer: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            mPendingInputFrames[*it].error = true;
+            mInputDepthBuffers.erase(it);
+            continue;
+        }
+
+        if (*it != imgBuffer.timestamp) {
+            ALOGW("%s: Expecting depth buffer with time stamp: %" PRId64 " received buffer with "
+                    "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
+        }
+
+        if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
+                (mPendingInputFrames[imgBuffer.timestamp].error)) {
+            mDepthConsumer->unlockBuffer(imgBuffer);
+        } else {
+            mPendingInputFrames[imgBuffer.timestamp].depthBuffer = imgBuffer;
+            mDepthBufferAcquired = true;
+        }
+        mInputDepthBuffers.erase(it);
+    }
+
+    while (!mCaptureResults.empty()) {
+        auto it = mCaptureResults.begin();
+        // Negative timestamp indicates that something went wrong during the capture result
+        // collection process.
+        if (it->first >= 0) {
+            mPendingInputFrames[it->first].frameNumber = std::get<0>(it->second);
+            mPendingInputFrames[it->first].result = std::get<1>(it->second);
+        }
+        mCaptureResults.erase(it);
+    }
+
+    while (!mFrameNumberMap.empty()) {
+        auto it = mFrameNumberMap.begin();
+        mPendingInputFrames[it->second].frameNumber = it->first;
+        mFrameNumberMap.erase(it);
+    }
+
+    auto it = mErrorFrameNumbers.begin();
+    while (it != mErrorFrameNumbers.end()) {
+        bool frameFound = false;
+        for (auto &inputFrame : mPendingInputFrames) {
+            if (inputFrame.second.frameNumber == *it) {
+                inputFrame.second.error = true;
+                frameFound = true;
+                break;
+            }
+        }
+
+        if (frameFound) {
+            it = mErrorFrameNumbers.erase(it);
+        } else {
+            ALOGW("%s: Not able to find failing input with frame number: %" PRId64, __FUNCTION__,
+                    *it);
+            it++;
+        }
+    }
+}
+
+bool DepthCompositeStream::getNextReadyInputLocked(int64_t *currentTs /*inout*/) {
+    if (currentTs == nullptr) {
+        return false;
+    }
+
+    bool newInputAvailable = false;
+    for (const auto& it : mPendingInputFrames) {
+        if ((!it.second.error) && (it.second.depthBuffer.data != nullptr) &&
+                (it.second.jpegBuffer.data != nullptr) && (it.first < *currentTs)) {
+            *currentTs = it.first;
+            newInputAvailable = true;
+        }
+    }
+
+    return newInputAvailable;
+}
+
+int64_t DepthCompositeStream::getNextFailingInputLocked(int64_t *currentTs /*inout*/) {
+    int64_t ret = -1;
+    if (currentTs == nullptr) {
+        return ret;
+    }
+
+    for (const auto& it : mPendingInputFrames) {
+        if (it.second.error && !it.second.errorNotified && (it.first < *currentTs)) {
+            *currentTs = it.first;
+            ret = it.second.frameNumber;
+        }
+    }
+
+    return ret;
+}
+
+status_t DepthCompositeStream::processInputFrame(const InputFrame &inputFrame) {
+    status_t res;
+    sp<ANativeWindow> outputANW = mOutputSurface;
+    ANativeWindowBuffer *anb;
+    int fenceFd;
+    void *dstBuffer;
+
+    auto jpegSize = android::camera2::JpegProcessor::findJpegSize(inputFrame.jpegBuffer.data,
+            inputFrame.jpegBuffer.width);
+    if (jpegSize == 0) {
+        ALOGW("%s: Failed to find input jpeg size, default to using entire buffer!", __FUNCTION__);
+        jpegSize = inputFrame.jpegBuffer.width;
+    }
+
+    size_t maxDepthJpegSize;
+    if (mMaxJpegSize > 0) {
+        maxDepthJpegSize = mMaxJpegSize;
+    } else {
+        maxDepthJpegSize = std::max<size_t> (jpegSize,
+                inputFrame.depthBuffer.width * inputFrame.depthBuffer.height * 3 / 2);
+    }
+    uint8_t jpegQuality = 100;
+    auto entry = inputFrame.result.find(ANDROID_JPEG_QUALITY);
+    if (entry.count > 0) {
+        jpegQuality = entry.data.u8[0];
+    }
+
+    // The final depth photo will consist of the main jpeg buffer, the depth map buffer (also in
+    // jpeg format) and confidence map (jpeg as well). Assume worst case that all 3 jpeg need
+    // max jpeg size.
+    size_t finalJpegBufferSize = maxDepthJpegSize * 3;
+
+    if ((res = native_window_set_buffers_dimensions(mOutputSurface.get(), finalJpegBufferSize, 1))
+            != OK) {
+        ALOGE("%s: Unable to configure stream buffer dimensions"
+                " %zux%u for stream %d", __FUNCTION__, finalJpegBufferSize, 1U, mBlobStreamId);
+        return res;
+    }
+
+    res = outputANW->dequeueBuffer(mOutputSurface.get(), &anb, &fenceFd);
+    if (res != OK) {
+        ALOGE("%s: Error retrieving output buffer: %s (%d)", __FUNCTION__, strerror(-res),
+                res);
+        return res;
+    }
+
+    sp<GraphicBuffer> gb = GraphicBuffer::from(anb);
+    res = gb->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, &dstBuffer, fenceFd);
+    if (res != OK) {
+        ALOGE("%s: Error trying to lock output buffer fence: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+        return res;
+    }
+
+    if ((gb->getWidth() < finalJpegBufferSize) || (gb->getHeight() != 1)) {
+        ALOGE("%s: Blob buffer size mismatch, expected %dx%d received %zux%u", __FUNCTION__,
+                gb->getWidth(), gb->getHeight(), finalJpegBufferSize, 1U);
+        outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+        return BAD_VALUE;
+    }
+
+    DepthPhotoInputFrame depthPhoto;
+    depthPhoto.mMainJpegBuffer = reinterpret_cast<const char*> (inputFrame.jpegBuffer.data);
+    depthPhoto.mMainJpegWidth = mBlobWidth;
+    depthPhoto.mMainJpegHeight = mBlobHeight;
+    depthPhoto.mMainJpegSize = jpegSize;
+    depthPhoto.mDepthMapBuffer = reinterpret_cast<uint16_t*> (inputFrame.depthBuffer.data);
+    depthPhoto.mDepthMapWidth = inputFrame.depthBuffer.width;
+    depthPhoto.mDepthMapHeight = inputFrame.depthBuffer.height;
+    depthPhoto.mDepthMapStride = inputFrame.depthBuffer.stride;
+    depthPhoto.mJpegQuality = jpegQuality;
+    depthPhoto.mIsLogical = mIsLogicalCamera;
+    depthPhoto.mMaxJpegSize = maxDepthJpegSize;
+    // The camera intrinsic calibration layout is as follows:
+    // [focalLengthX, focalLengthY, opticalCenterX, opticalCenterY, skew]
+    if (mInstrinsicCalibration.size() == 5) {
+        memcpy(depthPhoto.mInstrinsicCalibration, mInstrinsicCalibration.data(),
+                sizeof(depthPhoto.mInstrinsicCalibration));
+        depthPhoto.mIsInstrinsicCalibrationValid = 1;
+    } else {
+        depthPhoto.mIsInstrinsicCalibrationValid = 0;
+    }
+    // The camera lens distortion contains the following lens correction coefficients.
+    // [kappa_1, kappa_2, kappa_3 kappa_4, kappa_5]
+    if (mLensDistortion.size() == 5) {
+        memcpy(depthPhoto.mLensDistortion, mLensDistortion.data(),
+                sizeof(depthPhoto.mLensDistortion));
+        depthPhoto.mIsLensDistortionValid = 1;
+    } else {
+        depthPhoto.mIsLensDistortionValid = 0;
+    }
+
+    size_t actualJpegSize = 0;
+    res = mDepthPhotoProcess(depthPhoto, finalJpegBufferSize, dstBuffer, &actualJpegSize);
+    if (res != 0) {
+        ALOGE("%s: Depth photo processing failed: %s (%d)", __FUNCTION__, strerror(-res), res);
+        outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+        return res;
+    }
+
+    size_t finalJpegSize = actualJpegSize + sizeof(struct camera3_jpeg_blob);
+    if (finalJpegSize > finalJpegBufferSize) {
+        ALOGE("%s: Final jpeg buffer not large enough for the jpeg blob header", __FUNCTION__);
+        outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+        return NO_MEMORY;
+    }
+
+    ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegSize);
+    uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
+        (gb->getWidth() - sizeof(struct camera3_jpeg_blob));
+    struct camera3_jpeg_blob *blob = reinterpret_cast<struct camera3_jpeg_blob*> (header);
+    blob->jpeg_blob_id = CAMERA3_JPEG_BLOB_ID;
+    blob->jpeg_size = actualJpegSize;
+    outputANW->queueBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+
+    return res;
+}
+
+void DepthCompositeStream::releaseInputFrameLocked(InputFrame *inputFrame /*out*/) {
+    if (inputFrame == nullptr) {
+        return;
+    }
+
+    if (inputFrame->depthBuffer.data != nullptr) {
+        mDepthConsumer->unlockBuffer(inputFrame->depthBuffer);
+        inputFrame->depthBuffer.data = nullptr;
+        mDepthBufferAcquired = false;
+    }
+
+    if (inputFrame->jpegBuffer.data != nullptr) {
+        mBlobConsumer->unlockBuffer(inputFrame->jpegBuffer);
+        inputFrame->jpegBuffer.data = nullptr;
+        mBlobBufferAcquired = false;
+    }
+
+    if ((inputFrame->error || mErrorState) && !inputFrame->errorNotified) {
+        notifyError(inputFrame->frameNumber);
+        inputFrame->errorNotified = true;
+    }
+}
+
+void DepthCompositeStream::releaseInputFramesLocked(int64_t currentTs) {
+    auto it = mPendingInputFrames.begin();
+    while (it != mPendingInputFrames.end()) {
+        if (it->first <= currentTs) {
+            releaseInputFrameLocked(&it->second);
+            it = mPendingInputFrames.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
+bool DepthCompositeStream::threadLoop() {
+    int64_t currentTs = INT64_MAX;
+    bool newInputAvailable = false;
+
+    {
+        Mutex::Autolock l(mMutex);
+
+        if (mErrorState) {
+            // In case we landed in error state, return any pending buffers and
+            // halt all further processing.
+            compilePendingInputLocked();
+            releaseInputFramesLocked(currentTs);
+            return false;
+        }
+
+        while (!newInputAvailable) {
+            compilePendingInputLocked();
+            newInputAvailable = getNextReadyInputLocked(&currentTs);
+            if (!newInputAvailable) {
+                auto failingFrameNumber = getNextFailingInputLocked(&currentTs);
+                if (failingFrameNumber >= 0) {
+                    // We cannot erase 'mPendingInputFrames[currentTs]' at this point because it is
+                    // possible for two internal stream buffers to fail. In such scenario the
+                    // composite stream should notify the client about a stream buffer error only
+                    // once and this information is kept within 'errorNotified'.
+                    // Any present failed input frames will be removed on a subsequent call to
+                    // 'releaseInputFramesLocked()'.
+                    releaseInputFrameLocked(&mPendingInputFrames[currentTs]);
+                    currentTs = INT64_MAX;
+                }
+
+                auto ret = mInputReadyCondition.waitRelative(mMutex, kWaitDuration);
+                if (ret == TIMED_OUT) {
+                    return true;
+                } else if (ret != OK) {
+                    ALOGE("%s: Timed wait on condition failed: %s (%d)", __FUNCTION__,
+                            strerror(-ret), ret);
+                    return false;
+                }
+            }
+        }
+    }
+
+    auto res = processInputFrame(mPendingInputFrames[currentTs]);
+    Mutex::Autolock l(mMutex);
+    if (res != OK) {
+        ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ": %s (%d)", __FUNCTION__,
+                currentTs, strerror(-res), res);
+        mPendingInputFrames[currentTs].error = true;
+    }
+
+    releaseInputFramesLocked(currentTs);
+
+    return true;
+}
+
+bool DepthCompositeStream::isDepthCompositeStream(const sp<Surface> &surface) {
+    ANativeWindow *anw = surface.get();
+    status_t err;
+    int format;
+    if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
+        String8 msg = String8::format("Failed to query Surface format: %s (%d)", strerror(-err),
+                err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return false;
+    }
+
+    int dataspace;
+    if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE, &dataspace)) != OK) {
+        String8 msg = String8::format("Failed to query Surface dataspace: %s (%d)", strerror(-err),
+                err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return false;
+    }
+
+    if ((format == HAL_PIXEL_FORMAT_BLOB) && (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH)) {
+        return true;
+    }
+
+    return false;
+}
+
+status_t DepthCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
+        bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
+        camera3_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+        std::vector<int> *surfaceIds, int /*streamSetId*/, bool /*isShared*/) {
+    if (mSupportedDepthSizes.empty()) {
+        ALOGE("%s: This camera device doesn't support any depth map streams!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    size_t depthWidth, depthHeight;
+    auto ret = getMatchingDepthSize(width, height, mSupportedDepthSizes, &depthWidth, &depthHeight);
+    if (ret != OK) {
+        ALOGE("%s: Failed to find an appropriate depth stream size!", __FUNCTION__);
+        return ret;
+    }
+
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (!device.get()) {
+        ALOGE("%s: Invalid camera device!", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mBlobConsumer = new CpuConsumer(consumer, /*maxLockedBuffers*/1, /*controlledByApp*/ true);
+    mBlobConsumer->setFrameAvailableListener(this);
+    mBlobConsumer->setName(String8("Camera3-JpegCompositeStream"));
+    mBlobSurface = new Surface(producer);
+
+    ret = device->createStream(mBlobSurface, width, height, format, kJpegDataSpace, rotation,
+            id, physicalCameraId, surfaceIds);
+    if (ret == OK) {
+        mBlobStreamId = *id;
+        mBlobSurfaceId = (*surfaceIds)[0];
+        mOutputSurface = consumers[0];
+    } else {
+        return ret;
+    }
+
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mDepthConsumer = new CpuConsumer(consumer, /*maxLockedBuffers*/ 1, /*controlledByApp*/ true);
+    mDepthConsumer->setFrameAvailableListener(this);
+    mDepthConsumer->setName(String8("Camera3-DepthCompositeStream"));
+    mDepthSurface = new Surface(producer);
+    std::vector<int> depthSurfaceId;
+    ret = device->createStream(mDepthSurface, depthWidth, depthHeight, kDepthMapPixelFormat,
+            kDepthMapDataSpace, rotation, &mDepthStreamId, physicalCameraId, &depthSurfaceId);
+    if (ret == OK) {
+        mDepthSurfaceId = depthSurfaceId[0];
+    } else {
+        return ret;
+    }
+
+    ret = registerCompositeStreamListener(getStreamId());
+    if (ret != OK) {
+        ALOGE("%s: Failed to register blob stream listener!", __FUNCTION__);
+        return ret;
+    }
+
+    ret = registerCompositeStreamListener(mDepthStreamId);
+    if (ret != OK) {
+        ALOGE("%s: Failed to register depth stream listener!", __FUNCTION__);
+        return ret;
+    }
+
+    mBlobWidth = width;
+    mBlobHeight = height;
+
+    return ret;
+}
+
+status_t DepthCompositeStream::configureStream() {
+    if (isRunning()) {
+        // Processing thread is already running, nothing more to do.
+        return NO_ERROR;
+    }
+
+    if ((mDepthPhotoLibHandle == nullptr) || (mDepthPhotoProcess == nullptr)) {
+        ALOGE("%s: Depth photo library is not present!", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    if (mOutputSurface.get() == nullptr) {
+        ALOGE("%s: No valid output surface set!", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    auto res = mOutputSurface->connect(NATIVE_WINDOW_API_CAMERA, mProducerListener);
+    if (res != OK) {
+        ALOGE("%s: Unable to connect to native window for stream %d",
+                __FUNCTION__, mBlobStreamId);
+        return res;
+    }
+
+    if ((res = native_window_set_buffers_format(mOutputSurface.get(), HAL_PIXEL_FORMAT_BLOB))
+            != OK) {
+        ALOGE("%s: Unable to configure stream buffer format for stream %d", __FUNCTION__,
+                mBlobStreamId);
+        return res;
+    }
+
+    int maxProducerBuffers;
+    ANativeWindow *anw = mBlobSurface.get();
+    if ((res = anw->query(anw, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxProducerBuffers)) != OK) {
+        ALOGE("%s: Unable to query consumer undequeued"
+                " buffer count for stream %d", __FUNCTION__, mBlobStreamId);
+        return res;
+    }
+
+    ANativeWindow *anwConsumer = mOutputSurface.get();
+    int maxConsumerBuffers;
+    if ((res = anwConsumer->query(anwConsumer, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                    &maxConsumerBuffers)) != OK) {
+        ALOGE("%s: Unable to query consumer undequeued"
+                " buffer count for stream %d", __FUNCTION__, mBlobStreamId);
+        return res;
+    }
+
+    if ((res = native_window_set_buffer_count(
+                    anwConsumer, maxProducerBuffers + maxConsumerBuffers)) != OK) {
+        ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mBlobStreamId);
+        return res;
+    }
+
+    run("DepthCompositeStreamProc");
+
+    return NO_ERROR;
+}
+
+status_t DepthCompositeStream::deleteInternalStreams() {
+    // The 'CameraDeviceClient' parent will delete the blob stream
+    requestExit();
+
+    auto ret = join();
+    if (ret != OK) {
+        ALOGE("%s: Failed to join with the main processing thread: %s (%d)", __FUNCTION__,
+                strerror(-ret), ret);
+    }
+
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (!device.get()) {
+        ALOGE("%s: Invalid camera device!", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    if (mDepthStreamId >= 0) {
+        ret = device->deleteStream(mDepthStreamId);
+        mDepthStreamId = -1;
+    }
+
+    return ret;
+}
+
+void DepthCompositeStream::onFrameAvailable(const BufferItem& item) {
+    if (item.mDataSpace == kJpegDataSpace) {
+        ALOGV("%s: Jpeg buffer with ts: %" PRIu64 " ms. arrived!",
+                __func__, ns2ms(item.mTimestamp));
+
+        Mutex::Autolock l(mMutex);
+        if (!mErrorState) {
+            mInputJpegBuffers.push_back(item.mTimestamp);
+            mInputReadyCondition.signal();
+        }
+    } else if (item.mDataSpace == kDepthMapDataSpace) {
+        ALOGV("%s: Depth buffer with ts: %" PRIu64 " ms. arrived!", __func__,
+                ns2ms(item.mTimestamp));
+
+        Mutex::Autolock l(mMutex);
+        if (!mErrorState) {
+            mInputDepthBuffers.push_back(item.mTimestamp);
+            mInputReadyCondition.signal();
+        }
+    } else {
+        ALOGE("%s: Unexpected data space: 0x%x", __FUNCTION__, item.mDataSpace);
+    }
+}
+
+status_t DepthCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
+        Vector<int32_t> * /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) {
+    if (outSurfaceMap->find(mDepthStreamId) == outSurfaceMap->end()) {
+        (*outSurfaceMap)[mDepthStreamId] = std::vector<size_t>();
+        outputStreamIds->push_back(mDepthStreamId);
+    }
+    (*outSurfaceMap)[mDepthStreamId].push_back(mDepthSurfaceId);
+
+    if (outSurfaceMap->find(mBlobStreamId) == outSurfaceMap->end()) {
+        (*outSurfaceMap)[mBlobStreamId] = std::vector<size_t>();
+        outputStreamIds->push_back(mBlobStreamId);
+    }
+    (*outSurfaceMap)[mBlobStreamId].push_back(mBlobSurfaceId);
+
+    if (currentStreamId != nullptr) {
+        *currentStreamId = mBlobStreamId;
+    }
+
+    return NO_ERROR;
+}
+
+void DepthCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
+    // Processing can continue even in case of result errors.
+    // At the moment depth composite stream processing relies mainly on static camera
+    // characteristics data. The actual result data can be used for the jpeg quality but
+    // in case it is absent we can default to maximum.
+    eraseResult(resultExtras.frameNumber);
+}
+
+bool DepthCompositeStream::onStreamBufferError(const CaptureResultExtras& resultExtras) {
+    bool ret = false;
+    // Buffer errors concerning internal composite streams should not be directly visible to
+    // camera clients. They must only receive a single buffer error with the public composite
+    // stream id.
+    if ((resultExtras.errorStreamId == mDepthStreamId) ||
+            (resultExtras.errorStreamId == mBlobStreamId)) {
+        flagAnErrorFrameNumber(resultExtras.frameNumber);
+        ret = true;
+    }
+
+    return ret;
+}
+
+status_t DepthCompositeStream::getMatchingDepthSize(size_t width, size_t height,
+        const std::vector<std::tuple<size_t, size_t>>& supporedDepthSizes,
+        size_t *depthWidth /*out*/, size_t *depthHeight /*out*/) {
+    if ((depthWidth == nullptr) || (depthHeight == nullptr)) {
+        return BAD_VALUE;
+    }
+
+    float arTol = CameraProviderManager::kDepthARTolerance;
+    *depthWidth = *depthHeight = 0;
+
+    float aspectRatio = static_cast<float> (width) / static_cast<float> (height);
+    for (const auto& it : supporedDepthSizes) {
+        auto currentWidth = std::get<0>(it);
+        auto currentHeight = std::get<1>(it);
+        if ((currentWidth == width) && (currentHeight == height)) {
+            *depthWidth = width;
+            *depthHeight = height;
+            break;
+        } else {
+            float currentRatio = static_cast<float> (currentWidth) /
+                    static_cast<float> (currentHeight);
+            auto currentSize = currentWidth * currentHeight;
+            auto oldSize = (*depthWidth) * (*depthHeight);
+            if ((fabs(aspectRatio - currentRatio) <= arTol) && (currentSize > oldSize)) {
+                *depthWidth = currentWidth;
+                *depthHeight = currentHeight;
+            }
+        }
+    }
+
+    return ((*depthWidth > 0) && (*depthHeight > 0)) ? OK : BAD_VALUE;
+}
+
+void DepthCompositeStream::getSupportedDepthSizes(const CameraMetadata& ch,
+        std::vector<std::tuple<size_t, size_t>>* depthSizes /*out*/) {
+    if (depthSizes == nullptr) {
+        return;
+    }
+
+    auto entry = ch.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+    if (entry.count > 0) {
+        // Depth stream dimensions have four int32_t components
+        // (pixelformat, width, height, type)
+        size_t entryCount = entry.count / 4;
+        depthSizes->reserve(entryCount);
+        for (size_t i = 0; i < entry.count; i += 4) {
+            if ((entry.data.i32[i] == kDepthMapPixelFormat) &&
+                    (entry.data.i32[i+3] ==
+                     ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) {
+                depthSizes->push_back(std::make_tuple(entry.data.i32[i+1],
+                            entry.data.i32[i+2]));
+            }
+        }
+    }
+}
+
+status_t DepthCompositeStream::getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
+            const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/) {
+    if (compositeOutput == nullptr) {
+        return BAD_VALUE;
+    }
+
+    std::vector<std::tuple<size_t, size_t>> depthSizes;
+    getSupportedDepthSizes(ch, &depthSizes);
+    if (depthSizes.empty()) {
+        ALOGE("%s: No depth stream configurations present", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    size_t depthWidth, depthHeight;
+    auto ret = getMatchingDepthSize(streamInfo.width, streamInfo.height, depthSizes, &depthWidth,
+            &depthHeight);
+    if (ret != OK) {
+        ALOGE("%s: No matching depth stream size found", __FUNCTION__);
+        return ret;
+    }
+
+    compositeOutput->clear();
+    compositeOutput->insert(compositeOutput->end(), 2, streamInfo);
+
+    // Jpeg/Blob stream info
+    (*compositeOutput)[0].dataSpace = kJpegDataSpace;
+    (*compositeOutput)[0].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+
+    // Depth stream info
+    (*compositeOutput)[1].width = depthWidth;
+    (*compositeOutput)[1].height = depthHeight;
+    (*compositeOutput)[1].format = kDepthMapPixelFormat;
+    (*compositeOutput)[1].dataSpace = kDepthMapDataSpace;
+    (*compositeOutput)[1].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+
+    return NO_ERROR;
+}
+
+}; // namespace camera3
+}; // namespace android
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
new file mode 100644
index 0000000..e8fe517
--- /dev/null
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -0,0 +1,151 @@
+/*
+ * 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 ANDROID_SERVERS_CAMERA_CAMERA3_DEPTH_COMPOSITE_STREAM_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3_DEPTH_COMPOSITE_STREAM_H
+
+#include "common/DepthPhotoProcessor.h"
+#include <dynamic_depth/imaging_model.h>
+#include <dynamic_depth/depth_map.h>
+
+#include <gui/IProducerListener.h>
+#include <gui/CpuConsumer.h>
+
+#include "CompositeStream.h"
+
+using dynamic_depth::DepthMap;
+using dynamic_depth::Item;
+using dynamic_depth::ImagingModel;
+
+namespace android {
+
+class CameraDeviceClient;
+class CameraMetadata;
+class Surface;
+
+namespace camera3 {
+
+class DepthCompositeStream : public CompositeStream, public Thread,
+        public CpuConsumer::FrameAvailableListener {
+
+public:
+    DepthCompositeStream(wp<CameraDeviceBase> device,
+            wp<hardware::camera2::ICameraDeviceCallbacks> cb);
+    ~DepthCompositeStream() override;
+
+    static bool isDepthCompositeStream(const sp<Surface> &surface);
+
+    // CompositeStream overrides
+    status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+            bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
+            camera3_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+            std::vector<int> *surfaceIds, int streamSetId, bool isShared) override;
+    status_t deleteInternalStreams() override;
+    status_t configureStream() override;
+    status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
+            int32_t* /*out*/currentStreamId) override;
+    int getStreamId() override { return mBlobStreamId; }
+
+    // CpuConsumer listener implementation
+    void onFrameAvailable(const BufferItem& item) override;
+
+    // Return stream information about the internal camera streams
+    static status_t getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
+            const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/);
+
+protected:
+
+    bool threadLoop() override;
+    bool onStreamBufferError(const CaptureResultExtras& resultExtras) override;
+    void onResultError(const CaptureResultExtras& resultExtras) override;
+
+private:
+    struct InputFrame {
+        CpuConsumer::LockedBuffer depthBuffer;
+        CpuConsumer::LockedBuffer jpegBuffer;
+        CameraMetadata            result;
+        bool                      error;
+        bool                      errorNotified;
+        int64_t                   frameNumber;
+
+        InputFrame() : error(false), errorNotified(false), frameNumber(-1) { }
+    };
+
+    // Helper methods
+    static void getSupportedDepthSizes(const CameraMetadata& ch,
+            std::vector<std::tuple<size_t, size_t>>* depthSizes /*out*/);
+    static status_t getMatchingDepthSize(size_t width, size_t height,
+            const std::vector<std::tuple<size_t, size_t>>& supporedDepthSizes,
+            size_t *depthWidth /*out*/, size_t *depthHeight /*out*/);
+
+    // Dynamic depth processing
+    status_t encodeGrayscaleJpeg(size_t width, size_t height, uint8_t *in, void *out,
+            const size_t maxOutSize, uint8_t jpegQuality, size_t &actualSize);
+    std::unique_ptr<DepthMap> processDepthMapFrame(const CpuConsumer::LockedBuffer &depthMapBuffer,
+            size_t maxJpegSize, uint8_t jpegQuality,
+            std::vector<std::unique_ptr<Item>>* items /*out*/);
+    std::unique_ptr<ImagingModel> getImagingModel();
+    status_t processInputFrame(const InputFrame &inputFrame);
+
+    // Buffer/Results handling
+    void compilePendingInputLocked();
+    void releaseInputFrameLocked(InputFrame *inputFrame /*out*/);
+    void releaseInputFramesLocked(int64_t currentTs);
+
+    // Find first complete and valid frame with smallest timestamp
+    bool getNextReadyInputLocked(int64_t *currentTs /*inout*/);
+
+    // Find next failing frame number with smallest timestamp and return respective frame number
+    int64_t getNextFailingInputLocked(int64_t *currentTs /*inout*/);
+
+    static const nsecs_t kWaitDuration = 10000000; // 10 ms
+    static const auto kDepthMapPixelFormat = HAL_PIXEL_FORMAT_Y16;
+    static const auto kDepthMapDataSpace = HAL_DATASPACE_DEPTH;
+    static const auto kJpegDataSpace = HAL_DATASPACE_V0_JFIF;
+
+    struct ProducerListener : public BnProducerListener {
+        // ProducerListener implementation
+        void onBufferReleased() override { /*No impl. for now*/ };
+    };
+
+    int                  mBlobStreamId, mBlobSurfaceId, mDepthStreamId, mDepthSurfaceId;
+    size_t               mBlobWidth, mBlobHeight;
+    sp<CpuConsumer>      mBlobConsumer, mDepthConsumer;
+    bool                 mDepthBufferAcquired, mBlobBufferAcquired;
+    sp<Surface>          mDepthSurface, mBlobSurface, mOutputSurface;
+    sp<ProducerListener> mProducerListener;
+
+    ssize_t              mMaxJpegSize;
+    std::vector<std::tuple<size_t, size_t>> mSupportedDepthSizes;
+    std::vector<float>   mInstrinsicCalibration, mLensDistortion;
+    bool                 mIsLogicalCamera;
+    void*                mDepthPhotoLibHandle;
+    process_depth_photo_frame mDepthPhotoProcess;
+
+    // Keep all incoming Depth buffer timestamps pending further processing.
+    std::vector<int64_t> mInputDepthBuffers;
+
+    // Keep all incoming Jpeg/Blob buffer timestamps pending further processing.
+    std::vector<int64_t> mInputJpegBuffers;
+
+    // Map of all input frames pending further processing.
+    std::unordered_map<int64_t, InputFrame> mPendingInputFrames;
+};
+
+}; //namespace camera3
+}; //namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index a9cbe72..3059b07 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -24,6 +24,8 @@
 
 #include <algorithm>
 #include <chrono>
+#include "common/DepthPhotoProcessor.h"
+#include <dlfcn.h>
 #include <future>
 #include <inttypes.h>
 #include <hardware/camera_common.h>
@@ -58,6 +60,8 @@
 
 } // anonymous namespace
 
+const float CameraProviderManager::kDepthARTolerance = .1f;
+
 CameraProviderManager::HardwareServiceInteractionProxy
 CameraProviderManager::sHardwareServiceInteractionProxy{};
 
@@ -500,6 +504,275 @@
     }
 }
 
+void CameraProviderManager::ProviderInfo::DeviceInfo3::getSupportedSizes(
+        const CameraMetadata& ch, uint32_t tag, android_pixel_format_t format,
+        std::vector<std::tuple<size_t, size_t>> *sizes/*out*/) {
+    if (sizes == nullptr) {
+        return;
+    }
+
+    auto scalerDims = ch.find(tag);
+    if (scalerDims.count > 0) {
+        // Scaler entry contains 4 elements (format, width, height, type)
+        for (size_t i = 0; i < scalerDims.count; i += 4) {
+            if ((scalerDims.data.i32[i] == format) &&
+                    (scalerDims.data.i32[i+3] ==
+                     ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) {
+                sizes->push_back(std::make_tuple(scalerDims.data.i32[i+1],
+                            scalerDims.data.i32[i+2]));
+            }
+        }
+    }
+}
+
+void CameraProviderManager::ProviderInfo::DeviceInfo3::getSupportedDurations(
+        const CameraMetadata& ch, uint32_t tag, android_pixel_format_t format,
+        const std::vector<std::tuple<size_t, size_t>>& sizes,
+        std::vector<int64_t> *durations/*out*/) {
+    if (durations == nullptr) {
+        return;
+    }
+
+    auto availableDurations = ch.find(tag);
+    if (availableDurations.count > 0) {
+        // Duration entry contains 4 elements (format, width, height, duration)
+        for (size_t i = 0; i < availableDurations.count; i += 4) {
+            for (const auto& size : sizes) {
+                int64_t width = std::get<0>(size);
+                int64_t height = std::get<1>(size);
+                if ((availableDurations.data.i64[i] == format) &&
+                        (availableDurations.data.i64[i+1] == width) &&
+                        (availableDurations.data.i64[i+2] == height)) {
+                    durations->push_back(availableDurations.data.i64[i+3]);
+                }
+            }
+        }
+    }
+}
+void CameraProviderManager::ProviderInfo::DeviceInfo3::getSupportedDynamicDepthDurations(
+        const std::vector<int64_t>& depthDurations, const std::vector<int64_t>& blobDurations,
+        std::vector<int64_t> *dynamicDepthDurations /*out*/) {
+    if ((dynamicDepthDurations == nullptr) || (depthDurations.size() != blobDurations.size())) {
+        return;
+    }
+
+    // Unfortunately there is no direct way to calculate the dynamic depth stream duration.
+    // Processing time on camera service side can vary greatly depending on multiple
+    // variables which are not under our control. Make a guesstimate by taking the maximum
+    // corresponding duration value from depth and blob.
+    auto depthDuration = depthDurations.begin();
+    auto blobDuration = blobDurations.begin();
+    dynamicDepthDurations->reserve(depthDurations.size());
+    while ((depthDuration != depthDurations.end()) && (blobDuration != blobDurations.end())) {
+        dynamicDepthDurations->push_back(std::max(*depthDuration, *blobDuration));
+        depthDuration++; blobDuration++;
+    }
+}
+
+void CameraProviderManager::ProviderInfo::DeviceInfo3::getSupportedDynamicDepthSizes(
+        const std::vector<std::tuple<size_t, size_t>>& blobSizes,
+        const std::vector<std::tuple<size_t, size_t>>& depthSizes,
+        std::vector<std::tuple<size_t, size_t>> *dynamicDepthSizes /*out*/,
+        std::vector<std::tuple<size_t, size_t>> *internalDepthSizes /*out*/) {
+    if (dynamicDepthSizes == nullptr || internalDepthSizes == nullptr) {
+        return;
+    }
+
+    // The dynamic depth spec. does not mention how close the AR ratio should be.
+    // Try using something appropriate.
+    float ARTolerance = kDepthARTolerance;
+
+    for (const auto& blobSize : blobSizes) {
+        float jpegAR = static_cast<float> (std::get<0>(blobSize)) /
+                static_cast<float>(std::get<1>(blobSize));
+        bool found = false;
+        for (const auto& depthSize : depthSizes) {
+            if (depthSize == blobSize) {
+                internalDepthSizes->push_back(depthSize);
+                found = true;
+                break;
+            } else {
+                float depthAR = static_cast<float> (std::get<0>(depthSize)) /
+                    static_cast<float>(std::get<1>(depthSize));
+                if (std::fabs(jpegAR - depthAR) <= ARTolerance) {
+                    internalDepthSizes->push_back(depthSize);
+                    found = true;
+                    break;
+                }
+            }
+        }
+
+        if (found) {
+            dynamicDepthSizes->push_back(blobSize);
+        }
+    }
+}
+
+bool CameraProviderManager::ProviderInfo::DeviceInfo3::isDepthPhotoLibraryPresent() {
+    static bool libraryPresent = false;
+    static bool initialized = false;
+    if (initialized) {
+        return libraryPresent;
+    } else {
+        initialized = true;
+    }
+
+    void* depthLibHandle = dlopen(camera3::kDepthPhotoLibrary, RTLD_NOW | RTLD_LOCAL);
+    if (depthLibHandle == nullptr) {
+        return false;
+    }
+
+    auto processFunc = dlsym(depthLibHandle, camera3::kDepthPhotoProcessFunction);
+    if (processFunc != nullptr) {
+        libraryPresent = true;
+    } else {
+        libraryPresent = false;
+    }
+    dlclose(depthLibHandle);
+
+    return libraryPresent;
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addDynamicDepthTags() {
+    uint32_t depthExclTag = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE;
+    uint32_t depthSizesTag = ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS;
+    auto& c = mCameraCharacteristics;
+    std::vector<std::tuple<size_t, size_t>> supportedBlobSizes, supportedDepthSizes,
+            supportedDynamicDepthSizes, internalDepthSizes;
+    auto chTags = c.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+    if (chTags.count == 0) {
+        ALOGE("%s: Supported camera characteristics is empty!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    bool isDepthExclusivePresent = std::find(chTags.data.i32, chTags.data.i32 + chTags.count,
+            depthExclTag) != (chTags.data.i32 + chTags.count);
+    bool isDepthSizePresent = std::find(chTags.data.i32, chTags.data.i32 + chTags.count,
+            depthExclTag) != (chTags.data.i32 + chTags.count);
+    if (!(isDepthExclusivePresent && isDepthSizePresent)) {
+        // No depth support, nothing more to do.
+        return OK;
+    }
+
+    auto depthExclusiveEntry = c.find(depthExclTag);
+    if (depthExclusiveEntry.count > 0) {
+        if (depthExclusiveEntry.data.u8[0] != ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE) {
+            // Depth support is exclusive, nothing more to do.
+            return OK;
+        }
+    } else {
+        ALOGE("%s: Advertised depth exclusive tag but value is not present!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    getSupportedSizes(c, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, HAL_PIXEL_FORMAT_BLOB,
+            &supportedBlobSizes);
+    getSupportedSizes(c, depthSizesTag, HAL_PIXEL_FORMAT_Y16, &supportedDepthSizes);
+    if (supportedBlobSizes.empty() || supportedDepthSizes.empty()) {
+        // Nothing to do in this case.
+        return OK;
+    }
+
+    getSupportedDynamicDepthSizes(supportedBlobSizes, supportedDepthSizes,
+            &supportedDynamicDepthSizes, &internalDepthSizes);
+    if (supportedDynamicDepthSizes.empty()) {
+        ALOGE("%s: No dynamic depth size matched!", __func__);
+        // Nothing more to do.
+        return OK;
+    }
+
+    if(!isDepthPhotoLibraryPresent()) {
+        // Depth photo processing library is not present, nothing more to do.
+        return OK;
+    }
+
+    std::vector<int32_t> dynamicDepthEntries;
+    for (const auto& it : supportedDynamicDepthSizes) {
+        int32_t entry[4] = {HAL_PIXEL_FORMAT_BLOB, static_cast<int32_t> (std::get<0>(it)),
+                static_cast<int32_t> (std::get<1>(it)),
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT };
+        dynamicDepthEntries.insert(dynamicDepthEntries.end(), entry, entry + 4);
+    }
+
+    std::vector<int64_t> depthMinDurations, depthStallDurations;
+    std::vector<int64_t> blobMinDurations, blobStallDurations;
+    std::vector<int64_t> dynamicDepthMinDurations, dynamicDepthStallDurations;
+
+    getSupportedDurations(c, ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
+            HAL_PIXEL_FORMAT_Y16, internalDepthSizes, &depthMinDurations);
+    getSupportedDurations(c, ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+            HAL_PIXEL_FORMAT_BLOB, supportedDynamicDepthSizes, &blobMinDurations);
+    if (blobMinDurations.empty() || depthMinDurations.empty() ||
+            (depthMinDurations.size() != blobMinDurations.size())) {
+        ALOGE("%s: Unexpected number of available depth min durations! %zu vs. %zu",
+                __FUNCTION__, depthMinDurations.size(), blobMinDurations.size());
+        return BAD_VALUE;
+    }
+
+    getSupportedDurations(c, ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS,
+            HAL_PIXEL_FORMAT_Y16, internalDepthSizes, &depthStallDurations);
+    getSupportedDurations(c, ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+            HAL_PIXEL_FORMAT_BLOB, supportedDynamicDepthSizes, &blobStallDurations);
+    if (blobStallDurations.empty() || depthStallDurations.empty() ||
+            (depthStallDurations.size() != blobStallDurations.size())) {
+        ALOGE("%s: Unexpected number of available depth stall durations! %zu vs. %zu",
+                __FUNCTION__, depthStallDurations.size(), blobStallDurations.size());
+        return BAD_VALUE;
+    }
+
+    getSupportedDynamicDepthDurations(depthMinDurations, blobMinDurations,
+            &dynamicDepthMinDurations);
+    getSupportedDynamicDepthDurations(depthStallDurations, blobStallDurations,
+            &dynamicDepthStallDurations);
+    if (dynamicDepthMinDurations.empty() || dynamicDepthStallDurations.empty() ||
+            (dynamicDepthMinDurations.size() != dynamicDepthStallDurations.size())) {
+        ALOGE("%s: Unexpected number of dynamic depth stall/min durations! %zu vs. %zu",
+                __FUNCTION__, dynamicDepthMinDurations.size(), dynamicDepthStallDurations.size());
+        return BAD_VALUE;
+    }
+
+    std::vector<int64_t> dynamicDepthMinDurationEntries;
+    auto itDuration = dynamicDepthMinDurations.begin();
+    auto itSize = supportedDynamicDepthSizes.begin();
+    while (itDuration != dynamicDepthMinDurations.end()) {
+        int64_t entry[4] = {HAL_PIXEL_FORMAT_BLOB, static_cast<int32_t> (std::get<0>(*itSize)),
+                static_cast<int32_t> (std::get<1>(*itSize)), *itDuration};
+        dynamicDepthMinDurationEntries.insert(dynamicDepthMinDurationEntries.end(), entry,
+                entry + 4);
+        itDuration++; itSize++;
+    }
+
+    std::vector<int64_t> dynamicDepthStallDurationEntries;
+    itDuration = dynamicDepthStallDurations.begin();
+    itSize = supportedDynamicDepthSizes.begin();
+    while (itDuration != dynamicDepthStallDurations.end()) {
+        int64_t entry[4] = {HAL_PIXEL_FORMAT_BLOB, static_cast<int32_t> (std::get<0>(*itSize)),
+                static_cast<int32_t> (std::get<1>(*itSize)), *itDuration};
+        dynamicDepthStallDurationEntries.insert(dynamicDepthStallDurationEntries.end(), entry,
+                entry + 4);
+        itDuration++; itSize++;
+    }
+
+    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
+            dynamicDepthEntries.data(), dynamicDepthEntries.size());
+    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS,
+            dynamicDepthMinDurationEntries.data(), dynamicDepthMinDurationEntries.size());
+    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS,
+            dynamicDepthStallDurationEntries.data(), dynamicDepthStallDurationEntries.size());
+
+    std::vector<int32_t> supportedChTags;
+    supportedChTags.reserve(chTags.count + 3);
+    supportedChTags.insert(supportedChTags.end(), chTags.data.i32,
+            chTags.data.i32 + chTags.count);
+    supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+    supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
+    supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
+    c.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, supportedChTags.data(),
+            supportedChTags.size());
+
+    return OK;
+}
+
 status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
     status_t res = OK;
     auto& c = mCameraCharacteristics;
@@ -1442,6 +1715,12 @@
                 __FUNCTION__, strerror(-res), res);
         return;
     }
+    res = addDynamicDepthTags();
+    if (OK != res) {
+        ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-res),
+                res);
+        return;
+    }
     camera_metadata_entry flashAvailable =
             mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
     if (flashAvailable.count == 1 &&
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 0966743..fbd7d2e 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -265,6 +265,8 @@
     bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
 
     bool isHiddenPhysicalCamera(const std::string& cameraId);
+
+    static const float kDepthARTolerance;
 private:
     // All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
     mutable std::mutex mInterfaceMutex;
@@ -470,6 +472,23 @@
             std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
             void queryPhysicalCameraIds();
             status_t fixupMonochromeTags();
+            status_t addDynamicDepthTags();
+            static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag,
+                    android_pixel_format_t format,
+                    std::vector<std::tuple<size_t, size_t>> *sizes /*out*/);
+            void getSupportedDurations( const CameraMetadata& ch, uint32_t tag,
+                    android_pixel_format_t format,
+                    const std::vector<std::tuple<size_t, size_t>>& sizes,
+                    std::vector<int64_t> *durations/*out*/);
+            void getSupportedDynamicDepthDurations(const std::vector<int64_t>& depthDurations,
+                    const std::vector<int64_t>& blobDurations,
+                    std::vector<int64_t> *dynamicDepthDurations /*out*/);
+            static bool isDepthPhotoLibraryPresent();
+            static void getSupportedDynamicDepthSizes(
+                    const std::vector<std::tuple<size_t, size_t>>& blobSizes,
+                    const std::vector<std::tuple<size_t, size_t>>& depthSizes,
+                    std::vector<std::tuple<size_t, size_t>> *dynamicDepthSizes /*out*/,
+                    std::vector<std::tuple<size_t, size_t>> *internalDepthSizes /*out*/);
             status_t removeAvailableKeys(CameraMetadata& c, const std::vector<uint32_t>& keys,
                     uint32_t keyTag);
         };
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
new file mode 100644
index 0000000..a945aca
--- /dev/null
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2019 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_TAG "Camera3-DepthPhotoProcessor"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//
+
+#include "DepthPhotoProcessor.h"
+
+#include <dynamic_depth/camera.h>
+#include <dynamic_depth/cameras.h>
+#include <dynamic_depth/container.h>
+#include <dynamic_depth/device.h>
+#include <dynamic_depth/dimension.h>
+#include <dynamic_depth/dynamic_depth.h>
+#include <dynamic_depth/point.h>
+#include <dynamic_depth/pose.h>
+#include <dynamic_depth/profile.h>
+#include <dynamic_depth/profiles.h>
+#include <jpeglib.h>
+#include <math.h>
+#include <sstream>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <xmpmeta/xmp_data.h>
+#include <xmpmeta/xmp_writer.h>
+
+using dynamic_depth::Camera;
+using dynamic_depth::Cameras;
+using dynamic_depth::CameraParams;
+using dynamic_depth::Container;
+using dynamic_depth::DepthFormat;
+using dynamic_depth::DepthMap;
+using dynamic_depth::DepthMapParams;
+using dynamic_depth::DepthUnits;
+using dynamic_depth::Device;
+using dynamic_depth::DeviceParams;
+using dynamic_depth::Dimension;
+using dynamic_depth::Image;
+using dynamic_depth::ImagingModel;
+using dynamic_depth::ImagingModelParams;
+using dynamic_depth::Item;
+using dynamic_depth::Pose;
+using dynamic_depth::Profile;
+using dynamic_depth::Profiles;
+
+namespace android {
+namespace camera3 {
+
+status_t encodeGrayscaleJpeg(size_t width, size_t height, uint8_t *in, void *out,
+        const size_t maxOutSize, uint8_t jpegQuality, size_t &actualSize) {
+    status_t ret;
+    // libjpeg is a C library so we use C-style "inheritance" by
+    // putting libjpeg's jpeg_destination_mgr first in our custom
+    // struct. This allows us to cast jpeg_destination_mgr* to
+    // CustomJpegDestMgr* when we get it passed to us in a callback.
+    struct CustomJpegDestMgr : public jpeg_destination_mgr {
+        JOCTET *mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    // Initialize error handling with standard callbacks, but
+    // then override output_message (to print to ALOG) and
+    // error_exit to set a flag and print a message instead
+    // of killing the whole process.
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if(cinfo->client_data) {
+            auto & dmgr = *static_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+
+    // Now that we initialized some callbacks, let's create our compressor
+    jpeg_create_compress(&cinfo);
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    // These lambdas become C-style function pointers and as per C++11 spec
+    // may not capture anything.
+    dmgr.init_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = static_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.next_output_byte = dmgr.mBuffer;
+        dmgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]",
+              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.term_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = static_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+    cinfo.image_width = width;
+    cinfo.image_height = height;
+    cinfo.input_components = 1;
+    cinfo.in_color_space = JCS_GRAYSCALE;
+
+    // Initialize defaults and then override what we want
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
+    cinfo.raw_data_in = 0;
+    cinfo.dct_method = JDCT_IFAST;
+
+    cinfo.comp_info[0].h_samp_factor = 1;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[0].v_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+    for (size_t i = 0; i < cinfo.image_height; i++) {
+        auto currentRow  = static_cast<JSAMPROW>(in + i*width);
+        jpeg_write_scanlines(&cinfo, &currentRow, /*num_lines*/1);
+    }
+
+    jpeg_finish_compress(&cinfo);
+
+    actualSize = dmgr.mEncodedSize;
+    if (dmgr.mSuccess) {
+        ret = NO_ERROR;
+    } else {
+        ret = UNKNOWN_ERROR;
+    }
+
+    return ret;
+}
+
+std::unique_ptr<dynamic_depth::DepthMap> processDepthMapFrame(DepthPhotoInputFrame inputFrame,
+                std::vector<std::unique_ptr<Item>> *items /*out*/) {
+    std::vector<float> points, confidence;
+
+    size_t pointCount = inputFrame.mDepthMapWidth * inputFrame.mDepthMapHeight;
+    points.reserve(pointCount);
+    confidence.reserve(pointCount);
+    float near = UINT16_MAX;
+    float far = .0f;
+    for (size_t i = 0; i < inputFrame.mDepthMapHeight; i++) {
+        for (size_t j = 0; j < inputFrame.mDepthMapWidth; j++) {
+            // Android densely packed depth map. The units for the range are in
+            // millimeters and need to be scaled to meters.
+            // The confidence value is encoded in the 3 most significant bits.
+            // The confidence data needs to be additionally normalized with
+            // values 1.0f, 0.0f representing maximum and minimum confidence
+            // respectively.
+            auto value = inputFrame.mDepthMapBuffer[i*inputFrame.mDepthMapStride + j];
+            auto point = static_cast<float>(value & 0x1FFF) / 1000.f;
+            points.push_back(point);
+
+            auto conf = (value >> 13) & 0x7;
+            float normConfidence = (conf == 0) ? 1.f : (static_cast<float>(conf) - 1) / 7.f;
+            confidence.push_back(normConfidence);
+
+            if (near > point) {
+                near = point;
+            }
+            if (far < point) {
+                far = point;
+            }
+        }
+    }
+
+    if (near == far) {
+        ALOGE("%s: Near and far range values must not match!", __FUNCTION__);
+        return nullptr;
+    }
+
+    std::vector<uint8_t> pointsQuantized, confidenceQuantized;
+    pointsQuantized.reserve(pointCount); confidenceQuantized.reserve(pointCount);
+    auto pointIt = points.begin();
+    auto confidenceIt = confidence.begin();
+    while ((pointIt != points.end()) && (confidenceIt != confidence.end())) {
+        pointsQuantized.push_back(floorf(((far * (*pointIt - near)) /
+                (*pointIt * (far - near))) * 255.0f));
+        confidenceQuantized.push_back(floorf(*confidenceIt * 255.0f));
+        confidenceIt++; pointIt++;
+    }
+
+    DepthMapParams depthParams(DepthFormat::kRangeInverse, near, far, DepthUnits::kMeters,
+            "android/depthmap");
+    depthParams.confidence_uri = "android/confidencemap";
+    depthParams.mime = "image/jpeg";
+    depthParams.depth_image_data.resize(inputFrame.mMaxJpegSize);
+    depthParams.confidence_data.resize(inputFrame.mMaxJpegSize);
+    size_t actualJpegSize;
+    auto ret = encodeGrayscaleJpeg(inputFrame.mDepthMapWidth, inputFrame.mDepthMapHeight,
+            pointsQuantized.data(), depthParams.depth_image_data.data(), inputFrame.mMaxJpegSize,
+            inputFrame.mJpegQuality, actualJpegSize);
+    if (ret != NO_ERROR) {
+        ALOGE("%s: Depth map compression failed!", __FUNCTION__);
+        return nullptr;
+    }
+    depthParams.depth_image_data.resize(actualJpegSize);
+
+    ret = encodeGrayscaleJpeg(inputFrame.mDepthMapWidth, inputFrame.mDepthMapHeight,
+            confidenceQuantized.data(), depthParams.confidence_data.data(), inputFrame.mMaxJpegSize,
+            inputFrame.mJpegQuality, actualJpegSize);
+    if (ret != NO_ERROR) {
+        ALOGE("%s: Confidence map compression failed!", __FUNCTION__);
+        return nullptr;
+    }
+    depthParams.confidence_data.resize(actualJpegSize);
+
+    return DepthMap::FromData(depthParams, items);
+}
+
+extern "C" int processDepthPhotoFrame(DepthPhotoInputFrame inputFrame, size_t depthPhotoBufferSize,
+        void* depthPhotoBuffer /*out*/, size_t* depthPhotoActualSize /*out*/) {
+    if ((inputFrame.mMainJpegBuffer == nullptr) || (inputFrame.mDepthMapBuffer == nullptr) ||
+            (depthPhotoBuffer == nullptr) || (depthPhotoActualSize == nullptr)) {
+        return BAD_VALUE;
+    }
+
+    std::vector<std::unique_ptr<Item>> items;
+    std::vector<std::unique_ptr<Camera>> cameraList;
+    auto image = Image::FromDataForPrimaryImage("android/mainimage", &items);
+    std::unique_ptr<CameraParams> cameraParams(new CameraParams(std::move(image)));
+    if (cameraParams == nullptr) {
+        ALOGE("%s: Failed to initialize camera parameters", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    cameraParams->depth_map = processDepthMapFrame(inputFrame, &items);
+    if (cameraParams->depth_map == nullptr) {
+        ALOGE("%s: Depth map processing failed!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // It is not possible to generate an imaging model without instrinsic calibration.
+    if (inputFrame.mIsInstrinsicCalibrationValid) {
+        // The camera intrinsic calibration layout is as follows:
+        // [focalLengthX, focalLengthY, opticalCenterX, opticalCenterY, skew]
+        const dynamic_depth::Point<double> focalLength(inputFrame.mInstrinsicCalibration[0],
+                inputFrame.mInstrinsicCalibration[1]);
+        const Dimension imageSize(inputFrame.mMainJpegWidth, inputFrame.mMainJpegHeight);
+        ImagingModelParams imagingParams(focalLength, imageSize);
+        imagingParams.principal_point.x = inputFrame.mInstrinsicCalibration[2];
+        imagingParams.principal_point.y = inputFrame.mInstrinsicCalibration[3];
+        imagingParams.skew = inputFrame.mInstrinsicCalibration[4];
+
+        // The camera lens distortion contains the following lens correction coefficients.
+        // [kappa_1, kappa_2, kappa_3 kappa_4, kappa_5]
+        if (inputFrame.mIsLensDistortionValid) {
+            // According to specification the lens distortion coefficients should be ordered
+            // as [1, kappa_4, kappa_1, kappa_5, kappa_2, 0, kappa_3, 0]
+            float distortionData[] = {1.f, inputFrame.mLensDistortion[3],
+                    inputFrame.mLensDistortion[0], inputFrame.mLensDistortion[4],
+                    inputFrame.mLensDistortion[1], 0.f, inputFrame.mLensDistortion[2], 0.f};
+            auto distortionDataLength = sizeof(distortionData) / sizeof(distortionData[0]);
+            imagingParams.distortion.reserve(distortionDataLength);
+            imagingParams.distortion.insert(imagingParams.distortion.end(), distortionData,
+                    distortionData + distortionDataLength);
+        }
+
+        cameraParams->imaging_model = ImagingModel::FromData(imagingParams);
+    }
+
+    if (inputFrame.mIsLogical) {
+        cameraParams->trait = dynamic_depth::CameraTrait::LOGICAL;
+    } else {
+        cameraParams->trait = dynamic_depth::CameraTrait::PHYSICAL;
+    }
+
+    cameraList.emplace_back(Camera::FromData(std::move(cameraParams)));
+
+    auto deviceParams = std::make_unique<DeviceParams> (Cameras::FromCameraArray(&cameraList));
+    deviceParams->container = Container::FromItems(&items);
+    std::vector<std::unique_ptr<Profile>> profileList;
+    profileList.emplace_back(Profile::FromData("DepthPhoto", {0}));
+    deviceParams->profiles = Profiles::FromProfileArray(&profileList);
+    std::unique_ptr<Device> device = Device::FromData(std::move(deviceParams));
+    if (device == nullptr) {
+        ALOGE("%s: Failed to initialize camera device", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    std::istringstream inputJpegStream(
+            std::string(inputFrame.mMainJpegBuffer, inputFrame.mMainJpegSize));
+    std::ostringstream outputJpegStream;
+    if (!WriteImageAndMetadataAndContainer(&inputJpegStream, device.get(), &outputJpegStream)) {
+        ALOGE("%s: Failed writing depth output", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    *depthPhotoActualSize = static_cast<size_t> (outputJpegStream.tellp());
+    if (*depthPhotoActualSize > depthPhotoBufferSize) {
+        ALOGE("%s: Depth photo output buffer not sufficient, needed %zu actual %zu", __FUNCTION__,
+                *depthPhotoActualSize, depthPhotoBufferSize);
+        return NO_MEMORY;
+    }
+
+    memcpy(depthPhotoBuffer, outputJpegStream.str().c_str(), *depthPhotoActualSize);
+
+    return 0;
+}
+
+}; // namespace camera3
+}; // namespace android
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.h b/services/camera/libcameraservice/common/DepthPhotoProcessor.h
new file mode 100644
index 0000000..19889a1
--- /dev/null
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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 ANDROID_SERVERS_CAMERA_CAMERA3_DEPTH_PROCESSOR_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3_DEPTH_PROCESSOR_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace android {
+namespace camera3 {
+
+struct DepthPhotoInputFrame {
+    const char* mMainJpegBuffer;
+    size_t      mMainJpegSize;
+    size_t      mMainJpegWidth, mMainJpegHeight;
+    uint16_t*   mDepthMapBuffer;
+    size_t      mDepthMapWidth, mDepthMapHeight, mDepthMapStride;
+    size_t      mMaxJpegSize;
+    uint8_t     mJpegQuality;
+    uint8_t     mIsLogical;
+    float       mInstrinsicCalibration[5];
+    uint8_t     mIsInstrinsicCalibrationValid;
+    float       mLensDistortion[5];
+    uint8_t     mIsLensDistortionValid;
+
+    DepthPhotoInputFrame() :
+            mMainJpegBuffer(nullptr),
+            mMainJpegSize(0),
+            mMainJpegWidth(0),
+            mMainJpegHeight(0),
+            mDepthMapBuffer(nullptr),
+            mDepthMapWidth(0),
+            mDepthMapHeight(0),
+            mDepthMapStride(0),
+            mMaxJpegSize(0),
+            mJpegQuality(100),
+            mIsLogical(0),
+            mInstrinsicCalibration{0.f},
+            mIsInstrinsicCalibrationValid(0),
+            mLensDistortion{0.f},
+            mIsLensDistortionValid(0) {}
+};
+
+static const char *kDepthPhotoLibrary = "libdepthphoto.so";
+static const char *kDepthPhotoProcessFunction = "processDepthPhotoFrame";
+typedef int (*process_depth_photo_frame) (DepthPhotoInputFrame /*inputFrame*/,
+        size_t /*depthPhotoBufferSize*/, void* /*depthPhotoBuffer out*/,
+        size_t* /*depthPhotoActualSize out*/);
+
+}; // namespace camera3
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 12fbf82..99b8043 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -3119,10 +3119,12 @@
         status_t res = OK;
         if (it != outputSurfaces.end()) {
             res = stream->returnBuffer(
-                    outputBuffers[i], timestamp, timestampIncreasing, it->second);
+                    outputBuffers[i], timestamp, timestampIncreasing, it->second,
+                    inResultExtras.frameNumber);
         } else {
             res = stream->returnBuffer(
-                    outputBuffers[i], timestamp, timestampIncreasing);
+                    outputBuffers[i], timestamp, timestampIncreasing, std::vector<size_t> (),
+                    inResultExtras.frameNumber);
         }
 
         // Note: stream may be deallocated at this point, if this buffer was
@@ -3139,7 +3141,8 @@
             // cancel the buffer
             camera3_stream_buffer_t sb = outputBuffers[i];
             sb.status = CAMERA3_BUFFER_STATUS_ERROR;
-            stream->returnBuffer(sb, /*timestamp*/0, timestampIncreasing);
+            stream->returnBuffer(sb, /*timestamp*/0, timestampIncreasing, std::vector<size_t> (),
+                    inResultExtras.frameNumber);
 
             // notify client buffer error
             sp<NotificationListener> listener;
@@ -3279,7 +3282,8 @@
                 streamBuffer.stream = halStream;
                 switch (halStream->stream_type) {
                     case CAMERA3_STREAM_OUTPUT:
-                        res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0);
+                        res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0,
+                                /*timestampIncreasing*/true, std::vector<size_t> (), frameNumber);
                         if (res != OK) {
                             ALOGE("%s: Can't return output buffer for frame %d to"
                                   " stream %d: %s (%d)",  __FUNCTION__,
@@ -5469,6 +5473,8 @@
                     return TIMED_OUT;
                 }
             }
+            outputStream->fireBufferRequestForFrameNumber(
+                    captureRequest->mResultExtras.frameNumber);
 
             String8 physicalCameraId = outputStream->getPhysicalCameraId();
 
@@ -5692,7 +5698,9 @@
                 outputBuffers->editItemAt(i).acquire_fence = -1;
             }
             outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
-            captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0);
+            captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0,
+                    /*timestampIncreasing*/true, std::vector<size_t> (),
+                    captureRequest->mResultExtras.frameNumber);
         }
 
         if (sendRequestError) {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 24d1c1b..b296513 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -656,7 +656,7 @@
 
 status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
         nsecs_t timestamp, bool timestampIncreasing,
-         const std::vector<size_t>& surface_ids) {
+         const std::vector<size_t>& surface_ids, uint64_t frameNumber) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
@@ -687,7 +687,7 @@
      */
     status_t res = returnBufferLocked(b, timestamp, surface_ids);
     if (res == OK) {
-        fireBufferListenersLocked(b, /*acquired*/false, /*output*/true);
+        fireBufferListenersLocked(b, /*acquired*/false, /*output*/true, timestamp, frameNumber);
     }
 
     // Even if returning the buffer failed, we still want to signal whoever is waiting for the
@@ -763,8 +763,21 @@
     return getInputBufferProducerLocked(producer);
 }
 
+void Camera3Stream::fireBufferRequestForFrameNumber(uint64_t frameNumber) {
+    ATRACE_CALL();
+    Mutex::Autolock l(mLock);
+
+    for (auto &it : mBufferListenerList) {
+        sp<Camera3StreamBufferListener> listener = it.promote();
+        if (listener.get() != nullptr) {
+            listener->onBufferRequestForFrameNumber(frameNumber, getId());
+        }
+    }
+}
+
 void Camera3Stream::fireBufferListenersLocked(
-        const camera3_stream_buffer& buffer, bool acquired, bool output) {
+        const camera3_stream_buffer& buffer, bool acquired, bool output, nsecs_t timestamp,
+        uint64_t frameNumber) {
     List<wp<Camera3StreamBufferListener> >::iterator it, end;
 
     // TODO: finish implementing
@@ -773,6 +786,8 @@
         Camera3StreamBufferListener::BufferInfo();
     info.mOutput = output;
     info.mError = (buffer.status == CAMERA3_BUFFER_STATUS_ERROR);
+    info.mFrameNumber = frameNumber;
+    info.mTimestamp = timestamp;
     // TODO: rest of fields
 
     for (it = mBufferListenerList.begin(), end = mBufferListenerList.end();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index ddba9f6..06deba9 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -332,7 +332,8 @@
      */
     status_t         returnBuffer(const camera3_stream_buffer &buffer,
             nsecs_t timestamp, bool timestampIncreasing,
-            const std::vector<size_t>& surface_ids = std::vector<size_t>());
+            const std::vector<size_t>& surface_ids = std::vector<size_t>(),
+            uint64_t frameNumber = 0);
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
@@ -430,6 +431,11 @@
      */
     status_t         restoreConfiguredState();
 
+    /**
+     * Notify buffer stream listeners about incoming request with particular frame number.
+     */
+    void fireBufferRequestForFrameNumber(uint64_t frameNumber) override;
+
   protected:
     const int mId;
     /**
@@ -538,7 +544,7 @@
     static const nsecs_t kWaitForBufferDuration = 3000000000LL; // 3000 ms
 
     void fireBufferListenersLocked(const camera3_stream_buffer& buffer,
-                                  bool acquired, bool output);
+            bool acquired, bool output, nsecs_t timestamp = 0, uint64_t frameNumber = 0);
     List<wp<Camera3StreamBufferListener> > mBufferListenerList;
 
     status_t        cancelPrepareLocked();
diff --git a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
index 2db333d..0e6104e 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
@@ -41,6 +41,8 @@
     virtual void onBufferAcquired(const BufferInfo& bufferInfo) = 0;
     // Buffer was released by the HAL
     virtual void onBufferReleased(const BufferInfo& bufferInfo) = 0;
+    // Notify about incoming buffer request frame number
+    virtual void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) = 0;
 };
 
 }; //namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index a84720b..7b80cbd 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -259,7 +259,8 @@
      */
     virtual status_t returnBuffer(const camera3_stream_buffer &buffer,
             nsecs_t timestamp, bool timestampIncreasing = true,
-            const std::vector<size_t>& surface_ids = std::vector<size_t>()) = 0;
+            const std::vector<size_t>& surface_ids = std::vector<size_t>(),
+            uint64_t frameNumber = 0) = 0;
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
@@ -341,6 +342,11 @@
      * Camera3Stream.
      */
     virtual void setBufferFreedListener(wp<Camera3StreamBufferFreedListener> listener) = 0;
+
+    /**
+     * Notify buffer stream listeners about incoming request with particular frame number.
+     */
+    virtual void fireBufferRequestForFrameNumber(uint64_t frameNumber) = 0;
 };
 
 } // namespace camera3
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index edf4dab..0aa5acc 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -13,6 +13,8 @@
 ppoll: 1
 mmap2: 1
 getrandom: 1
+memfd_create: 1
+ftruncate64: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 966e214..6d88c84 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -18,15 +18,19 @@
 openat: 1
 open: 1
 getuid32: 1
+getuid: 1
+getrlimit: 1
 writev: 1
 ioctl: 1
 close: 1
 mmap2: 1
+mmap: 1
 fstat64: 1
 stat64: 1
 statfs64: 1
 madvise: 1
 fstatat64: 1
+newfstatat: 1
 futex: 1
 munmap: 1
 faccessat: 1
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 588141a..b9adbd9 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -21,6 +21,8 @@
 ppoll: 1
 mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
 mmap2: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+memfd_create: 1
+ftruncate64: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index 1bee1b5..7abb432 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
@@ -26,6 +26,8 @@
 fstat: 1
 newfstatat: 1
 fstatfs: 1
+memfd_create: 1
+ftruncate64: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent