Merge "CCodec: reduce log amount for render warning" into qt-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index 0a9551d..2cc6fcb 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -15,7 +15,6 @@
 apex_defaults {
     name: "com.android.media-defaults",
     java_libs: ["updatable-media"],
-    compile_multilib: "both",
     multilib: {
         first: {
             // Extractor process runs only with the primary ABI.
@@ -33,12 +32,6 @@
                 "libwavextractor",
             ],
         },
-        both: {
-            native_shared_libs: [
-                // MediaPlayer2
-                "libmedia2_jni",
-            ],
-        },
     },
     key: "com.android.media.key",
     certificate: ":com.android.media.certificate",
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index b6896f5..715113d 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -27,7 +27,7 @@
 # TODO: replace the following when apex has a way to auto-generate this list
 # namespace.default.link.platform.shared_libs  = %LLNDK_LIBRARIES%
 # namespace.default.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so
+namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libdl_android.so:libvulkan.so
 
 ###############################################################################
 # "platform" namespace
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 320e7b3..4563b41 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -7670,6 +7670,24 @@
      * <li>ACAMERA_LENS_POSE_REFERENCE</li>
      * <li>ACAMERA_LENS_DISTORTION</li>
      * </ul>
+     * <p>The field of view of all non-RAW physical streams must be the same or as close as
+     * possible to that of non-RAW logical streams. If the requested FOV is outside of the
+     * range supported by the physical camera, the physical stream for that physical camera
+     * will use either the maximum or minimum scaler crop region, depending on which one is
+     * closer to the requested FOV. For example, for a logical camera with wide-tele lens
+     * configuration where the wide lens is the default, if the logical camera's crop region
+     * is set to maximum, the physical stream for the tele lens will be configured to its
+     * maximum crop region. On the other hand, if the logical camera has a normal-wide lens
+     * configuration where the normal lens is the default, when the logical camera's crop
+     * region is set to maximum, the FOV of the logical streams will be that of the normal
+     * lens. The FOV of the physical streams for the wide lens will be the same as the
+     * logical stream, by making the crop region smaller than its active array size to
+     * compensate for the smaller focal length.</p>
+     * <p>Even if the underlying physical cameras have different RAW characteristics (such as
+     * size or CFA pattern), a logical camera can still advertise RAW capability. In this
+     * case, when the application configures a RAW stream, the camera device will make sure
+     * the active physical camera will remain active to ensure consistent RAW output
+     * behavior, and not switch to other physical cameras.</p>
      * <p>To maintain backward compatibility, the capture request and result metadata tags
      * required for basic camera functionalities will be solely based on the
      * logical camera capabiltity. Other request and result metadata tags, on the other
@@ -8311,6 +8329,7 @@
      * fire the flash for flash power metering during precapture, and then fire the flash
      * for the final capture, if a flash is available on the device and the AE mode is set to
      * enable the flash.</p>
+     * <p>Devices that initially shipped with Android version <a href="https://developer.android.com/reference/android/os/Build.VERSION_CODES.html#Q">Q</a> or newer will not include any LEGACY-level devices.</p>
      *
      * @see ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
      * @see ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index b18c897..1fdff40 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -87,7 +87,7 @@
                 __FUNCTION__, strerror(-err), err);
         setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
     }
-    mHandler = new CallbackHandler();
+    mHandler = new CallbackHandler(id);
     mCbLooper->registerHandler(mHandler);
 
     const CameraMetadata& metadata = mChars->getInternalData();
@@ -918,6 +918,8 @@
     return;
 }
 
+CameraDevice::CallbackHandler::CallbackHandler(const char *id) : mId(id) { }
+
 void CameraDevice::CallbackHandler::onMessageReceived(
         const sp<AMessage> &msg) {
     switch (msg->what()) {
@@ -1012,9 +1014,9 @@
                 return;
             }
             sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
-            ACameraDevice* device = session->getDevice();
             mCachedSessions.push(session);
             sp<CaptureRequest> requestSp = nullptr;
+            const char *id_cstr = mId.c_str();
             switch (msg->what()) {
                 case kWhatCaptureStart:
                 case kWhatCaptureResult:
@@ -1063,7 +1065,7 @@
                         ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
                         return;
                     }
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
                     (*onStart)(context, session.get(), request, timestamp);
                     freeACaptureRequest(request);
                     break;
@@ -1086,7 +1088,7 @@
                         return;
                     }
                     sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
                     (*onResult)(context, session.get(), request, result.get());
                     freeACaptureRequest(request);
                     break;
@@ -1139,7 +1141,7 @@
                         physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
                     }
 
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
                     (*onResult)(context, session.get(), request, result.get(),
                             physicalResultInfo.size(), physicalCameraIdPtrs.data(),
                             physicalMetadataCopyPtrs.data());
@@ -1168,7 +1170,7 @@
                             static_cast<CameraCaptureFailure*>(obj.get()));
                     ACameraCaptureFailure* failure =
                             static_cast<ACameraCaptureFailure*>(failureSp.get());
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
                     (*onFail)(context, session.get(), request, failure);
                     freeACaptureRequest(request);
                     break;
@@ -1201,7 +1203,7 @@
                         failure.physicalCameraId = nullptr;
                     }
                     failure.captureFailure = *failureSp;
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
                     (*onFail)(context, session.get(), request, &failure);
                     freeACaptureRequest(request);
                     break;
@@ -1278,7 +1280,7 @@
                         return;
                     }
 
-                    ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
                     (*onBufferLost)(context, session.get(), request, anw, frameNumber);
                     freeACaptureRequest(request);
                     break;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 7036017..829b084 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -266,9 +266,11 @@
 
     class CallbackHandler : public AHandler {
       public:
+        explicit CallbackHandler(const char *id);
         void onMessageReceived(const sp<AMessage> &msg) override;
 
       private:
+        std::string mId;
         // This handler will cache all capture session sp until kWhatCleanUpSessions
         // is processed. This is used to guarantee the last session reference is always
         // being removed in callback thread without holding camera device lock
diff --git a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
index e7393ee..e3bafd3 100644
--- a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
+++ b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
@@ -270,7 +270,8 @@
     const uint8_t *data = rView.data() + inOffset;
     int32_t numChannels  = mVi->channels;
     int32_t samplingRate = mVi->rate;
-    if (inSize > 7 && !memcmp(&data[1], "vorbis", 6)) {
+    /* Decode vorbis headers only once */
+    if (inSize > 7 && !memcmp(&data[1], "vorbis", 6) && (!mInfoUnpacked || !mBooksUnpacked)) {
         if ((data[0] != 1) && (data[0] != 5)) {
             ALOGE("unexpected type received %d", data[0]);
             mSignalledError = true;
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index 97dde71..b73f0c8 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -1,4 +1,49 @@
 // DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-client-defaults instead
+cc_library {
+    name: "libcodec2_hidl_client@1.0",
+
+    defaults: ["hidl_defaults"],
+
+    srcs: [
+        "ClientBlockHelper.cpp",
+        "types.cpp",
+    ],
+
+    header_libs: [
+        "libcodec2_internal", // private
+    ],
+
+    shared_libs: [
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
+        "libbase",
+        "libcodec2",
+        "libcodec2_vndk",
+        "libcutils",
+        "libgui",
+        "libhidlbase",
+        "liblog",
+        "libstagefright_bufferpool@2.0",
+        "libui",
+        "libutils",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    export_shared_lib_headers: [
+        "android.hardware.media.c2@1.0",
+        "libcodec2",
+        "libgui",
+        "libstagefright_bufferpool@2.0",
+        "libui",
+    ],
+}
+
+
+// DO NOT DEPEND ON THIS DIRECTLY
 // use libcodec2-hidl-defaults instead
 cc_library {
     name: "libcodec2_hidl@1.0",
@@ -33,12 +78,10 @@
         "android.hardware.media.bufferpool@2.0",
         "android.hardware.media.c2@1.0",
         "android.hardware.media.omx@1.0",
-        "android.hidl.safe_union@1.0",
         "libbase",
         "libcodec2",
         "libcodec2_vndk",
         "libcutils",
-        "libgui",
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
@@ -56,9 +99,9 @@
     export_shared_lib_headers: [
         "android.hardware.media.c2@1.0",
         "libcodec2",
+        "libcodec2_vndk",
         "libhidlbase",
         "libstagefright_bufferpool@2.0",
-        "libstagefright_bufferqueue_helper",
         "libui",
     ],
 }
@@ -73,3 +116,14 @@
         "libcodec2_hidl@1.0",
     ],
 }
+
+// public dependency for Codec 2.0 HAL client
+cc_defaults {
+    name: "libcodec2-hidl-client-defaults",
+    defaults: ["libcodec2-impl-defaults"],
+
+    shared_libs: [
+        "android.hardware.media.c2@1.0",
+        "libcodec2_hidl_client@1.0",
+    ],
+}
diff --git a/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp b/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
new file mode 100644
index 0000000..1786c69
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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-block_helper"
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <codec2/hidl/1.0/ClientBlockHelper.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+        V2_0::IGraphicBufferProducer;
+using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+        V2_0::utils::B2HGraphicBufferProducer;
+
+namespace /* unnamed */ {
+
+// Create a GraphicBuffer object from a graphic block.
+sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
+    uint32_t width;
+    uint32_t height;
+    uint32_t format;
+    uint64_t usage;
+    uint32_t stride;
+    uint32_t generation;
+    uint64_t bqId;
+    int32_t bqSlot;
+    _UnwrapNativeCodec2GrallocMetadata(
+            block.handle(), &width, &height, &format, &usage,
+            &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
+    native_handle_t *grallocHandle =
+            UnwrapNativeCodec2GrallocHandle(block.handle());
+    sp<GraphicBuffer> graphicBuffer =
+            new GraphicBuffer(grallocHandle,
+                              GraphicBuffer::CLONE_HANDLE,
+                              width, height, format,
+                              1, usage, stride);
+    native_handle_delete(grallocHandle);
+    return graphicBuffer;
+}
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+                  BlockProcessor process) {
+    for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+        if (buffer) {
+            for (const C2ConstGraphicBlock& block :
+                    buffer->data().graphicBlocks()) {
+                process(block);
+            }
+        }
+    }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+                  BlockProcessor process,
+                  bool processInput, bool processOutput) {
+    for (const std::unique_ptr<C2Work>& work : workList) {
+        if (!work) {
+            continue;
+        }
+        if (processInput) {
+            forEachBlock(work->input, process);
+        }
+        if (processOutput) {
+            for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+                if (worklet) {
+                    forEachBlock(worklet->output,
+                                 process);
+                }
+            }
+        }
+    }
+}
+
+sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
+    sp<HGraphicBufferProducer> hgbp =
+            igbp->getHalInterface<HGraphicBufferProducer>();
+    return hgbp ? hgbp :
+            new B2HGraphicBufferProducer(igbp);
+}
+
+} // unnamed namespace
+
+status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
+                             const sp<IGraphicBufferProducer>& igbp,
+                             uint32_t generation,
+                             int32_t* bqSlot) {
+    if (!igbp) {
+        LOG(WARNING) << "attachToBufferQueue -- null producer.";
+        return NO_INIT;
+    }
+
+    sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
+    graphicBuffer->setGenerationNumber(generation);
+
+    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) {
+        LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+                        "status = " << result << ".";
+        return result;
+    }
+    LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+                 << *bqSlot << ".";
+    return OK;
+}
+
+bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
+                              uint32_t* generation,
+                              uint64_t* bqId,
+                              int32_t* bqSlot) {
+    return _C2BlockFactory::GetBufferQueueData(
+            _C2BlockFactory::GetGraphicBlockPoolData(block),
+            generation, bqId, bqSlot);
+}
+
+bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
+                            const sp<IGraphicBufferProducer>& igbp,
+                            uint64_t bqId,
+                            uint32_t generation) {
+    std::shared_ptr<_C2BlockPoolData> data =
+            _C2BlockFactory::GetGraphicBlockPoolData(block);
+    if (!data) {
+        return false;
+    }
+
+    uint32_t oldGeneration;
+    uint64_t oldId;
+    int32_t oldSlot;
+    // If the block is not bufferqueue-based, do nothing.
+    if (!_C2BlockFactory::GetBufferQueueData(
+            data, &oldGeneration, &oldId, &oldSlot) ||
+            (oldId == 0)) {
+        return false;
+    }
+
+    // If the block's bqId is the same as the desired bqId, just hold.
+    if ((oldId == bqId) && (oldGeneration == generation)) {
+        LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
+                     << " bqId " << oldId
+                     << ", bqSlot " << oldSlot
+                     << ", generation " << generation
+                     << ".";
+        _C2BlockFactory::HoldBlockFromBufferQueue(data, getHgbp(igbp));
+        return true;
+    }
+
+    // Otherwise, attach to the given igbp, which must not be null.
+    if (!igbp) {
+        return false;
+    }
+
+    int32_t bqSlot;
+    status_t result = attachToBufferQueue(block, igbp, generation, &bqSlot);
+
+    if (result != OK) {
+        LOG(ERROR) << "holdBufferQueueBlock -- fail to attach:"
+                   << " target bqId " << bqId
+                   << ", generation " << generation
+                   << ".";
+        return false;
+    }
+
+    LOG(VERBOSE) << "holdBufferQueueBlock -- attached:"
+                 << " bqId " << bqId
+                 << ", bqSlot " << bqSlot
+                 << ", generation " << generation
+                 << ".";
+    _C2BlockFactory::AssignBlockToBufferQueue(
+            data, getHgbp(igbp), generation, bqId, bqSlot, true);
+    return true;
+}
+
+void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
+                           const sp<IGraphicBufferProducer>& igbp,
+                           uint64_t bqId,
+                           uint32_t generation,
+                           bool forInput) {
+    forEachBlock(workList,
+                 std::bind(holdBufferQueueBlock,
+                           std::placeholders::_1, igbp, bqId, generation),
+                 forInput, !forInput);
+}
+
+}  // 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 53bb6d2..d6f84b4 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -222,8 +222,7 @@
     sp<InputSurface> inputSurface = new InputSurface(
             this,
             std::make_shared<C2ReflectorHelper>(),
-            new ::android::hardware::graphics::bufferqueue::V2_0::utils::
-                B2HGraphicBufferProducer(source->getIGraphicBufferProducer()),
+            source->getHGraphicBufferProducer(),
             source);
     _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
              inputSurface);
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
new file mode 100644
index 0000000..be429ac
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
@@ -0,0 +1,95 @@
+/*
+ * 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 CLIENT_BLOCK_HELPER_H
+#define CLIENT_BLOCK_HELPER_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <codec2/hidl/1.0/types.h>
+#include <C2Work.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+
+// BufferQueue-Based Block Operations
+// ==================================
+
+// Create a GraphicBuffer object from a graphic block and attach it to an
+// IGraphicBufferProducer.
+status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
+                             const sp<IGraphicBufferProducer>& igbp,
+                             uint32_t generation,
+                             int32_t* bqSlot);
+
+// Return false if block does not come from a bufferqueue-based blockpool.
+// Otherwise, extract generation, bqId and bqSlot and return true.
+bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
+                              uint32_t* generation,
+                              uint64_t* bqId,
+                              int32_t* bqSlot);
+
+// Assign the given block to a bufferqueue so that when the block is destroyed,
+// cancelBuffer() will be called.
+//
+// If the block does not come from a bufferqueue-based blockpool, this function
+// returns false.
+//
+// If the block already has a bufferqueue assignment that matches the given one,
+// the function returns true.
+//
+// If the block already has a bufferqueue assignment that does not match the
+// given one, the block will be reassigned to the given bufferqueue. This
+// will call attachBuffer() on the given igbp. The function then returns true on
+// success or false on any failure during the operation.
+//
+// Note: This function should be called after detachBuffer() or dequeueBuffer()
+// is called manually.
+bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
+                          const sp<IGraphicBufferProducer>& igbp,
+                          uint64_t bqId,
+                          uint32_t generation);
+
+// Call holdBufferQueueBlock() on input or output blocks in the given workList.
+// Since the bufferqueue assignment for input and output buffers can be
+// different, this function takes forInput to determine whether the given
+// bufferqueue is for input buffers or output buffers. (The default value of
+// forInput is false.)
+//
+// In the (rare) case that both input and output buffers are bufferqueue-based,
+// this function must be called twice, once for the input buffers and once for
+// the output buffers.
+//
+// Note: This function should be called after WorkBundle has been received from
+// another process.
+void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
+                           const sp<IGraphicBufferProducer>& igbp,
+                           uint64_t bqId,
+                           uint32_t generation,
+                           bool forInput = false);
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CLIENT_BLOCK_HELPER_H
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 817d148..0ddfec5 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
@@ -23,7 +23,6 @@
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
 #include <android/hardware/media/c2/1.0/types.h>
 #include <android/hidl/safe_union/1.0/types.h>
-#include <gui/IGraphicBufferProducer.h>
 
 #include <C2Component.h>
 #include <C2Param.h>
@@ -50,7 +49,6 @@
 using ::android::sp;
 using ::android::hardware::media::bufferpool::V2_0::implementation::
         ConnectionId;
-using ::android::IGraphicBufferProducer;
 
 // Types of metadata for Blocks.
 struct C2Hidl_Range {
@@ -301,20 +299,6 @@
 // BufferQueue-Based Block Operations
 // ==================================
 
-// Create a GraphicBuffer object from a graphic block and attach it to an
-// IGraphicBufferProducer.
-status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
-                             const sp<IGraphicBufferProducer>& igbp,
-                             uint32_t generation,
-                             int32_t* bqSlot);
-
-// Return false if block does not come from a bufferqueue-based blockpool.
-// Otherwise, extract generation, bqId and bqSlot and return true.
-bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
-                              uint32_t* generation,
-                              uint64_t* bqId,
-                              int32_t* bqSlot);
-
 // Disassociate the given block with its designated bufferqueue so that
 // cancelBuffer() will not be called when the block is destroyed. If the block
 // does not have a designated bufferqueue, the function returns false.
@@ -336,45 +320,6 @@
                             bool processInput = false,
                             bool processOutput = true);
 
-// Assign the given block to a bufferqueue so that when the block is destroyed,
-// cancelBuffer() will be called.
-//
-// If the block does not come from a bufferqueue-based blockpool, this function
-// returns false.
-//
-// If the block already has a bufferqueue assignment that matches the given one,
-// the function returns true.
-//
-// If the block already has a bufferqueue assignment that does not match the
-// given one, the block will be reassigned to the given bufferqueue. This
-// will call attachBuffer() on the given igbp. The function then returns true on
-// success or false on any failure during the operation.
-//
-// Note: This function should be called after detachBuffer() or dequeueBuffer()
-// is called manually.
-bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
-                          const sp<IGraphicBufferProducer>& igbp,
-                          uint64_t bqId,
-                          uint32_t generation);
-
-// Call holdBufferQueueBlock() on input or output blocks in the given workList.
-// Since the bufferqueue assignment for input and output buffers can be
-// different, this function takes forInput to determine whether the given
-// bufferqueue is for input buffers or output buffers. (The default value of
-// forInput is false.)
-//
-// In the (rare) case that both input and output buffers are bufferqueue-based,
-// this function must be called twice, once for the input buffers and once for
-// the output buffers.
-//
-// Note: This function should be called after WorkBundle has been received from
-// another process.
-void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
-                           const sp<IGraphicBufferProducer>& igbp,
-                           uint64_t bqId,
-                           uint32_t generation,
-                           bool forInput = false);
-
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace c2
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index 74320e7..3fd2f92 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -18,9 +18,7 @@
 #define LOG_TAG "Codec2-types"
 #include <android-base/logging.h>
 
-#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 #include <codec2/hidl/1.0/types.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
 #include <media/stagefright/foundation/AUtils.h>
 
 #include <C2AllocatorIon.h>
@@ -54,10 +52,6 @@
         ClientManager;
 using ::android::hardware::media::bufferpool::V2_0::implementation::
         TransactionId;
-using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
-        V2_0::IGraphicBufferProducer;
-using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
-        V2_0::utils::B2HGraphicBufferProducer;
 
 const char* asString(Status status, const char* def) {
     return asString(static_cast<c2_status_t>(status), def);
@@ -1741,30 +1735,6 @@
 
 namespace /* unnamed */ {
 
-// Create a GraphicBuffer object from a graphic block.
-sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
-    uint32_t width;
-    uint32_t height;
-    uint32_t format;
-    uint64_t usage;
-    uint32_t stride;
-    uint32_t generation;
-    uint64_t bqId;
-    int32_t bqSlot;
-    _UnwrapNativeCodec2GrallocMetadata(
-            block.handle(), &width, &height, &format, &usage,
-            &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
-    native_handle_t *grallocHandle =
-            UnwrapNativeCodec2GrallocHandle(block.handle());
-    sp<GraphicBuffer> graphicBuffer =
-            new GraphicBuffer(grallocHandle,
-                              GraphicBuffer::CLONE_HANDLE,
-                              width, height, format,
-                              1, usage, stride);
-    native_handle_delete(grallocHandle);
-    return graphicBuffer;
-}
-
 template <typename BlockProcessor>
 void forEachBlock(C2FrameData& frameData,
                   BlockProcessor process) {
@@ -1800,59 +1770,8 @@
     }
 }
 
-sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
-    sp<HGraphicBufferProducer> hgbp =
-            igbp->getHalInterface<HGraphicBufferProducer>();
-    return hgbp ? hgbp :
-            new B2HGraphicBufferProducer(igbp);
-}
-
 } // unnamed namespace
 
-status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
-                             const sp<IGraphicBufferProducer>& igbp,
-                             uint32_t generation,
-                             int32_t* bqSlot) {
-    if (!igbp) {
-        LOG(WARNING) << "attachToBufferQueue -- null producer.";
-        return NO_INIT;
-    }
-
-    sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
-    graphicBuffer->setGenerationNumber(generation);
-
-    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) {
-        LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
-                        "status = " << result << ".";
-        return result;
-    }
-    LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
-                 << *bqSlot << ".";
-    return OK;
-}
-
-bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
-                              uint32_t* generation,
-                              uint64_t* bqId,
-                              int32_t* bqSlot) {
-    return _C2BlockFactory::GetBufferQueueData(
-            _C2BlockFactory::GetGraphicBlockPoolData(block),
-            generation, bqId, bqSlot);
-}
-
 bool yieldBufferQueueBlock(const C2ConstGraphicBlock& block) {
     std::shared_ptr<_C2BlockPoolData> data =
             _C2BlockFactory::GetGraphicBlockPoolData(block);
@@ -1869,74 +1788,6 @@
     forEachBlock(workList, yieldBufferQueueBlock, processInput, processOutput);
 }
 
-bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
-                            const sp<IGraphicBufferProducer>& igbp,
-                            uint64_t bqId,
-                            uint32_t generation) {
-    std::shared_ptr<_C2BlockPoolData> data =
-            _C2BlockFactory::GetGraphicBlockPoolData(block);
-    if (!data) {
-        return false;
-    }
-
-    uint32_t oldGeneration;
-    uint64_t oldId;
-    int32_t oldSlot;
-    // If the block is not bufferqueue-based, do nothing.
-    if (!_C2BlockFactory::GetBufferQueueData(
-            data, &oldGeneration, &oldId, &oldSlot) ||
-            (oldId == 0)) {
-        return false;
-    }
-
-    // If the block's bqId is the same as the desired bqId, just hold.
-    if ((oldId == bqId) && (oldGeneration == generation)) {
-        LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
-                     << " bqId " << oldId
-                     << ", bqSlot " << oldSlot
-                     << ", generation " << generation
-                     << ".";
-        _C2BlockFactory::HoldBlockFromBufferQueue(data, getHgbp(igbp));
-        return true;
-    }
-
-    // Otherwise, attach to the given igbp, which must not be null.
-    if (!igbp) {
-        return false;
-    }
-
-    int32_t bqSlot;
-    status_t result = attachToBufferQueue(block, igbp, generation, &bqSlot);
-
-    if (result != OK) {
-        LOG(ERROR) << "holdBufferQueueBlock -- fail to attach:"
-                   << " target bqId " << bqId
-                   << ", generation " << generation
-                   << ".";
-        return false;
-    }
-
-    LOG(VERBOSE) << "holdBufferQueueBlock -- attached:"
-                 << " bqId " << bqId
-                 << ", bqSlot " << bqSlot
-                 << ", generation " << generation
-                 << ".";
-    _C2BlockFactory::AssignBlockToBufferQueue(
-            data, getHgbp(igbp), generation, bqId, bqSlot, true);
-    return true;
-}
-
-void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
-                           const sp<IGraphicBufferProducer>& igbp,
-                           uint64_t bqId,
-                           uint32_t generation,
-                           bool forInput) {
-    forEachBlock(workList,
-                 std::bind(holdBufferQueueBlock,
-                           std::placeholders::_1, igbp, bqId, generation),
-                 forInput, !forInput);
-}
-
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace c2
diff --git a/media/codec2/hidl/1.0/vts/functional/common/Android.bp b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
index 94f46ed..da0061a 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
@@ -2,7 +2,7 @@
     name: "VtsMediaC2V1_0CommonUtil",
     defaults: [
         "VtsHalTargetTestDefaults",
-        "libcodec2-hidl-defaults",
+        "libcodec2-hidl-client-defaults",
     ],
 
     include_dirs: [
@@ -20,7 +20,7 @@
     name: "VtsMediaC2V1_0Defaults",
     defaults: [
         "VtsHalTargetTestDefaults",
-        "libcodec2-hidl-defaults",
+        "libcodec2-hidl-client-defaults",
     ],
 
     static_libs: [
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index 965e438..6038a40 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -12,7 +12,7 @@
         "libbase",
         "libbinder",
         "libcodec2",
-        "libcodec2_hidl@1.0",
+        "libcodec2_hidl_client@1.0",
         "libcodec2_vndk",
         "libcutils",
         "libgui",
@@ -30,7 +30,8 @@
 
     export_shared_lib_headers: [
         "libcodec2",
-        "libcodec2_hidl@1.0",
+        "libcodec2_hidl_client@1.0",
+        "libcodec2_vndk",
     ],
 
 }
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 53adbbc..6aca4a3 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -75,82 +75,11 @@
 // c2_status_t value that corresponds to hwbinder transaction failure.
 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
 
-// Returns the list of IComponentStore service names that are available on the
-// device. This list is specified at the build time in manifest files.
-// Note: A software service will have "_software" as a suffix.
-std::vector<std::string> const& getServiceNames() {
-    static std::vector<std::string> sServiceNames{[]() {
-        using ::android::hardware::media::c2::V1_0::IComponentStore;
-        using ::android::hidl::manager::V1_2::IServiceManager;
-
-        while (true) {
-            sp<IServiceManager> serviceManager = IServiceManager::getService();
-            CHECK(serviceManager) << "Hardware service manager is not running.";
-
-            // There are three categories of services based on names.
-            std::vector<std::string> defaultNames; // Prefixed with "default"
-            std::vector<std::string> vendorNames;  // Prefixed with "vendor"
-            std::vector<std::string> otherNames;   // Others
-            Return<void> transResult;
-            transResult = serviceManager->listManifestByInterface(
-                    IComponentStore::descriptor,
-                    [&defaultNames, &vendorNames, &otherNames](
-                            hidl_vec<hidl_string> const& instanceNames) {
-                        for (hidl_string const& instanceName : instanceNames) {
-                            char const* name = instanceName.c_str();
-                            if (strncmp(name, "default", 7) == 0) {
-                                defaultNames.emplace_back(name);
-                            } else if (strncmp(name, "vendor", 6) == 0) {
-                                vendorNames.emplace_back(name);
-                            } else {
-                                otherNames.emplace_back(name);
-                            }
-                        }
-                    });
-            if (transResult.isOk()) {
-                // Sort service names in each category.
-                std::sort(defaultNames.begin(), defaultNames.end());
-                std::sort(vendorNames.begin(), vendorNames.end());
-                std::sort(otherNames.begin(), otherNames.end());
-
-                // Concatenate the three lists in this order: default, vendor,
-                // other.
-                std::vector<std::string>& names = defaultNames;
-                names.reserve(names.size() + vendorNames.size() + otherNames.size());
-                names.insert(names.end(),
-                             std::make_move_iterator(vendorNames.begin()),
-                             std::make_move_iterator(vendorNames.end()));
-                names.insert(names.end(),
-                             std::make_move_iterator(otherNames.begin()),
-                             std::make_move_iterator(otherNames.end()));
-
-                // Summarize to logcat.
-                if (names.empty()) {
-                    LOG(INFO) << "No Codec2 services declared in the manifest.";
-                } else {
-                    std::stringstream stringOutput;
-                    stringOutput << "Available Codec2 services:";
-                    for (std::string const& name : names) {
-                        stringOutput << " \"" << name << "\"";
-                    }
-                    LOG(INFO) << stringOutput.str();
-                }
-
-                return names;
-            }
-            LOG(ERROR) << "Could not retrieve the list of service instances of "
-                       << IComponentStore::descriptor
-                       << ". Retrying...";
-        }
-    }()};
-    return sServiceNames;
-}
-
-// Searches for a name in getServiceNames() and returns the index found. If the
+// Searches for a name in GetServiceNames() and returns the index found. If the
 // name is not found, the returned index will be equal to
-// getServiceNames().size().
+// GetServiceNames().size().
 size_t getServiceIndex(char const* name) {
-    std::vector<std::string> const& names = getServiceNames();
+    std::vector<std::string> const& names = Codec2Client::GetServiceNames();
     size_t i = 0;
     for (; i < names.size(); ++i) {
         if (name == names[i]) {
@@ -175,17 +104,14 @@
     std::vector<C2Component::Traits> mTraits;
     std::once_flag mTraitsInitializationFlag;
 
-    // The index of the service. This is based on getServiceNames().
+    // The index of the service. This is based on GetServiceNames().
     size_t mIndex;
-    // A "valid" cache object must have its mIndex set with init().
-    bool mValid{false};
     // Called by s() exactly once to initialize the cache. The index must be a
-    // valid index into the vector returned by getServiceNames(). Calling
+    // valid index into the vector returned by GetServiceNames(). Calling
     // init(index) will associate the cache to the service with name
-    // getServiceNames()[index].
+    // GetServiceNames()[index].
     void init(size_t index) {
         mIndex = index;
-        mValid = true;
     }
 
 public:
@@ -195,7 +121,6 @@
     // If the service is unavailable but listed in the manifest, this function
     // will block indefinitely.
     std::shared_ptr<Codec2Client> getClient() {
-        CHECK(mValid) << "Uninitialized cache";
         std::scoped_lock lock{mClientMutex};
         if (!mClient) {
             mClient = Codec2Client::_CreateFromIndex(mIndex);
@@ -208,7 +133,6 @@
     //
     // Note: This function is called only by ForAllServices().
     void invalidate() {
-        CHECK(mValid) << "Uninitialized cache";
         std::scoped_lock lock{mClientMutex};
         mClient = nullptr;
     }
@@ -216,7 +140,6 @@
     // Returns a list of traits for components supported by the service. This
     // list is cached.
     std::vector<C2Component::Traits> const& getTraits() {
-        CHECK(mValid) << "Uninitialized cache";
         std::call_once(mTraitsInitializationFlag, [this]() {
             bool success{false};
             // Spin until _listComponents() is successful.
@@ -229,7 +152,7 @@
                 using namespace std::chrono_literals;
                 static constexpr auto kServiceRetryPeriod = 5s;
                 LOG(INFO) << "Failed to retrieve component traits from service "
-                             "\"" << getServiceNames()[mIndex] << "\". "
+                             "\"" << GetServiceNames()[mIndex] << "\". "
                              "Retrying...";
                 std::this_thread::sleep_for(kServiceRetryPeriod);
             }
@@ -240,7 +163,7 @@
     // List() returns the list of all caches.
     static std::vector<Cache>& List() {
         static std::vector<Cache> sCaches{[]() {
-            size_t numServices = getServiceNames().size();
+            size_t numServices = GetServiceNames().size();
             std::vector<Cache> caches(numServices);
             for (size_t i = 0; i < numServices; ++i) {
                 caches[i].init(i);
@@ -610,8 +533,12 @@
     }
 }
 
+sp<Codec2Client::Base> const& Codec2Client::getBase() const {
+    return mBase;
+}
+
 std::string const& Codec2Client::getServiceName() const {
-    return getServiceNames()[mServiceIndex];
+    return GetServiceNames()[mServiceIndex];
 }
 
 c2_status_t Codec2Client::createComponent(
@@ -807,15 +734,94 @@
     return std::make_shared<SimpleParamReflector>(mBase);
 };
 
+std::vector<std::string> const& Codec2Client::GetServiceNames() {
+    static std::vector<std::string> sServiceNames{[]() {
+        using ::android::hardware::media::c2::V1_0::IComponentStore;
+        using ::android::hidl::manager::V1_2::IServiceManager;
+
+        while (true) {
+            sp<IServiceManager> serviceManager = IServiceManager::getService();
+            CHECK(serviceManager) << "Hardware service manager is not running.";
+
+            // There are three categories of services based on names.
+            std::vector<std::string> defaultNames; // Prefixed with "default"
+            std::vector<std::string> vendorNames;  // Prefixed with "vendor"
+            std::vector<std::string> otherNames;   // Others
+            Return<void> transResult;
+            transResult = serviceManager->listManifestByInterface(
+                    IComponentStore::descriptor,
+                    [&defaultNames, &vendorNames, &otherNames](
+                            hidl_vec<hidl_string> const& instanceNames) {
+                        for (hidl_string const& instanceName : instanceNames) {
+                            char const* name = instanceName.c_str();
+                            if (strncmp(name, "default", 7) == 0) {
+                                defaultNames.emplace_back(name);
+                            } else if (strncmp(name, "vendor", 6) == 0) {
+                                vendorNames.emplace_back(name);
+                            } else {
+                                otherNames.emplace_back(name);
+                            }
+                        }
+                    });
+            if (transResult.isOk()) {
+                // Sort service names in each category.
+                std::sort(defaultNames.begin(), defaultNames.end());
+                std::sort(vendorNames.begin(), vendorNames.end());
+                std::sort(otherNames.begin(), otherNames.end());
+
+                // Concatenate the three lists in this order: default, vendor,
+                // other.
+                std::vector<std::string>& names = defaultNames;
+                names.reserve(names.size() + vendorNames.size() + otherNames.size());
+                names.insert(names.end(),
+                             std::make_move_iterator(vendorNames.begin()),
+                             std::make_move_iterator(vendorNames.end()));
+                names.insert(names.end(),
+                             std::make_move_iterator(otherNames.begin()),
+                             std::make_move_iterator(otherNames.end()));
+
+                // Summarize to logcat.
+                if (names.empty()) {
+                    LOG(INFO) << "No Codec2 services declared in the manifest.";
+                } else {
+                    std::stringstream stringOutput;
+                    stringOutput << "Available Codec2 services:";
+                    for (std::string const& name : names) {
+                        stringOutput << " \"" << name << "\"";
+                    }
+                    LOG(INFO) << stringOutput.str();
+                }
+
+                return names;
+            }
+            LOG(ERROR) << "Could not retrieve the list of service instances of "
+                       << IComponentStore::descriptor
+                       << ". Retrying...";
+        }
+    }()};
+    return sServiceNames;
+}
+
 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
         const char* name) {
     size_t index = getServiceIndex(name);
-    return index == getServiceNames().size() ?
+    return index == GetServiceNames().size() ?
             nullptr : _CreateFromIndex(index);
 }
 
+std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
+        CreateFromAllServices() {
+    std::vector<std::shared_ptr<Codec2Client>> clients(
+            GetServiceNames().size());
+    for (size_t i = GetServiceNames().size(); i > 0; ) {
+        --i;
+        clients[i] = _CreateFromIndex(i);
+    }
+    return clients;
+}
+
 std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
-    std::string const& name = getServiceNames()[index];
+    std::string const& name = GetServiceNames()[index];
     LOG(INFO) << "Creating a Codec2 client to service \"" << name << "\"";
     sp<Base> baseStore = Base::getService(name);
     CHECK(baseStore) << "Codec2 service \"" << name << "\""
@@ -958,17 +964,17 @@
     if (inputSurfaceSetting == 0) {
         return nullptr;
     }
-    size_t index = getServiceNames().size();
+    size_t index = GetServiceNames().size();
     if (serviceName) {
         index = getServiceIndex(serviceName);
-        if (index == getServiceNames().size()) {
+        if (index == GetServiceNames().size()) {
             LOG(DEBUG) << "CreateInputSurface -- invalid service name: \""
                        << serviceName << "\"";
         }
     }
 
     std::shared_ptr<Codec2Client::InputSurface> inputSurface;
-    if (index != getServiceNames().size()) {
+    if (index != GetServiceNames().size()) {
         std::shared_ptr<Codec2Client> client = Cache::List()[index].getClient();
         if (client->createInputSurface(&inputSurface) == C2_OK) {
             return inputSurface;
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 8265380..03db515 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -18,8 +18,7 @@
 #define CODEC2_HIDL_CLIENT_H
 
 #include <gui/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/types.h>
-
+#include <codec2/hidl/1.0/ClientBlockHelper.h>
 #include <C2PlatformSupport.h>
 #include <C2Component.h>
 #include <C2Buffer.h>
@@ -144,6 +143,8 @@
 
     typedef Codec2Client Store;
 
+    sp<Base> const& getBase() const;
+
     std::string const& getServiceName() const;
 
     c2_status_t createComponent(
@@ -166,8 +167,17 @@
 
     std::shared_ptr<C2ParamReflector> getParamReflector();
 
+    // Returns the list of IComponentStore service names that are available on
+    // the device. This list is specified at the build time in manifest files.
+    // Note: A software service will have "_software" as a suffix.
+    static std::vector<std::string> const& GetServiceNames();
+
+    // Create a service with a given service name.
     static std::shared_ptr<Codec2Client> CreateFromService(char const* name);
 
+    // Get clients to all services.
+    static std::vector<std::shared_ptr<Codec2Client>> CreateFromAllServices();
+
     // Try to create a component with a given name from all known
     // IComponentStore services.
     static std::shared_ptr<Component> CreateComponentByName(
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 66457e7..8ae80ee 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -5,6 +5,7 @@
         "C2OMXNode.cpp",
         "CCodec.cpp",
         "CCodecBufferChannel.cpp",
+        "CCodecBuffers.cpp",
         "CCodecConfig.cpp",
         "Codec2Buffer.cpp",
         "Codec2InfoBuilder.cpp",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 751c8c5..85c783b 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -40,7 +40,6 @@
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/PersistentSurface.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
 
 #include "C2OMXNode.h"
 #include "CCodec.h"
@@ -1034,7 +1033,8 @@
     OmxStatus s;
     android::sp<HGraphicBufferProducer> gbp;
     android::sp<HGraphicBufferSource> gbs;
-    android::Return<void> transStatus = omx->createInputSurface(
+    using ::android::hardware::Return;
+    Return<void> transStatus = omx->createInputSurface(
             [&s, &gbp, &gbs](
                     OmxStatus status,
                     const android::sp<HGraphicBufferProducer>& producer,
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 1b21df1..715e78b 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -56,1398 +56,14 @@
 
 using CasStatus = hardware::cas::V1_0::Status;
 
-/**
- * Base class for representation of buffers at one port.
- */
-class CCodecBufferChannel::Buffers {
-public:
-    Buffers(const char *componentName, const char *name = "Buffers")
-        : mComponentName(componentName),
-          mChannelName(std::string(componentName) + ":" + name),
-          mName(mChannelName.c_str()) {
-    }
-    virtual ~Buffers() = default;
-
-    /**
-     * Set format for MediaCodec-facing buffers.
-     */
-    void setFormat(const sp<AMessage> &format) {
-        CHECK(format != nullptr);
-        mFormat = format;
-    }
-
-    /**
-     * Return a copy of current format.
-     */
-    sp<AMessage> dupFormat() {
-        return mFormat != nullptr ? mFormat->dup() : nullptr;
-    }
-
-    /**
-     * Returns true if the buffers are operating under array mode.
-     */
-    virtual bool isArrayMode() const { return false; }
-
-    /**
-     * Fills the vector with MediaCodecBuffer's if in array mode; otherwise,
-     * no-op.
-     */
-    virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {}
-
-    /**
-     * Return number of buffers the client owns.
-     */
-    virtual size_t numClientBuffers() const = 0;
-
-    void handleImageData(const sp<Codec2Buffer> &buffer) {
-        sp<ABuffer> imageDataCandidate = buffer->getImageData();
-        if (imageDataCandidate == nullptr) {
-            return;
-        }
-        sp<ABuffer> imageData;
-        if (!mFormat->findBuffer("image-data", &imageData)
-                || imageDataCandidate->size() != imageData->size()
-                || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
-            ALOGD("[%s] updating image-data", mName);
-            sp<AMessage> newFormat = dupFormat();
-            newFormat->setBuffer("image-data", imageDataCandidate);
-            MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
-            if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
-                int32_t stride = img->mPlane[0].mRowInc;
-                newFormat->setInt32(KEY_STRIDE, stride);
-                ALOGD("[%s] updating stride = %d", mName, stride);
-                if (img->mNumPlanes > 1 && stride > 0) {
-                    int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
-                    newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
-                    ALOGD("[%s] updating vstride = %d", mName, vstride);
-                }
-            }
-            setFormat(newFormat);
-            buffer->setFormat(newFormat);
-        }
-    }
-
-protected:
-    std::string mComponentName; ///< name of component for debugging
-    std::string mChannelName; ///< name of channel for debugging
-    const char *mName; ///< C-string version of channel name
-    // Format to be used for creating MediaCodec-facing buffers.
-    sp<AMessage> mFormat;
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(Buffers);
-};
-
-class CCodecBufferChannel::InputBuffers : public CCodecBufferChannel::Buffers {
-public:
-    InputBuffers(const char *componentName, const char *name = "Input[]")
-        : Buffers(componentName, name) { }
-    virtual ~InputBuffers() = default;
-
-    /**
-     * Set a block pool to obtain input memory blocks.
-     */
-    void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; }
-
-    /**
-     * Get a new MediaCodecBuffer for input and its corresponding index.
-     * Returns false if no new buffer can be obtained at the moment.
-     */
-    virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0;
-
-    /**
-     * Release the buffer obtained from requestNewBuffer() and get the
-     * associated C2Buffer object back. Returns true if the buffer was on file
-     * and released successfully.
-     */
-    virtual bool releaseBuffer(
-            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
-     * true if and only if the buffer was on file and released successfully.
-     */
-    virtual bool expireComponentBuffer(
-            const std::shared_ptr<C2Buffer> &c2buffer) = 0;
-
-    /**
-     * Flush internal state. After this call, no index or buffer previously
-     * returned from requestNewBuffer() is valid.
-     */
-    virtual void flush() = 0;
-
-    /**
-     * Return array-backed version of input buffers. The returned object
-     * shall retain the internal state so that it will honor index and
-     * buffer from previous calls of requestNewBuffer().
-     */
-    virtual std::unique_ptr<InputBuffers> toArrayMode(size_t size) = 0;
-
-protected:
-    // Pool to obtain blocks for input buffers.
-    std::shared_ptr<C2BlockPool> mPool;
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
-};
-
-class CCodecBufferChannel::OutputBuffers : public CCodecBufferChannel::Buffers {
-public:
-    OutputBuffers(const char *componentName, const char *name = "Output")
-        : Buffers(componentName, name) { }
-    virtual ~OutputBuffers() = default;
-
-    /**
-     * Register output C2Buffer from the component and obtain corresponding
-     * index and MediaCodecBuffer object. Returns false if registration
-     * fails.
-     */
-    virtual status_t registerBuffer(
-            const std::shared_ptr<C2Buffer> &buffer,
-            size_t *index,
-            sp<MediaCodecBuffer> *clientBuffer) = 0;
-
-    /**
-     * Register codec specific data as a buffer to be consistent with
-     * MediaCodec behavior.
-     */
-    virtual status_t registerCsd(
-            const C2StreamInitDataInfo::output * /* csd */,
-            size_t * /* index */,
-            sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
-
-    /**
-     * Release the buffer obtained from registerBuffer() and get the
-     * associated C2Buffer object back. Returns true if the buffer was on file
-     * and released successfully.
-     */
-    virtual bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
-
-    /**
-     * Flush internal state. After this call, no index or buffer previously
-     * returned from registerBuffer() is valid.
-     */
-    virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0;
-
-    /**
-     * Return array-backed version of output buffers. The returned object
-     * shall retain the internal state so that it will honor index and
-     * buffer from previous calls of registerBuffer().
-     */
-    virtual std::unique_ptr<OutputBuffers> toArrayMode(size_t size) = 0;
-
-    /**
-     * Initialize SkipCutBuffer object.
-     */
-    void initSkipCutBuffer(
-            int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
-        CHECK(mSkipCutBuffer == nullptr);
-        mDelay = delay;
-        mPadding = padding;
-        mSampleRate = sampleRate;
-        setSkipCutBuffer(delay, padding, channelCount);
-    }
-
-    /**
-     * Update the SkipCutBuffer object. No-op if it's never initialized.
-     */
-    void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
-        if (mSkipCutBuffer == nullptr) {
-            return;
-        }
-        int32_t delay = mDelay;
-        int32_t padding = mPadding;
-        if (sampleRate != mSampleRate) {
-            delay = ((int64_t)delay * sampleRate) / mSampleRate;
-            padding = ((int64_t)padding * sampleRate) / mSampleRate;
-        }
-        setSkipCutBuffer(delay, padding, channelCount);
-    }
-
-    /**
-     * Submit buffer to SkipCutBuffer object, if initialized.
-     */
-    void submit(const sp<MediaCodecBuffer> &buffer) {
-        if (mSkipCutBuffer != nullptr) {
-            mSkipCutBuffer->submit(buffer);
-        }
-    }
-
-    /**
-     * Transfer SkipCutBuffer object to the other Buffers object.
-     */
-    void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
-        mSkipCutBuffer = scb;
-    }
-
-protected:
-    sp<SkipCutBuffer> mSkipCutBuffer;
-
-private:
-    int32_t mDelay;
-    int32_t mPadding;
-    int32_t mSampleRate;
-
-    void setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
-        if (mSkipCutBuffer != nullptr) {
-            size_t prevSize = mSkipCutBuffer->size();
-            if (prevSize != 0u) {
-                ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
-            }
-        }
-        mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
-    }
-
-    DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
-};
-
 namespace {
 
-const static size_t kSmoothnessFactor = 4;
-const static size_t kRenderingDepth = 3;
-const static size_t kLinearBufferSize = 1048576;
-// This can fit 4K RGBA frame, and most likely client won't need more than this.
-const static size_t kMaxLinearBufferSize = 3840 * 2160 * 4;
+constexpr size_t kSmoothnessFactor = 4;
+constexpr size_t kRenderingDepth = 3;
 
-/**
- * Simple local buffer pool backed by std::vector.
- */
-class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> {
-public:
-    /**
-     * Create a new LocalBufferPool object.
-     *
-     * \param poolCapacity  max total size of buffers managed by this pool.
-     *
-     * \return  a newly created pool object.
-     */
-    static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity) {
-        return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
-    }
-
-    /**
-     * Return an ABuffer object whose size is at least |capacity|.
-     *
-     * \param   capacity  requested capacity
-     * \return  nullptr if the pool capacity is reached
-     *          an ABuffer object otherwise.
-     */
-    sp<ABuffer> newBuffer(size_t capacity) {
-        Mutex::Autolock lock(mMutex);
-        auto it = std::find_if(
-                mPool.begin(), mPool.end(),
-                [capacity](const std::vector<uint8_t> &vec) {
-                    return vec.capacity() >= capacity;
-                });
-        if (it != mPool.end()) {
-            sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
-            mPool.erase(it);
-            return buffer;
-        }
-        if (mUsedSize + capacity > mPoolCapacity) {
-            while (!mPool.empty()) {
-                mUsedSize -= mPool.back().capacity();
-                mPool.pop_back();
-            }
-            if (mUsedSize + capacity > mPoolCapacity) {
-                ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
-                        mUsedSize, capacity, mPoolCapacity);
-                return nullptr;
-            }
-        }
-        std::vector<uint8_t> vec(capacity);
-        mUsedSize += vec.capacity();
-        return new VectorBuffer(std::move(vec), shared_from_this());
-    }
-
-private:
-    /**
-     * ABuffer backed by std::vector.
-     */
-    class VectorBuffer : public ::android::ABuffer {
-    public:
-        /**
-         * Construct a VectorBuffer by taking the ownership of supplied vector.
-         *
-         * \param vec   backing vector of the buffer. this object takes
-         *              ownership at construction.
-         * \param pool  a LocalBufferPool object to return the vector at
-         *              destruction.
-         */
-        VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
-            : ABuffer(vec.data(), vec.capacity()),
-              mVec(std::move(vec)),
-              mPool(pool) {
-        }
-
-        ~VectorBuffer() override {
-            std::shared_ptr<LocalBufferPool> pool = mPool.lock();
-            if (pool) {
-                // If pool is alive, return the vector back to the pool so that
-                // it can be recycled.
-                pool->returnVector(std::move(mVec));
-            }
-        }
-
-    private:
-        std::vector<uint8_t> mVec;
-        std::weak_ptr<LocalBufferPool> mPool;
-    };
-
-    Mutex mMutex;
-    size_t mPoolCapacity;
-    size_t mUsedSize;
-    std::list<std::vector<uint8_t>> mPool;
-
-    /**
-     * Private constructor to prevent constructing non-managed LocalBufferPool.
-     */
-    explicit LocalBufferPool(size_t poolCapacity)
-        : mPoolCapacity(poolCapacity), mUsedSize(0) {
-    }
-
-    /**
-     * Take back the ownership of vec from the destructed VectorBuffer and put
-     * it in front of the pool.
-     */
-    void returnVector(std::vector<uint8_t> &&vec) {
-        Mutex::Autolock lock(mMutex);
-        mPool.push_front(std::move(vec));
-    }
-
-    DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool);
-};
-
-sp<GraphicBlockBuffer> AllocateGraphicBuffer(
-        const std::shared_ptr<C2BlockPool> &pool,
-        const sp<AMessage> &format,
-        uint32_t pixelFormat,
-        const C2MemoryUsage &usage,
-        const std::shared_ptr<LocalBufferPool> &localBufferPool) {
-    int32_t width, height;
-    if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
-        ALOGD("format lacks width or height");
-        return nullptr;
-    }
-
-    std::shared_ptr<C2GraphicBlock> block;
-    c2_status_t err = pool->fetchGraphicBlock(
-            width, height, pixelFormat, usage, &block);
-    if (err != C2_OK) {
-        ALOGD("fetch graphic block failed: %d", err);
-        return nullptr;
-    }
-
-    return GraphicBlockBuffer::Allocate(
-            format,
-            block,
-            [localBufferPool](size_t capacity) {
-                return localBufferPool->newBuffer(capacity);
-            });
-}
-
-class BuffersArrayImpl;
-
-/**
- * Flexible buffer slots implementation.
- */
-class FlexBuffersImpl {
-public:
-    FlexBuffersImpl(const char *name)
-        : mImplName(std::string(name) + ".Impl"),
-          mName(mImplName.c_str()) { }
-
-    /**
-     * Assign an empty slot for a buffer and return the index. If there's no
-     * empty slot, just add one at the end and return it.
-     *
-     * \param buffer[in]  a new buffer to assign a slot.
-     * \return            index of the assigned slot.
-     */
-    size_t assignSlot(const sp<Codec2Buffer> &buffer) {
-        for (size_t i = 0; i < mBuffers.size(); ++i) {
-            if (mBuffers[i].clientBuffer == nullptr
-                    && mBuffers[i].compBuffer.expired()) {
-                mBuffers[i].clientBuffer = buffer;
-                return i;
-            }
-        }
-        mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
-        return mBuffers.size() - 1;
-    }
-
-    /**
-     * Release the slot from the client, and get the C2Buffer object back from
-     * the previously assigned buffer. Note that the slot is not completely free
-     * until the returned C2Buffer object is freed.
-     *
-     * \param   buffer[in]        the buffer previously assigned a slot.
-     * \param   c2buffer[in,out]  pointer to C2Buffer to be populated. Ignored
-     *                            if null.
-     * \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 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;
-                if (release) {
-                    mBuffers[i].clientBuffer.clear();
-                }
-                index = i;
-                break;
-            }
-        }
-        if (clientBuffer == nullptr) {
-            ALOGV("[%s] %s: No matching buffer found", mName, __func__);
-            return false;
-        }
-        std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
-        if (!result) {
-            result = clientBuffer->asC2Buffer();
-            mBuffers[index].compBuffer = result;
-        }
-        if (c2buffer) {
-            *c2buffer = result;
-        }
-        return true;
-    }
-
-    bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
-        for (size_t i = 0; i < mBuffers.size(); ++i) {
-            std::shared_ptr<C2Buffer> compBuffer =
-                    mBuffers[i].compBuffer.lock();
-            if (!compBuffer || compBuffer != c2buffer) {
-                continue;
-            }
-            mBuffers[i].compBuffer.reset();
-            ALOGV("[%s] codec released buffer #%zu", mName, i);
-            return true;
-        }
-        ALOGV("[%s] codec released an unknown buffer", mName);
-        return false;
-    }
-
-    void flush() {
-        ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
-        mBuffers.clear();
-    }
-
-    size_t numClientBuffers() const {
-        return std::count_if(
-                mBuffers.begin(), mBuffers.end(),
-                [](const Entry &entry) {
-                    return (entry.clientBuffer != nullptr);
-                });
-    }
-
-private:
-    friend class BuffersArrayImpl;
-
-    std::string mImplName; ///< name for debugging
-    const char *mName; ///< C-string version of name
-
-    struct Entry {
-        sp<Codec2Buffer> clientBuffer;
-        std::weak_ptr<C2Buffer> compBuffer;
-    };
-    std::vector<Entry> mBuffers;
-};
-
-/**
- * Static buffer slots implementation based on a fixed-size array.
- */
-class BuffersArrayImpl {
-public:
-    BuffersArrayImpl()
-        : mImplName("BuffersArrayImpl"),
-          mName(mImplName.c_str()) { }
-
-    /**
-     * Initialize buffer array from the original |impl|. The buffers known by
-     * the client is preserved, and the empty slots are populated so that the
-     * array size is at least |minSize|.
-     *
-     * \param impl[in]      FlexBuffersImpl object used so far.
-     * \param minSize[in]   minimum size of the buffer array.
-     * \param allocate[in]  function to allocate a client buffer for an empty slot.
-     */
-    void initialize(
-            const FlexBuffersImpl &impl,
-            size_t minSize,
-            std::function<sp<Codec2Buffer>()> allocate) {
-        mImplName = impl.mImplName + "[N]";
-        mName = mImplName.c_str();
-        for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
-            sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
-            bool ownedByClient = (clientBuffer != nullptr);
-            if (!ownedByClient) {
-                clientBuffer = allocate();
-            }
-            mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
-        }
-        ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
-        for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
-            mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
-        }
-    }
-
-    /**
-     * Grab a buffer from the underlying array which matches the criteria.
-     *
-     * \param index[out]    index of the slot.
-     * \param buffer[out]   the matching buffer.
-     * \param match[in]     a function to test whether the buffer matches the
-     *                      criteria or not.
-     * \return OK           if successful,
-     *         WOULD_BLOCK  if slots are being used,
-     *         NO_MEMORY    if no slot matches the criteria, even though it's
-     *                      available
-     */
-    status_t grabBuffer(
-            size_t *index,
-            sp<Codec2Buffer> *buffer,
-            std::function<bool(const sp<Codec2Buffer> &)> match =
-                [](const sp<Codec2Buffer> &) { return true; }) {
-        // allBuffersDontMatch remains true if all buffers are available but
-        // match() returns false for every buffer.
-        bool allBuffersDontMatch = true;
-        for (size_t i = 0; i < mBuffers.size(); ++i) {
-            if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
-                if (match(mBuffers[i].clientBuffer)) {
-                    mBuffers[i].ownedByClient = true;
-                    *buffer = mBuffers[i].clientBuffer;
-                    (*buffer)->meta()->clear();
-                    (*buffer)->setRange(0, (*buffer)->capacity());
-                    *index = i;
-                    return OK;
-                }
-            } else {
-                allBuffersDontMatch = false;
-            }
-        }
-        return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
-    }
-
-    /**
-     * Return the buffer from the client, and get the C2Buffer object back from
-     * the buffer. Note that the slot is not completely free until the returned
-     * C2Buffer object is freed.
-     *
-     * \param   buffer[in]        the buffer previously grabbed.
-     * \param   c2buffer[in,out]  pointer to C2Buffer to be populated. Ignored
-     *                            if null.
-     * \return  true  if the buffer is successfully returned
-     *          false otherwise
-     */
-    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) {
-            if (mBuffers[i].clientBuffer == buffer) {
-                if (!mBuffers[i].ownedByClient) {
-                    ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", mName, i);
-                }
-                clientBuffer = mBuffers[i].clientBuffer;
-                if (release) {
-                    mBuffers[i].ownedByClient = false;
-                }
-                index = i;
-                break;
-            }
-        }
-        if (clientBuffer == nullptr) {
-            ALOGV("[%s] %s: No matching buffer found", mName, __func__);
-            return false;
-        }
-        ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
-        std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
-        if (!result) {
-            result = clientBuffer->asC2Buffer();
-            mBuffers[index].compBuffer = result;
-        }
-        if (c2buffer) {
-            *c2buffer = result;
-        }
-        return true;
-    }
-
-    bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
-        for (size_t i = 0; i < mBuffers.size(); ++i) {
-            std::shared_ptr<C2Buffer> compBuffer =
-                    mBuffers[i].compBuffer.lock();
-            if (!compBuffer) {
-                continue;
-            }
-            if (c2buffer == compBuffer) {
-                if (mBuffers[i].ownedByClient) {
-                    // This should not happen.
-                    ALOGD("[%s] codec released a buffer owned by client "
-                          "(index %zu)", mName, i);
-                }
-                mBuffers[i].compBuffer.reset();
-                ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
-                return true;
-            }
-        }
-        ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
-        return false;
-    }
-
-    /**
-     * Populate |array| with the underlying buffer array.
-     *
-     * \param array[out]  an array to be filled with the underlying buffer array.
-     */
-    void getArray(Vector<sp<MediaCodecBuffer>> *array) const {
-        array->clear();
-        for (const Entry &entry : mBuffers) {
-            array->push(entry.clientBuffer);
-        }
-    }
-
-    /**
-     * The client abandoned all known buffers, so reclaim the ownership.
-     */
-    void flush() {
-        for (Entry &entry : mBuffers) {
-            entry.ownedByClient = false;
-        }
-    }
-
-    void realloc(std::function<sp<Codec2Buffer>()> alloc) {
-        size_t size = mBuffers.size();
-        mBuffers.clear();
-        for (size_t i = 0; i < size; ++i) {
-            mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
-        }
-    }
-
-    size_t numClientBuffers() const {
-        return std::count_if(
-                mBuffers.begin(), mBuffers.end(),
-                [](const Entry &entry) {
-                    return entry.ownedByClient;
-                });
-    }
-
-private:
-    std::string mImplName; ///< name for debugging
-    const char *mName; ///< C-string version of name
-
-    struct Entry {
-        const sp<Codec2Buffer> clientBuffer;
-        std::weak_ptr<C2Buffer> compBuffer;
-        bool ownedByClient;
-    };
-    std::vector<Entry> mBuffers;
-};
-
-class InputBuffersArray : public CCodecBufferChannel::InputBuffers {
-public:
-    InputBuffersArray(const char *componentName, const char *name = "Input[N]")
-        : InputBuffers(componentName, name) { }
-    ~InputBuffersArray() override = default;
-
-    void initialize(
-            const FlexBuffersImpl &impl,
-            size_t minSize,
-            std::function<sp<Codec2Buffer>()> allocate) {
-        mImpl.initialize(impl, minSize, allocate);
-    }
-
-    bool isArrayMode() const final { return true; }
-
-    std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
-            size_t) final {
-        return nullptr;
-    }
-
-    void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
-        mImpl.getArray(array);
-    }
-
-    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
-        sp<Codec2Buffer> c2Buffer;
-        status_t err = mImpl.grabBuffer(index, &c2Buffer);
-        if (err == OK) {
-            c2Buffer->setFormat(mFormat);
-            handleImageData(c2Buffer);
-            *buffer = c2Buffer;
-            return true;
-        }
-        return false;
-    }
-
-    bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer,
-            std::shared_ptr<C2Buffer> *c2buffer,
-            bool release) override {
-        return mImpl.returnBuffer(buffer, c2buffer, release);
-    }
-
-    bool expireComponentBuffer(
-            const std::shared_ptr<C2Buffer> &c2buffer) override {
-        return mImpl.expireComponentBuffer(c2buffer);
-    }
-
-    void flush() override {
-        mImpl.flush();
-    }
-
-    size_t numClientBuffers() const final {
-        return mImpl.numClientBuffers();
-    }
-
-private:
-    BuffersArrayImpl mImpl;
-};
-
-class LinearInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
-    LinearInputBuffers(const char *componentName, const char *name = "1D-Input")
-        : InputBuffers(componentName, name),
-          mImpl(mName) { }
-
-    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
-        int32_t capacity = kLinearBufferSize;
-        (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
-        if ((size_t)capacity > kMaxLinearBufferSize) {
-            ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
-            capacity = kMaxLinearBufferSize;
-        }
-        // TODO: proper max input size
-        // TODO: read usage from intf
-        sp<Codec2Buffer> newBuffer = alloc((size_t)capacity);
-        if (newBuffer == nullptr) {
-            return false;
-        }
-        *index = mImpl.assignSlot(newBuffer);
-        *buffer = newBuffer;
-        return true;
-    }
-
-    bool releaseBuffer(
-            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.
-        mImpl.flush();
-    }
-
-    std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
-            size_t size) final {
-        int32_t capacity = kLinearBufferSize;
-        (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
-        if ((size_t)capacity > kMaxLinearBufferSize) {
-            ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
-            capacity = kMaxLinearBufferSize;
-        }
-        // TODO: proper max input size
-        // TODO: read usage from intf
-        std::unique_ptr<InputBuffersArray> array(
-                new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
-        array->setPool(mPool);
-        array->setFormat(mFormat);
-        array->initialize(
-                mImpl,
-                size,
-                [this, capacity] () -> sp<Codec2Buffer> { return alloc(capacity); });
-        return std::move(array);
-    }
-
-    size_t numClientBuffers() const final {
-        return mImpl.numClientBuffers();
-    }
-
-    virtual sp<Codec2Buffer> alloc(size_t size) {
-        C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        std::shared_ptr<C2LinearBlock> block;
-
-        c2_status_t err = mPool->fetchLinearBlock(size, usage, &block);
-        if (err != C2_OK) {
-            return nullptr;
-        }
-
-        return LinearBlockBuffer::Allocate(mFormat, block);
-    }
-
-private:
-    FlexBuffersImpl mImpl;
-};
-
-class EncryptedLinearInputBuffers : public LinearInputBuffers {
-public:
-    EncryptedLinearInputBuffers(
-            bool secure,
-            const sp<MemoryDealer> &dealer,
-            const sp<ICrypto> &crypto,
-            int32_t heapSeqNum,
-            size_t capacity,
-            size_t numInputSlots,
-            const char *componentName, const char *name = "EncryptedInput")
-        : LinearInputBuffers(componentName, name),
-          mUsage({0, 0}),
-          mDealer(dealer),
-          mCrypto(crypto),
-          mHeapSeqNum(heapSeqNum) {
-        if (secure) {
-            mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
-        } else {
-            mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        }
-        for (size_t i = 0; i < numInputSlots; ++i) {
-            sp<IMemory> memory = mDealer->allocate(capacity);
-            if (memory == nullptr) {
-                ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated", mName, i);
-                break;
-            }
-            mMemoryVector.push_back({std::weak_ptr<C2LinearBlock>(), memory});
-        }
-    }
-
-    ~EncryptedLinearInputBuffers() override {
-    }
-
-    sp<Codec2Buffer> alloc(size_t size) override {
-        sp<IMemory> memory;
-        size_t slot = 0;
-        for (; slot < mMemoryVector.size(); ++slot) {
-            if (mMemoryVector[slot].block.expired()) {
-                memory = mMemoryVector[slot].memory;
-                break;
-            }
-        }
-        if (memory == nullptr) {
-            return nullptr;
-        }
-
-        std::shared_ptr<C2LinearBlock> block;
-        c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
-        if (err != C2_OK || block == nullptr) {
-            return nullptr;
-        }
-
-        mMemoryVector[slot].block = block;
-        return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
-    }
-
-private:
-    C2MemoryUsage mUsage;
-    sp<MemoryDealer> mDealer;
-    sp<ICrypto> mCrypto;
-    int32_t mHeapSeqNum;
-    struct Entry {
-        std::weak_ptr<C2LinearBlock> block;
-        sp<IMemory> memory;
-    };
-    std::vector<Entry> mMemoryVector;
-};
-
-class GraphicMetadataInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
-    GraphicMetadataInputBuffers(const char *componentName, const char *name = "2D-MetaInput")
-        : InputBuffers(componentName, name),
-          mImpl(mName),
-          mStore(GetCodec2PlatformAllocatorStore()) { }
-    ~GraphicMetadataInputBuffers() override = default;
-
-    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
-        std::shared_ptr<C2Allocator> alloc;
-        c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
-        if (err != C2_OK) {
-            return false;
-        }
-        sp<GraphicMetadataBuffer> newBuffer = new GraphicMetadataBuffer(mFormat, alloc);
-        if (newBuffer == nullptr) {
-            return false;
-        }
-        *index = mImpl.assignSlot(newBuffer);
-        *buffer = newBuffer;
-        return true;
-    }
-
-    bool releaseBuffer(
-            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.
-    }
-
-    std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
-            size_t size) final {
-        std::shared_ptr<C2Allocator> alloc;
-        c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
-        if (err != C2_OK) {
-            return nullptr;
-        }
-        std::unique_ptr<InputBuffersArray> array(
-                new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
-        array->setPool(mPool);
-        array->setFormat(mFormat);
-        array->initialize(
-                mImpl,
-                size,
-                [format = mFormat, alloc]() -> sp<Codec2Buffer> {
-                    return new GraphicMetadataBuffer(format, alloc);
-                });
-        return std::move(array);
-    }
-
-    size_t numClientBuffers() const final {
-        return mImpl.numClientBuffers();
-    }
-
-private:
-    FlexBuffersImpl mImpl;
-    std::shared_ptr<C2AllocatorStore> mStore;
-};
-
-class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
-    GraphicInputBuffers(
-            size_t numInputSlots, const char *componentName, const char *name = "2D-BB-Input")
-        : InputBuffers(componentName, name),
-          mImpl(mName),
-          mLocalBufferPool(LocalBufferPool::Create(
-                  kMaxLinearBufferSize * numInputSlots)) { }
-    ~GraphicInputBuffers() override = default;
-
-    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
-        // TODO: proper max input size
-        // TODO: read usage from intf
-        C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer(
-                mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
-        if (newBuffer == nullptr) {
-            return false;
-        }
-        *index = mImpl.assignSlot(newBuffer);
-        handleImageData(newBuffer);
-        *buffer = newBuffer;
-        return true;
-    }
-
-    bool releaseBuffer(
-            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.
-    }
-
-    std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
-            size_t size) final {
-        std::unique_ptr<InputBuffersArray> array(
-                new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
-        array->setPool(mPool);
-        array->setFormat(mFormat);
-        array->initialize(
-                mImpl,
-                size,
-                [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
-                    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-                    return AllocateGraphicBuffer(
-                            pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
-                });
-        return std::move(array);
-    }
-
-    size_t numClientBuffers() const final {
-        return mImpl.numClientBuffers();
-    }
-
-private:
-    FlexBuffersImpl mImpl;
-    std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
-
-class DummyInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
-    DummyInputBuffers(const char *componentName, const char *name = "2D-Input")
-        : InputBuffers(componentName, name) { }
-
-    bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
-        return false;
-    }
-
-    bool releaseBuffer(
-            const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
-        return false;
-    }
-
-    bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &) override {
-        return false;
-    }
-    void flush() override {
-    }
-
-    std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
-            size_t) final {
-        return nullptr;
-    }
-
-    bool isArrayMode() const final { return true; }
-
-    void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
-        array->clear();
-    }
-
-    size_t numClientBuffers() const final {
-        return 0u;
-    }
-};
-
-class OutputBuffersArray : public CCodecBufferChannel::OutputBuffers {
-public:
-    OutputBuffersArray(const char *componentName, const char *name = "Output[N]")
-        : OutputBuffers(componentName, name) { }
-    ~OutputBuffersArray() override = default;
-
-    void initialize(
-            const FlexBuffersImpl &impl,
-            size_t minSize,
-            std::function<sp<Codec2Buffer>()> allocate) {
-        mImpl.initialize(impl, minSize, allocate);
-    }
-
-    bool isArrayMode() const final { return true; }
-
-    std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode(
-            size_t) final {
-        return nullptr;
-    }
-
-    status_t registerBuffer(
-            const std::shared_ptr<C2Buffer> &buffer,
-            size_t *index,
-            sp<MediaCodecBuffer> *clientBuffer) final {
-        sp<Codec2Buffer> c2Buffer;
-        status_t err = mImpl.grabBuffer(
-                index,
-                &c2Buffer,
-                [buffer](const sp<Codec2Buffer> &clientBuffer) {
-                    return clientBuffer->canCopy(buffer);
-                });
-        if (err == WOULD_BLOCK) {
-            ALOGV("[%s] buffers temporarily not available", mName);
-            return err;
-        } else if (err != OK) {
-            ALOGD("[%s] grabBuffer failed: %d", mName, err);
-            return err;
-        }
-        c2Buffer->setFormat(mFormat);
-        if (!c2Buffer->copy(buffer)) {
-            ALOGD("[%s] copy buffer failed", mName);
-            return WOULD_BLOCK;
-        }
-        submit(c2Buffer);
-        handleImageData(c2Buffer);
-        *clientBuffer = c2Buffer;
-        ALOGV("[%s] grabbed buffer %zu", mName, *index);
-        return OK;
-    }
-
-    status_t registerCsd(
-            const C2StreamInitDataInfo::output *csd,
-            size_t *index,
-            sp<MediaCodecBuffer> *clientBuffer) final {
-        sp<Codec2Buffer> c2Buffer;
-        status_t err = mImpl.grabBuffer(
-                index,
-                &c2Buffer,
-                [csd](const sp<Codec2Buffer> &clientBuffer) {
-                    return clientBuffer->base() != nullptr
-                            && clientBuffer->capacity() >= csd->flexCount();
-                });
-        if (err != OK) {
-            return err;
-        }
-        memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
-        c2Buffer->setRange(0, csd->flexCount());
-        c2Buffer->setFormat(mFormat);
-        *clientBuffer = c2Buffer;
-        return OK;
-    }
-
-    bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.returnBuffer(buffer, c2buffer, true);
-    }
-
-    void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
-        (void)flushedWork;
-        mImpl.flush();
-        if (mSkipCutBuffer != nullptr) {
-            mSkipCutBuffer->clear();
-        }
-    }
-
-    void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
-        mImpl.getArray(array);
-    }
-
-    void realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
-        std::function<sp<Codec2Buffer>()> alloc;
-        switch (c2buffer->data().type()) {
-            case C2BufferData::LINEAR: {
-                uint32_t size = kLinearBufferSize;
-                const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
-                if (block.size() < kMaxLinearBufferSize / 2) {
-                    size = block.size() * 2;
-                } else {
-                    size = kMaxLinearBufferSize;
-                }
-                alloc = [format = mFormat, size] {
-                    return new LocalLinearBuffer(format, new ABuffer(size));
-                };
-                break;
-            }
-
-            // TODO: add support
-            case C2BufferData::GRAPHIC:         FALLTHROUGH_INTENDED;
-
-            case C2BufferData::INVALID:         FALLTHROUGH_INTENDED;
-            case C2BufferData::LINEAR_CHUNKS:   FALLTHROUGH_INTENDED;
-            case C2BufferData::GRAPHIC_CHUNKS:  FALLTHROUGH_INTENDED;
-            default:
-                ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
-                return;
-        }
-        mImpl.realloc(alloc);
-    }
-
-    size_t numClientBuffers() const final {
-        return mImpl.numClientBuffers();
-    }
-
-private:
-    BuffersArrayImpl mImpl;
-};
-
-class FlexOutputBuffers : public CCodecBufferChannel::OutputBuffers {
-public:
-    FlexOutputBuffers(const char *componentName, const char *name = "Output[]")
-        : OutputBuffers(componentName, name),
-          mImpl(mName) { }
-
-    status_t registerBuffer(
-            const std::shared_ptr<C2Buffer> &buffer,
-            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);
-        handleImageData(newBuffer);
-        *clientBuffer = newBuffer;
-        ALOGV("[%s] registered buffer %zu", mName, *index);
-        return OK;
-    }
-
-    status_t registerCsd(
-            const C2StreamInitDataInfo::output *csd,
-            size_t *index,
-            sp<MediaCodecBuffer> *clientBuffer) final {
-        sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
-                mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
-        *index = mImpl.assignSlot(newBuffer);
-        *clientBuffer = newBuffer;
-        return OK;
-    }
-
-    bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer,
-            std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer, true);
-    }
-
-    void flush(
-            const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
-        (void) flushedWork;
-        // This is no-op by default unless we're in array mode where we need to keep
-        // track of the flushed work.
-    }
-
-    std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode(
-            size_t size) override {
-        std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
-        array->setFormat(mFormat);
-        array->transferSkipCutBuffer(mSkipCutBuffer);
-        array->initialize(
-                mImpl,
-                size,
-                [this]() { return allocateArrayBuffer(); });
-        return std::move(array);
-    }
-
-    size_t numClientBuffers() const final {
-        return mImpl.numClientBuffers();
-    }
-
-    /**
-     * Return an appropriate Codec2Buffer object for the type of buffers.
-     *
-     * \param buffer  C2Buffer object to wrap.
-     *
-     * \return  appropriate Codec2Buffer object to wrap |buffer|.
-     */
-    virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0;
-
-    /**
-     * Return an appropriate Codec2Buffer object for the type of buffers, to be
-     * used as an empty array buffer.
-     *
-     * \return  appropriate Codec2Buffer object which can copy() from C2Buffers.
-     */
-    virtual sp<Codec2Buffer> allocateArrayBuffer() = 0;
-
-private:
-    FlexBuffersImpl mImpl;
-};
-
-class LinearOutputBuffers : public FlexOutputBuffers {
-public:
-    LinearOutputBuffers(const char *componentName, const char *name = "1D-Output")
-        : FlexOutputBuffers(componentName, name) { }
-
-    void flush(
-            const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
-        if (mSkipCutBuffer != nullptr) {
-            mSkipCutBuffer->clear();
-        }
-        FlexOutputBuffers::flush(flushedWork);
-    }
-
-    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
-        if (buffer == nullptr) {
-            ALOGV("[%s] using a dummy buffer", mName);
-            return new LocalLinearBuffer(mFormat, new ABuffer(0));
-        }
-        if (buffer->data().type() != C2BufferData::LINEAR) {
-            ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
-            // We expect linear output buffers from the component.
-            return nullptr;
-        }
-        if (buffer->data().linearBlocks().size() != 1u) {
-            ALOGV("[%s] no linear buffers", mName);
-            // We expect one and only one linear block from the component.
-            return nullptr;
-        }
-        sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
-        if (clientBuffer == nullptr) {
-            ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
-            return nullptr;
-        }
-        submit(clientBuffer);
-        return clientBuffer;
-    }
-
-    sp<Codec2Buffer> allocateArrayBuffer() override {
-        // TODO: proper max output size
-        return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
-    }
-};
-
-class GraphicOutputBuffers : public FlexOutputBuffers {
-public:
-    GraphicOutputBuffers(const char *componentName, const char *name = "2D-Output")
-        : FlexOutputBuffers(componentName, name) { }
-
-    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
-        return new DummyContainerBuffer(mFormat, buffer);
-    }
-
-    sp<Codec2Buffer> allocateArrayBuffer() override {
-        return new DummyContainerBuffer(mFormat);
-    }
-};
-
-class RawGraphicOutputBuffers : public FlexOutputBuffers {
-public:
-    RawGraphicOutputBuffers(
-            size_t numOutputSlots, const char *componentName, const char *name = "2D-BB-Output")
-        : FlexOutputBuffers(componentName, name),
-          mLocalBufferPool(LocalBufferPool::Create(
-                  kMaxLinearBufferSize * numOutputSlots)) { }
-    ~RawGraphicOutputBuffers() override = default;
-
-    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
-        if (buffer == nullptr) {
-            sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
-                    mFormat,
-                    [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 {
-            return ConstGraphicBlockBuffer::Allocate(
-                    mFormat,
-                    buffer,
-                    [lbp = mLocalBufferPool](size_t capacity) {
-                        return lbp->newBuffer(capacity);
-                    });
-        }
-    }
-
-    sp<Codec2Buffer> allocateArrayBuffer() override {
-        return ConstGraphicBlockBuffer::AllocateEmpty(
-                mFormat,
-                [lbp = mLocalBufferPool](size_t capacity) {
-                    return lbp->newBuffer(capacity);
-                });
-    }
-
-private:
-    std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
+// This is for keeping IGBP's buffer dropping logic in legacy mode other
+// than making it non-blocking. Do not change this value.
+const static size_t kDequeueTimeoutNs = 0;
 
 }  // namespace
 
@@ -2846,6 +1462,7 @@
     sp<IGraphicBufferProducer> producer;
     if (newSurface) {
         newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        newSurface->setDequeueTimeout(kDequeueTimeoutNs);
         producer = newSurface->getIGraphicBufferProducer();
         producer->setGenerationNumber(generation);
     } else {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 964121e..9aec82d 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -27,12 +27,11 @@
 #include <Codec2Mapper.h>
 
 #include <codec2/hidl/client.h>
-#include <media/stagefright/bqhelper/GraphicBufferSource.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
 #include <media/stagefright/foundation/Mutexed.h>
 #include <media/stagefright/CodecBase.h>
 #include <media/ICrypto.h>
 
+#include "CCodecBuffers.h"
 #include "InputSurfaceWrapper.h"
 #include "PipelineWatcher.h"
 
@@ -151,11 +150,6 @@
 
     void setMetaMode(MetaMode mode);
 
-    // Internal classes
-    class Buffers;
-    class InputBuffers;
-    class OutputBuffers;
-
 private:
     class QueueGuard;
 
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
new file mode 100644
index 0000000..fb0efce
--- /dev/null
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -0,0 +1,963 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CCodecBuffers"
+#include <utils/Log.h>
+
+#include <C2PlatformSupport.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+#include "CCodecBuffers.h"
+
+namespace android {
+
+namespace {
+
+sp<GraphicBlockBuffer> AllocateGraphicBuffer(
+        const std::shared_ptr<C2BlockPool> &pool,
+        const sp<AMessage> &format,
+        uint32_t pixelFormat,
+        const C2MemoryUsage &usage,
+        const std::shared_ptr<LocalBufferPool> &localBufferPool) {
+    int32_t width, height;
+    if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
+        ALOGD("format lacks width or height");
+        return nullptr;
+    }
+
+    std::shared_ptr<C2GraphicBlock> block;
+    c2_status_t err = pool->fetchGraphicBlock(
+            width, height, pixelFormat, usage, &block);
+    if (err != C2_OK) {
+        ALOGD("fetch graphic block failed: %d", err);
+        return nullptr;
+    }
+
+    return GraphicBlockBuffer::Allocate(
+            format,
+            block,
+            [localBufferPool](size_t capacity) {
+                return localBufferPool->newBuffer(capacity);
+            });
+}
+
+}  // namespace
+
+// CCodecBuffers
+
+void CCodecBuffers::setFormat(const sp<AMessage> &format) {
+    CHECK(format != nullptr);
+    mFormat = format;
+}
+
+sp<AMessage> CCodecBuffers::dupFormat() {
+    return mFormat != nullptr ? mFormat->dup() : nullptr;
+}
+
+void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
+    sp<ABuffer> imageDataCandidate = buffer->getImageData();
+    if (imageDataCandidate == nullptr) {
+        return;
+    }
+    sp<ABuffer> imageData;
+    if (!mFormat->findBuffer("image-data", &imageData)
+            || imageDataCandidate->size() != imageData->size()
+            || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
+        ALOGD("[%s] updating image-data", mName);
+        sp<AMessage> newFormat = dupFormat();
+        newFormat->setBuffer("image-data", imageDataCandidate);
+        MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
+        if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
+            int32_t stride = img->mPlane[0].mRowInc;
+            newFormat->setInt32(KEY_STRIDE, stride);
+            ALOGD("[%s] updating stride = %d", mName, stride);
+            if (img->mNumPlanes > 1 && stride > 0) {
+                int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
+                newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
+                ALOGD("[%s] updating vstride = %d", mName, vstride);
+            }
+        }
+        setFormat(newFormat);
+        buffer->setFormat(newFormat);
+    }
+}
+
+// OutputBuffers
+
+void OutputBuffers::initSkipCutBuffer(
+        int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
+    CHECK(mSkipCutBuffer == nullptr);
+    mDelay = delay;
+    mPadding = padding;
+    mSampleRate = sampleRate;
+    setSkipCutBuffer(delay, padding, channelCount);
+}
+
+void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
+    if (mSkipCutBuffer == nullptr) {
+        return;
+    }
+    int32_t delay = mDelay;
+    int32_t padding = mPadding;
+    if (sampleRate != mSampleRate) {
+        delay = ((int64_t)delay * sampleRate) / mSampleRate;
+        padding = ((int64_t)padding * sampleRate) / mSampleRate;
+    }
+    setSkipCutBuffer(delay, padding, channelCount);
+}
+
+void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
+    if (mSkipCutBuffer != nullptr) {
+        mSkipCutBuffer->submit(buffer);
+    }
+}
+
+void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
+    mSkipCutBuffer = scb;
+}
+
+void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
+    if (mSkipCutBuffer != nullptr) {
+        size_t prevSize = mSkipCutBuffer->size();
+        if (prevSize != 0u) {
+            ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
+        }
+    }
+    mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
+}
+
+// LocalBufferPool
+
+std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
+    return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
+}
+
+sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
+    Mutex::Autolock lock(mMutex);
+    auto it = std::find_if(
+            mPool.begin(), mPool.end(),
+            [capacity](const std::vector<uint8_t> &vec) {
+                return vec.capacity() >= capacity;
+            });
+    if (it != mPool.end()) {
+        sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
+        mPool.erase(it);
+        return buffer;
+    }
+    if (mUsedSize + capacity > mPoolCapacity) {
+        while (!mPool.empty()) {
+            mUsedSize -= mPool.back().capacity();
+            mPool.pop_back();
+        }
+        if (mUsedSize + capacity > mPoolCapacity) {
+            ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
+                    mUsedSize, capacity, mPoolCapacity);
+            return nullptr;
+        }
+    }
+    std::vector<uint8_t> vec(capacity);
+    mUsedSize += vec.capacity();
+    return new VectorBuffer(std::move(vec), shared_from_this());
+}
+
+LocalBufferPool::VectorBuffer::VectorBuffer(
+        std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
+    : ABuffer(vec.data(), vec.capacity()),
+      mVec(std::move(vec)),
+      mPool(pool) {
+}
+
+LocalBufferPool::VectorBuffer::~VectorBuffer() {
+    std::shared_ptr<LocalBufferPool> pool = mPool.lock();
+    if (pool) {
+        // If pool is alive, return the vector back to the pool so that
+        // it can be recycled.
+        pool->returnVector(std::move(mVec));
+    }
+}
+
+void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
+    Mutex::Autolock lock(mMutex);
+    mPool.push_front(std::move(vec));
+}
+
+size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
+    for (size_t i = 0; i < mBuffers.size(); ++i) {
+        if (mBuffers[i].clientBuffer == nullptr
+                && mBuffers[i].compBuffer.expired()) {
+            mBuffers[i].clientBuffer = buffer;
+            return i;
+        }
+    }
+    mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
+    return mBuffers.size() - 1;
+}
+
+// FlexBuffersImpl
+
+bool FlexBuffersImpl::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;
+            if (release) {
+                mBuffers[i].clientBuffer.clear();
+            }
+            index = i;
+            break;
+        }
+    }
+    if (clientBuffer == nullptr) {
+        ALOGV("[%s] %s: No matching buffer found", mName, __func__);
+        return false;
+    }
+    std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+    if (!result) {
+        result = clientBuffer->asC2Buffer();
+        mBuffers[index].compBuffer = result;
+    }
+    if (c2buffer) {
+        *c2buffer = result;
+    }
+    return true;
+}
+
+bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
+    for (size_t i = 0; i < mBuffers.size(); ++i) {
+        std::shared_ptr<C2Buffer> compBuffer =
+                mBuffers[i].compBuffer.lock();
+        if (!compBuffer || compBuffer != c2buffer) {
+            continue;
+        }
+        mBuffers[i].compBuffer.reset();
+        ALOGV("[%s] codec released buffer #%zu", mName, i);
+        return true;
+    }
+    ALOGV("[%s] codec released an unknown buffer", mName);
+    return false;
+}
+
+void FlexBuffersImpl::flush() {
+    ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
+    mBuffers.clear();
+}
+
+size_t FlexBuffersImpl::numClientBuffers() const {
+    return std::count_if(
+            mBuffers.begin(), mBuffers.end(),
+            [](const Entry &entry) {
+                return (entry.clientBuffer != nullptr);
+            });
+}
+
+// BuffersArrayImpl
+
+void BuffersArrayImpl::initialize(
+        const FlexBuffersImpl &impl,
+        size_t minSize,
+        std::function<sp<Codec2Buffer>()> allocate) {
+    mImplName = impl.mImplName + "[N]";
+    mName = mImplName.c_str();
+    for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
+        sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
+        bool ownedByClient = (clientBuffer != nullptr);
+        if (!ownedByClient) {
+            clientBuffer = allocate();
+        }
+        mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
+    }
+    ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
+    for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
+        mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
+    }
+}
+
+status_t BuffersArrayImpl::grabBuffer(
+        size_t *index,
+        sp<Codec2Buffer> *buffer,
+        std::function<bool(const sp<Codec2Buffer> &)> match) {
+    // allBuffersDontMatch remains true if all buffers are available but
+    // match() returns false for every buffer.
+    bool allBuffersDontMatch = true;
+    for (size_t i = 0; i < mBuffers.size(); ++i) {
+        if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
+            if (match(mBuffers[i].clientBuffer)) {
+                mBuffers[i].ownedByClient = true;
+                *buffer = mBuffers[i].clientBuffer;
+                (*buffer)->meta()->clear();
+                (*buffer)->setRange(0, (*buffer)->capacity());
+                *index = i;
+                return OK;
+            }
+        } else {
+            allBuffersDontMatch = false;
+        }
+    }
+    return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
+}
+
+bool BuffersArrayImpl::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) {
+        if (mBuffers[i].clientBuffer == buffer) {
+            if (!mBuffers[i].ownedByClient) {
+                ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
+                      mName, i);
+            }
+            clientBuffer = mBuffers[i].clientBuffer;
+            if (release) {
+                mBuffers[i].ownedByClient = false;
+            }
+            index = i;
+            break;
+        }
+    }
+    if (clientBuffer == nullptr) {
+        ALOGV("[%s] %s: No matching buffer found", mName, __func__);
+        return false;
+    }
+    ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
+    std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+    if (!result) {
+        result = clientBuffer->asC2Buffer();
+        mBuffers[index].compBuffer = result;
+    }
+    if (c2buffer) {
+        *c2buffer = result;
+    }
+    return true;
+}
+
+bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
+    for (size_t i = 0; i < mBuffers.size(); ++i) {
+        std::shared_ptr<C2Buffer> compBuffer =
+                mBuffers[i].compBuffer.lock();
+        if (!compBuffer) {
+            continue;
+        }
+        if (c2buffer == compBuffer) {
+            if (mBuffers[i].ownedByClient) {
+                // This should not happen.
+                ALOGD("[%s] codec released a buffer owned by client "
+                      "(index %zu)", mName, i);
+            }
+            mBuffers[i].compBuffer.reset();
+            ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
+            return true;
+        }
+    }
+    ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
+    return false;
+}
+
+void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
+    array->clear();
+    for (const Entry &entry : mBuffers) {
+        array->push(entry.clientBuffer);
+    }
+}
+
+void BuffersArrayImpl::flush() {
+    for (Entry &entry : mBuffers) {
+        entry.ownedByClient = false;
+    }
+}
+
+void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
+    size_t size = mBuffers.size();
+    mBuffers.clear();
+    for (size_t i = 0; i < size; ++i) {
+        mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
+    }
+}
+
+size_t BuffersArrayImpl::numClientBuffers() const {
+    return std::count_if(
+            mBuffers.begin(), mBuffers.end(),
+            [](const Entry &entry) {
+                return entry.ownedByClient;
+            });
+}
+
+// InputBuffersArray
+
+void InputBuffersArray::initialize(
+        const FlexBuffersImpl &impl,
+        size_t minSize,
+        std::function<sp<Codec2Buffer>()> allocate) {
+    mImpl.initialize(impl, minSize, allocate);
+}
+
+void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
+    mImpl.getArray(array);
+}
+
+bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
+    sp<Codec2Buffer> c2Buffer;
+    status_t err = mImpl.grabBuffer(index, &c2Buffer);
+    if (err == OK) {
+        c2Buffer->setFormat(mFormat);
+        handleImageData(c2Buffer);
+        *buffer = c2Buffer;
+        return true;
+    }
+    return false;
+}
+
+bool InputBuffersArray::releaseBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        std::shared_ptr<C2Buffer> *c2buffer,
+        bool release) {
+    return mImpl.returnBuffer(buffer, c2buffer, release);
+}
+
+bool InputBuffersArray::expireComponentBuffer(
+        const std::shared_ptr<C2Buffer> &c2buffer) {
+    return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void InputBuffersArray::flush() {
+    mImpl.flush();
+}
+
+size_t InputBuffersArray::numClientBuffers() const {
+    return mImpl.numClientBuffers();
+}
+
+// LinearInputBuffers
+
+bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
+    int32_t capacity = kLinearBufferSize;
+    (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
+    if ((size_t)capacity > kMaxLinearBufferSize) {
+        ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
+        capacity = kMaxLinearBufferSize;
+    }
+    // TODO: proper max input size
+    // TODO: read usage from intf
+    sp<Codec2Buffer> newBuffer = alloc((size_t)capacity);
+    if (newBuffer == nullptr) {
+        return false;
+    }
+    *index = mImpl.assignSlot(newBuffer);
+    *buffer = newBuffer;
+    return true;
+}
+
+bool LinearInputBuffers::releaseBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        std::shared_ptr<C2Buffer> *c2buffer,
+        bool release) {
+    return mImpl.releaseSlot(buffer, c2buffer, release);
+}
+
+bool LinearInputBuffers::expireComponentBuffer(
+        const std::shared_ptr<C2Buffer> &c2buffer) {
+    return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void LinearInputBuffers::flush() {
+    // This is no-op by default unless we're in array mode where we need to keep
+    // track of the flushed work.
+    mImpl.flush();
+}
+
+std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(
+        size_t size) {
+    int32_t capacity = kLinearBufferSize;
+    (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
+    if ((size_t)capacity > kMaxLinearBufferSize) {
+        ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
+        capacity = kMaxLinearBufferSize;
+    }
+    // TODO: proper max input size
+    // TODO: read usage from intf
+    std::unique_ptr<InputBuffersArray> array(
+            new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
+    array->setPool(mPool);
+    array->setFormat(mFormat);
+    array->initialize(
+            mImpl,
+            size,
+            [this, capacity] () -> sp<Codec2Buffer> { return alloc(capacity); });
+    return std::move(array);
+}
+
+size_t LinearInputBuffers::numClientBuffers() const {
+    return mImpl.numClientBuffers();
+}
+
+sp<Codec2Buffer> LinearInputBuffers::alloc(size_t size) {
+    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+    std::shared_ptr<C2LinearBlock> block;
+
+    c2_status_t err = mPool->fetchLinearBlock(size, usage, &block);
+    if (err != C2_OK) {
+        return nullptr;
+    }
+
+    return LinearBlockBuffer::Allocate(mFormat, block);
+}
+
+// EncryptedLinearInputBuffers
+
+EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
+        bool secure,
+        const sp<MemoryDealer> &dealer,
+        const sp<ICrypto> &crypto,
+        int32_t heapSeqNum,
+        size_t capacity,
+        size_t numInputSlots,
+        const char *componentName, const char *name)
+    : LinearInputBuffers(componentName, name),
+      mUsage({0, 0}),
+      mDealer(dealer),
+      mCrypto(crypto),
+      mHeapSeqNum(heapSeqNum) {
+    if (secure) {
+        mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
+    } else {
+        mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+    }
+    for (size_t i = 0; i < numInputSlots; ++i) {
+        sp<IMemory> memory = mDealer->allocate(capacity);
+        if (memory == nullptr) {
+            ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
+                  mName, i);
+            break;
+        }
+        mMemoryVector.push_back({std::weak_ptr<C2LinearBlock>(), memory});
+    }
+}
+
+sp<Codec2Buffer> EncryptedLinearInputBuffers::alloc(size_t size) {
+    sp<IMemory> memory;
+    size_t slot = 0;
+    for (; slot < mMemoryVector.size(); ++slot) {
+        if (mMemoryVector[slot].block.expired()) {
+            memory = mMemoryVector[slot].memory;
+            break;
+        }
+    }
+    if (memory == nullptr) {
+        return nullptr;
+    }
+
+    std::shared_ptr<C2LinearBlock> block;
+    c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
+    if (err != C2_OK || block == nullptr) {
+        return nullptr;
+    }
+
+    mMemoryVector[slot].block = block;
+    return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
+}
+
+// GraphicMetadataInputBuffers
+
+GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
+        const char *componentName, const char *name)
+    : InputBuffers(componentName, name),
+      mImpl(mName),
+      mStore(GetCodec2PlatformAllocatorStore()) { }
+
+bool GraphicMetadataInputBuffers::requestNewBuffer(
+        size_t *index, sp<MediaCodecBuffer> *buffer) {
+    std::shared_ptr<C2Allocator> alloc;
+    c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
+    if (err != C2_OK) {
+        return false;
+    }
+    sp<GraphicMetadataBuffer> newBuffer = new GraphicMetadataBuffer(mFormat, alloc);
+    if (newBuffer == nullptr) {
+        return false;
+    }
+    *index = mImpl.assignSlot(newBuffer);
+    *buffer = newBuffer;
+    return true;
+}
+
+bool GraphicMetadataInputBuffers::releaseBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        std::shared_ptr<C2Buffer> *c2buffer,
+        bool release) {
+    return mImpl.releaseSlot(buffer, c2buffer, release);
+}
+
+bool GraphicMetadataInputBuffers::expireComponentBuffer(
+        const std::shared_ptr<C2Buffer> &c2buffer) {
+    return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void GraphicMetadataInputBuffers::flush() {
+    // This is no-op by default unless we're in array mode where we need to keep
+    // track of the flushed work.
+}
+
+std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
+        size_t size) {
+    std::shared_ptr<C2Allocator> alloc;
+    c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
+    if (err != C2_OK) {
+        return nullptr;
+    }
+    std::unique_ptr<InputBuffersArray> array(
+            new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
+    array->setPool(mPool);
+    array->setFormat(mFormat);
+    array->initialize(
+            mImpl,
+            size,
+            [format = mFormat, alloc]() -> sp<Codec2Buffer> {
+                return new GraphicMetadataBuffer(format, alloc);
+            });
+    return std::move(array);
+}
+
+size_t GraphicMetadataInputBuffers::numClientBuffers() const {
+    return mImpl.numClientBuffers();
+}
+
+// GraphicInputBuffers
+
+GraphicInputBuffers::GraphicInputBuffers(
+        size_t numInputSlots, const char *componentName, const char *name)
+    : InputBuffers(componentName, name),
+      mImpl(mName),
+      mLocalBufferPool(LocalBufferPool::Create(
+              kMaxLinearBufferSize * numInputSlots)) { }
+
+bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
+    // TODO: proper max input size
+    // TODO: read usage from intf
+    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+    sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer(
+            mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
+    if (newBuffer == nullptr) {
+        return false;
+    }
+    *index = mImpl.assignSlot(newBuffer);
+    handleImageData(newBuffer);
+    *buffer = newBuffer;
+    return true;
+}
+
+bool GraphicInputBuffers::releaseBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        std::shared_ptr<C2Buffer> *c2buffer,
+        bool release) {
+    return mImpl.releaseSlot(buffer, c2buffer, release);
+}
+
+bool GraphicInputBuffers::expireComponentBuffer(
+        const std::shared_ptr<C2Buffer> &c2buffer) {
+    return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void GraphicInputBuffers::flush() {
+    // This is no-op by default unless we're in array mode where we need to keep
+    // track of the flushed work.
+}
+
+std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
+    std::unique_ptr<InputBuffersArray> array(
+            new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
+    array->setPool(mPool);
+    array->setFormat(mFormat);
+    array->initialize(
+            mImpl,
+            size,
+            [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
+                C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+                return AllocateGraphicBuffer(
+                        pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
+            });
+    return std::move(array);
+}
+
+size_t GraphicInputBuffers::numClientBuffers() const {
+    return mImpl.numClientBuffers();
+}
+
+// OutputBuffersArray
+
+void OutputBuffersArray::initialize(
+        const FlexBuffersImpl &impl,
+        size_t minSize,
+        std::function<sp<Codec2Buffer>()> allocate) {
+    mImpl.initialize(impl, minSize, allocate);
+}
+
+status_t OutputBuffersArray::registerBuffer(
+        const std::shared_ptr<C2Buffer> &buffer,
+        size_t *index,
+        sp<MediaCodecBuffer> *clientBuffer) {
+    sp<Codec2Buffer> c2Buffer;
+    status_t err = mImpl.grabBuffer(
+            index,
+            &c2Buffer,
+            [buffer](const sp<Codec2Buffer> &clientBuffer) {
+                return clientBuffer->canCopy(buffer);
+            });
+    if (err == WOULD_BLOCK) {
+        ALOGV("[%s] buffers temporarily not available", mName);
+        return err;
+    } else if (err != OK) {
+        ALOGD("[%s] grabBuffer failed: %d", mName, err);
+        return err;
+    }
+    c2Buffer->setFormat(mFormat);
+    if (!c2Buffer->copy(buffer)) {
+        ALOGD("[%s] copy buffer failed", mName);
+        return WOULD_BLOCK;
+    }
+    submit(c2Buffer);
+    handleImageData(c2Buffer);
+    *clientBuffer = c2Buffer;
+    ALOGV("[%s] grabbed buffer %zu", mName, *index);
+    return OK;
+}
+
+status_t OutputBuffersArray::registerCsd(
+        const C2StreamInitDataInfo::output *csd,
+        size_t *index,
+        sp<MediaCodecBuffer> *clientBuffer) {
+    sp<Codec2Buffer> c2Buffer;
+    status_t err = mImpl.grabBuffer(
+            index,
+            &c2Buffer,
+            [csd](const sp<Codec2Buffer> &clientBuffer) {
+                return clientBuffer->base() != nullptr
+                        && clientBuffer->capacity() >= csd->flexCount();
+            });
+    if (err != OK) {
+        return err;
+    }
+    memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
+    c2Buffer->setRange(0, csd->flexCount());
+    c2Buffer->setFormat(mFormat);
+    *clientBuffer = c2Buffer;
+    return OK;
+}
+
+bool OutputBuffersArray::releaseBuffer(
+        const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+    return mImpl.returnBuffer(buffer, c2buffer, true);
+}
+
+void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
+    (void)flushedWork;
+    mImpl.flush();
+    if (mSkipCutBuffer != nullptr) {
+        mSkipCutBuffer->clear();
+    }
+}
+
+void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
+    mImpl.getArray(array);
+}
+
+void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
+    std::function<sp<Codec2Buffer>()> alloc;
+    switch (c2buffer->data().type()) {
+        case C2BufferData::LINEAR: {
+            uint32_t size = kLinearBufferSize;
+            const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
+            if (block.size() < kMaxLinearBufferSize / 2) {
+                size = block.size() * 2;
+            } else {
+                size = kMaxLinearBufferSize;
+            }
+            alloc = [format = mFormat, size] {
+                return new LocalLinearBuffer(format, new ABuffer(size));
+            };
+            break;
+        }
+
+        // TODO: add support
+        case C2BufferData::GRAPHIC:         [[fallthrough]];
+
+        case C2BufferData::INVALID:         [[fallthrough]];
+        case C2BufferData::LINEAR_CHUNKS:   [[fallthrough]];
+        case C2BufferData::GRAPHIC_CHUNKS:  [[fallthrough]];
+        default:
+            ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
+            return;
+    }
+    mImpl.realloc(alloc);
+}
+
+size_t OutputBuffersArray::numClientBuffers() const {
+    return mImpl.numClientBuffers();
+}
+
+// FlexOutputBuffers
+
+status_t FlexOutputBuffers::registerBuffer(
+        const std::shared_ptr<C2Buffer> &buffer,
+        size_t *index,
+        sp<MediaCodecBuffer> *clientBuffer) {
+    sp<Codec2Buffer> newBuffer = wrap(buffer);
+    if (newBuffer == nullptr) {
+        return NO_MEMORY;
+    }
+    newBuffer->setFormat(mFormat);
+    *index = mImpl.assignSlot(newBuffer);
+    handleImageData(newBuffer);
+    *clientBuffer = newBuffer;
+    ALOGV("[%s] registered buffer %zu", mName, *index);
+    return OK;
+}
+
+status_t FlexOutputBuffers::registerCsd(
+        const C2StreamInitDataInfo::output *csd,
+        size_t *index,
+        sp<MediaCodecBuffer> *clientBuffer) {
+    sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
+            mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
+    *index = mImpl.assignSlot(newBuffer);
+    *clientBuffer = newBuffer;
+    return OK;
+}
+
+bool FlexOutputBuffers::releaseBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        std::shared_ptr<C2Buffer> *c2buffer) {
+    return mImpl.releaseSlot(buffer, c2buffer, true);
+}
+
+void FlexOutputBuffers::flush(
+        const std::list<std::unique_ptr<C2Work>> &flushedWork) {
+    (void) flushedWork;
+    // This is no-op by default unless we're in array mode where we need to keep
+    // track of the flushed work.
+}
+
+std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
+    std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
+    array->setFormat(mFormat);
+    array->transferSkipCutBuffer(mSkipCutBuffer);
+    array->initialize(
+            mImpl,
+            size,
+            [this]() { return allocateArrayBuffer(); });
+    return std::move(array);
+}
+
+size_t FlexOutputBuffers::numClientBuffers() const {
+    return mImpl.numClientBuffers();
+}
+
+// LinearOutputBuffers
+
+void LinearOutputBuffers::flush(
+        const std::list<std::unique_ptr<C2Work>> &flushedWork) {
+    if (mSkipCutBuffer != nullptr) {
+        mSkipCutBuffer->clear();
+    }
+    FlexOutputBuffers::flush(flushedWork);
+}
+
+sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
+    if (buffer == nullptr) {
+        ALOGV("[%s] using a dummy buffer", mName);
+        return new LocalLinearBuffer(mFormat, new ABuffer(0));
+    }
+    if (buffer->data().type() != C2BufferData::LINEAR) {
+        ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
+        // We expect linear output buffers from the component.
+        return nullptr;
+    }
+    if (buffer->data().linearBlocks().size() != 1u) {
+        ALOGV("[%s] no linear buffers", mName);
+        // We expect one and only one linear block from the component.
+        return nullptr;
+    }
+    sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
+    if (clientBuffer == nullptr) {
+        ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
+        return nullptr;
+    }
+    submit(clientBuffer);
+    return clientBuffer;
+}
+
+sp<Codec2Buffer> LinearOutputBuffers::allocateArrayBuffer() {
+    // TODO: proper max output size
+    return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
+}
+
+// GraphicOutputBuffers
+
+sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
+    return new DummyContainerBuffer(mFormat, buffer);
+}
+
+sp<Codec2Buffer> GraphicOutputBuffers::allocateArrayBuffer() {
+    return new DummyContainerBuffer(mFormat);
+}
+
+// RawGraphicOutputBuffers
+
+RawGraphicOutputBuffers::RawGraphicOutputBuffers(
+        size_t numOutputSlots, const char *componentName, const char *name)
+    : FlexOutputBuffers(componentName, name),
+      mLocalBufferPool(LocalBufferPool::Create(
+              kMaxLinearBufferSize * numOutputSlots)) { }
+
+sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
+    if (buffer == nullptr) {
+        sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
+                mFormat,
+                [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 {
+        return ConstGraphicBlockBuffer::Allocate(
+                mFormat,
+                buffer,
+                [lbp = mLocalBufferPool](size_t capacity) {
+                    return lbp->newBuffer(capacity);
+                });
+    }
+}
+
+sp<Codec2Buffer> RawGraphicOutputBuffers::allocateArrayBuffer() {
+    return ConstGraphicBlockBuffer::AllocateEmpty(
+            mFormat,
+            [lbp = mLocalBufferPool](size_t capacity) {
+                return lbp->newBuffer(capacity);
+            });
+}
+
+}  // namespace android
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
new file mode 100644
index 0000000..f5d9fee
--- /dev/null
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -0,0 +1,808 @@
+/*
+ * 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.
+ */
+
+#ifndef CCODEC_BUFFERS_H_
+
+#define CCODEC_BUFFERS_H_
+
+#include <string>
+
+#include <C2Config.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/MediaCodecBuffer.h>
+
+#include "Codec2Buffer.h"
+#include "SkipCutBuffer.h"
+
+namespace android {
+
+constexpr size_t kLinearBufferSize = 1048576;
+// This can fit 4K RGBA frame, and most likely client won't need more than this.
+constexpr size_t kMaxLinearBufferSize = 3840 * 2160 * 4;
+
+/**
+ * Base class for representation of buffers at one port.
+ */
+class CCodecBuffers {
+public:
+    CCodecBuffers(const char *componentName, const char *name = "Buffers")
+        : mComponentName(componentName),
+          mChannelName(std::string(componentName) + ":" + name),
+          mName(mChannelName.c_str()) {
+    }
+    virtual ~CCodecBuffers() = default;
+
+    /**
+     * Set format for MediaCodec-facing buffers.
+     */
+    void setFormat(const sp<AMessage> &format);
+
+    /**
+     * Return a copy of current format.
+     */
+    sp<AMessage> dupFormat();
+
+    /**
+     * Returns true if the buffers are operating under array mode.
+     */
+    virtual bool isArrayMode() const { return false; }
+
+    /**
+     * Fills the vector with MediaCodecBuffer's if in array mode; otherwise,
+     * no-op.
+     */
+    virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {}
+
+    /**
+     * Return number of buffers the client owns.
+     */
+    virtual size_t numClientBuffers() const = 0;
+
+    /**
+     * Examine image data from the buffer and update the format if necessary.
+     */
+    void handleImageData(const sp<Codec2Buffer> &buffer);
+
+protected:
+    std::string mComponentName; ///< name of component for debugging
+    std::string mChannelName; ///< name of channel for debugging
+    const char *mName; ///< C-string version of channel name
+    // Format to be used for creating MediaCodec-facing buffers.
+    sp<AMessage> mFormat;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(CCodecBuffers);
+};
+
+class InputBuffers : public CCodecBuffers {
+public:
+    InputBuffers(const char *componentName, const char *name = "Input[]")
+        : CCodecBuffers(componentName, name) { }
+    virtual ~InputBuffers() = default;
+
+    /**
+     * Set a block pool to obtain input memory blocks.
+     */
+    void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; }
+
+    /**
+     * Get a new MediaCodecBuffer for input and its corresponding index.
+     * Returns false if no new buffer can be obtained at the moment.
+     */
+    virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0;
+
+    /**
+     * Release the buffer obtained from requestNewBuffer() and get the
+     * associated C2Buffer object back. Returns true if the buffer was on file
+     * and released successfully.
+     */
+    virtual bool releaseBuffer(
+            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
+     * true if and only if the buffer was on file and released successfully.
+     */
+    virtual bool expireComponentBuffer(
+            const std::shared_ptr<C2Buffer> &c2buffer) = 0;
+
+    /**
+     * Flush internal state. After this call, no index or buffer previously
+     * returned from requestNewBuffer() is valid.
+     */
+    virtual void flush() = 0;
+
+    /**
+     * Return array-backed version of input buffers. The returned object
+     * shall retain the internal state so that it will honor index and
+     * buffer from previous calls of requestNewBuffer().
+     */
+    virtual std::unique_ptr<InputBuffers> toArrayMode(size_t size) = 0;
+
+protected:
+    // Pool to obtain blocks for input buffers.
+    std::shared_ptr<C2BlockPool> mPool;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
+};
+
+class OutputBuffers : public CCodecBuffers {
+public:
+    OutputBuffers(const char *componentName, const char *name = "Output")
+        : CCodecBuffers(componentName, name) { }
+    virtual ~OutputBuffers() = default;
+
+    /**
+     * Register output C2Buffer from the component and obtain corresponding
+     * index and MediaCodecBuffer object. Returns false if registration
+     * fails.
+     */
+    virtual status_t registerBuffer(
+            const std::shared_ptr<C2Buffer> &buffer,
+            size_t *index,
+            sp<MediaCodecBuffer> *clientBuffer) = 0;
+
+    /**
+     * Register codec specific data as a buffer to be consistent with
+     * MediaCodec behavior.
+     */
+    virtual status_t registerCsd(
+            const C2StreamInitDataInfo::output * /* csd */,
+            size_t * /* index */,
+            sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
+
+    /**
+     * Release the buffer obtained from registerBuffer() and get the
+     * associated C2Buffer object back. Returns true if the buffer was on file
+     * and released successfully.
+     */
+    virtual bool releaseBuffer(
+            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
+
+    /**
+     * Flush internal state. After this call, no index or buffer previously
+     * returned from registerBuffer() is valid.
+     */
+    virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0;
+
+    /**
+     * Return array-backed version of output buffers. The returned object
+     * shall retain the internal state so that it will honor index and
+     * buffer from previous calls of registerBuffer().
+     */
+    virtual std::unique_ptr<OutputBuffers> toArrayMode(size_t size) = 0;
+
+    /**
+     * Initialize SkipCutBuffer object.
+     */
+    void initSkipCutBuffer(
+            int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount);
+
+    /**
+     * Update the SkipCutBuffer object. No-op if it's never initialized.
+     */
+    void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount);
+
+    /**
+     * Submit buffer to SkipCutBuffer object, if initialized.
+     */
+    void submit(const sp<MediaCodecBuffer> &buffer);
+
+    /**
+     * Transfer SkipCutBuffer object to the other Buffers object.
+     */
+    void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb);
+
+protected:
+    sp<SkipCutBuffer> mSkipCutBuffer;
+
+private:
+    int32_t mDelay;
+    int32_t mPadding;
+    int32_t mSampleRate;
+
+    void setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount);
+
+    DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
+};
+
+/**
+ * Simple local buffer pool backed by std::vector.
+ */
+class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> {
+public:
+    /**
+     * Create a new LocalBufferPool object.
+     *
+     * \param poolCapacity  max total size of buffers managed by this pool.
+     *
+     * \return  a newly created pool object.
+     */
+    static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity);
+
+    /**
+     * Return an ABuffer object whose size is at least |capacity|.
+     *
+     * \param   capacity  requested capacity
+     * \return  nullptr if the pool capacity is reached
+     *          an ABuffer object otherwise.
+     */
+    sp<ABuffer> newBuffer(size_t capacity);
+
+private:
+    /**
+     * ABuffer backed by std::vector.
+     */
+    class VectorBuffer : public ::android::ABuffer {
+    public:
+        /**
+         * Construct a VectorBuffer by taking the ownership of supplied vector.
+         *
+         * \param vec   backing vector of the buffer. this object takes
+         *              ownership at construction.
+         * \param pool  a LocalBufferPool object to return the vector at
+         *              destruction.
+         */
+        VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool);
+
+        ~VectorBuffer() override;
+
+    private:
+        std::vector<uint8_t> mVec;
+        std::weak_ptr<LocalBufferPool> mPool;
+    };
+
+    Mutex mMutex;
+    size_t mPoolCapacity;
+    size_t mUsedSize;
+    std::list<std::vector<uint8_t>> mPool;
+
+    /**
+     * Private constructor to prevent constructing non-managed LocalBufferPool.
+     */
+    explicit LocalBufferPool(size_t poolCapacity)
+        : mPoolCapacity(poolCapacity), mUsedSize(0) {
+    }
+
+    /**
+     * Take back the ownership of vec from the destructed VectorBuffer and put
+     * it in front of the pool.
+     */
+    void returnVector(std::vector<uint8_t> &&vec);
+
+    DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool);
+};
+
+class BuffersArrayImpl;
+
+/**
+ * Flexible buffer slots implementation.
+ */
+class FlexBuffersImpl {
+public:
+    FlexBuffersImpl(const char *name)
+        : mImplName(std::string(name) + ".Impl"),
+          mName(mImplName.c_str()) { }
+
+    /**
+     * Assign an empty slot for a buffer and return the index. If there's no
+     * empty slot, just add one at the end and return it.
+     *
+     * \param buffer[in]  a new buffer to assign a slot.
+     * \return            index of the assigned slot.
+     */
+    size_t assignSlot(const sp<Codec2Buffer> &buffer);
+
+    /**
+     * Release the slot from the client, and get the C2Buffer object back from
+     * the previously assigned buffer. Note that the slot is not completely free
+     * until the returned C2Buffer object is freed.
+     *
+     * \param   buffer[in]        the buffer previously assigned a slot.
+     * \param   c2buffer[in,out]  pointer to C2Buffer to be populated. Ignored
+     *                            if null.
+     * \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 release);
+
+    /**
+     * Expire the C2Buffer object in the slot.
+     *
+     * \param   c2buffer[in]  C2Buffer object which the component released.
+     * \return  true  if the buffer is found in one of the slots and
+     *                successfully released
+     *          false otherwise
+     */
+    bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer);
+
+    /**
+     * The client abandoned all known buffers, so reclaim the ownership.
+     */
+    void flush();
+
+    /**
+     * Return the number of buffers that are sent to the client but not released
+     * yet.
+     */
+    size_t numClientBuffers() const;
+
+private:
+    friend class BuffersArrayImpl;
+
+    std::string mImplName; ///< name for debugging
+    const char *mName; ///< C-string version of name
+
+    struct Entry {
+        sp<Codec2Buffer> clientBuffer;
+        std::weak_ptr<C2Buffer> compBuffer;
+    };
+    std::vector<Entry> mBuffers;
+};
+
+/**
+ * Static buffer slots implementation based on a fixed-size array.
+ */
+class BuffersArrayImpl {
+public:
+    BuffersArrayImpl()
+        : mImplName("BuffersArrayImpl"),
+          mName(mImplName.c_str()) { }
+
+    /**
+     * Initialize buffer array from the original |impl|. The buffers known by
+     * the client is preserved, and the empty slots are populated so that the
+     * array size is at least |minSize|.
+     *
+     * \param impl[in]      FlexBuffersImpl object used so far.
+     * \param minSize[in]   minimum size of the buffer array.
+     * \param allocate[in]  function to allocate a client buffer for an empty slot.
+     */
+    void initialize(
+            const FlexBuffersImpl &impl,
+            size_t minSize,
+            std::function<sp<Codec2Buffer>()> allocate);
+
+    /**
+     * Grab a buffer from the underlying array which matches the criteria.
+     *
+     * \param index[out]    index of the slot.
+     * \param buffer[out]   the matching buffer.
+     * \param match[in]     a function to test whether the buffer matches the
+     *                      criteria or not.
+     * \return OK           if successful,
+     *         WOULD_BLOCK  if slots are being used,
+     *         NO_MEMORY    if no slot matches the criteria, even though it's
+     *                      available
+     */
+    status_t grabBuffer(
+            size_t *index,
+            sp<Codec2Buffer> *buffer,
+            std::function<bool(const sp<Codec2Buffer> &)> match =
+                [](const sp<Codec2Buffer> &) { return true; });
+
+    /**
+     * Return the buffer from the client, and get the C2Buffer object back from
+     * the buffer. Note that the slot is not completely free until the returned
+     * C2Buffer object is freed.
+     *
+     * \param   buffer[in]        the buffer previously grabbed.
+     * \param   c2buffer[in,out]  pointer to C2Buffer to be populated. Ignored
+     *                            if null.
+     * \return  true  if the buffer is successfully returned
+     *          false otherwise
+     */
+    bool returnBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release);
+
+    /**
+     * Expire the C2Buffer object in the slot.
+     *
+     * \param   c2buffer[in]  C2Buffer object which the component released.
+     * \return  true  if the buffer is found in one of the slots and
+     *                successfully released
+     *          false otherwise
+     */
+    bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer);
+
+    /**
+     * Populate |array| with the underlying buffer array.
+     *
+     * \param array[out]  an array to be filled with the underlying buffer array.
+     */
+    void getArray(Vector<sp<MediaCodecBuffer>> *array) const;
+
+    /**
+     * The client abandoned all known buffers, so reclaim the ownership.
+     */
+    void flush();
+
+    /**
+     * Reallocate the array with the given allocation function.
+     *
+     * \param alloc[in] the allocation function for client buffers.
+     */
+    void realloc(std::function<sp<Codec2Buffer>()> alloc);
+
+    /**
+     * Return the number of buffers that are sent to the client but not released
+     * yet.
+     */
+    size_t numClientBuffers() const;
+
+private:
+    std::string mImplName; ///< name for debugging
+    const char *mName; ///< C-string version of name
+
+    struct Entry {
+        const sp<Codec2Buffer> clientBuffer;
+        std::weak_ptr<C2Buffer> compBuffer;
+        bool ownedByClient;
+    };
+    std::vector<Entry> mBuffers;
+};
+
+class InputBuffersArray : public InputBuffers {
+public:
+    InputBuffersArray(const char *componentName, const char *name = "Input[N]")
+        : InputBuffers(componentName, name) { }
+    ~InputBuffersArray() override = default;
+
+    /**
+     * Initialize this object from the non-array state. We keep existing slots
+     * at the same index, and for empty slots we allocate client buffers with
+     * the given allocate function. If the number of slots is less than minSize,
+     * we fill the array to the minimum size.
+     *
+     * \param impl[in]      existing non-array state
+     * \param minSize[in]   minimum size of the array
+     * \param allocate[in]  allocate function to fill empty slots
+     */
+    void initialize(
+            const FlexBuffersImpl &impl,
+            size_t minSize,
+            std::function<sp<Codec2Buffer>()> allocate);
+
+    bool isArrayMode() const final { return true; }
+
+    std::unique_ptr<InputBuffers> toArrayMode(size_t) final {
+        return nullptr;
+    }
+
+    void getArray(Vector<sp<MediaCodecBuffer>> *array) const final;
+
+    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+    bool releaseBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override;
+
+    bool expireComponentBuffer(
+            const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+    void flush() override;
+
+    size_t numClientBuffers() const final;
+
+private:
+    BuffersArrayImpl mImpl;
+};
+
+class LinearInputBuffers : public InputBuffers {
+public:
+    LinearInputBuffers(const char *componentName, const char *name = "1D-Input")
+        : InputBuffers(componentName, name),
+          mImpl(mName) { }
+    ~LinearInputBuffers() override = default;
+
+    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+    bool releaseBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override;
+
+    bool expireComponentBuffer(
+            const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+    void flush() override;
+
+    std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
+
+    size_t numClientBuffers() const final;
+
+    /**
+     * Allocate a client buffer with the given size. This method may be
+     * overridden to support different kind of linear buffers (e.g. encrypted).
+     */
+    virtual sp<Codec2Buffer> alloc(size_t size);
+
+private:
+    FlexBuffersImpl mImpl;
+};
+
+class EncryptedLinearInputBuffers : public LinearInputBuffers {
+public:
+    EncryptedLinearInputBuffers(
+            bool secure,
+            const sp<MemoryDealer> &dealer,
+            const sp<ICrypto> &crypto,
+            int32_t heapSeqNum,
+            size_t capacity,
+            size_t numInputSlots,
+            const char *componentName, const char *name = "EncryptedInput");
+
+    ~EncryptedLinearInputBuffers() override = default;
+
+    sp<Codec2Buffer> alloc(size_t size) override;
+
+private:
+    C2MemoryUsage mUsage;
+    sp<MemoryDealer> mDealer;
+    sp<ICrypto> mCrypto;
+    int32_t mHeapSeqNum;
+    struct Entry {
+        std::weak_ptr<C2LinearBlock> block;
+        sp<IMemory> memory;
+    };
+    std::vector<Entry> mMemoryVector;
+};
+
+class GraphicMetadataInputBuffers : public InputBuffers {
+public:
+    GraphicMetadataInputBuffers(const char *componentName, const char *name = "2D-MetaInput");
+    ~GraphicMetadataInputBuffers() override = default;
+
+    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+    bool releaseBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override;
+
+    bool expireComponentBuffer(
+            const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+    void flush() override;
+
+    std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
+
+    size_t numClientBuffers() const final;
+
+private:
+    FlexBuffersImpl mImpl;
+    std::shared_ptr<C2AllocatorStore> mStore;
+};
+
+class GraphicInputBuffers : public InputBuffers {
+public:
+    GraphicInputBuffers(
+            size_t numInputSlots, const char *componentName, const char *name = "2D-BB-Input");
+    ~GraphicInputBuffers() override = default;
+
+    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+    bool releaseBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override;
+
+    bool expireComponentBuffer(
+            const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+    void flush() override;
+
+    std::unique_ptr<InputBuffers> toArrayMode(
+            size_t size) final;
+
+    size_t numClientBuffers() const final;
+
+private:
+    FlexBuffersImpl mImpl;
+    std::shared_ptr<LocalBufferPool> mLocalBufferPool;
+};
+
+class DummyInputBuffers : public InputBuffers {
+public:
+    DummyInputBuffers(const char *componentName, const char *name = "2D-Input")
+        : InputBuffers(componentName, name) { }
+    ~DummyInputBuffers() override = default;
+
+    bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
+        return false;
+    }
+
+    bool releaseBuffer(
+            const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
+        return false;
+    }
+
+    bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &) override {
+        return false;
+    }
+    void flush() override {
+    }
+
+    std::unique_ptr<InputBuffers> toArrayMode(size_t) final {
+        return nullptr;
+    }
+
+    bool isArrayMode() const final { return true; }
+
+    void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
+        array->clear();
+    }
+
+    size_t numClientBuffers() const final {
+        return 0u;
+    }
+};
+
+class OutputBuffersArray : public OutputBuffers {
+public:
+    OutputBuffersArray(const char *componentName, const char *name = "Output[N]")
+        : OutputBuffers(componentName, name) { }
+    ~OutputBuffersArray() override = default;
+
+    /**
+     * Initialize this object from the non-array state. We keep existing slots
+     * at the same index, and for empty slots we allocate client buffers with
+     * the given allocate function. If the number of slots is less than minSize,
+     * we fill the array to the minimum size.
+     *
+     * \param impl[in]      existing non-array state
+     * \param minSize[in]   minimum size of the array
+     * \param allocate[in]  allocate function to fill empty slots
+     */
+    void initialize(
+            const FlexBuffersImpl &impl,
+            size_t minSize,
+            std::function<sp<Codec2Buffer>()> allocate);
+
+    bool isArrayMode() const final { return true; }
+
+    std::unique_ptr<OutputBuffers> toArrayMode(size_t) final {
+        return nullptr;
+    }
+
+    status_t registerBuffer(
+            const std::shared_ptr<C2Buffer> &buffer,
+            size_t *index,
+            sp<MediaCodecBuffer> *clientBuffer) final;
+
+    status_t registerCsd(
+            const C2StreamInitDataInfo::output *csd,
+            size_t *index,
+            sp<MediaCodecBuffer> *clientBuffer) final;
+
+    bool releaseBuffer(
+            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override;
+
+    void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
+
+    void getArray(Vector<sp<MediaCodecBuffer>> *array) const final;
+
+    /**
+     * Reallocate the array, filled with buffers with the same size as given
+     * buffer.
+     *
+     * \param c2buffer[in] the reference buffer
+     */
+    void realloc(const std::shared_ptr<C2Buffer> &c2buffer);
+
+    size_t numClientBuffers() const final;
+
+private:
+    BuffersArrayImpl mImpl;
+};
+
+class FlexOutputBuffers : public OutputBuffers {
+public:
+    FlexOutputBuffers(const char *componentName, const char *name = "Output[]")
+        : OutputBuffers(componentName, name),
+          mImpl(mName) { }
+
+    status_t registerBuffer(
+            const std::shared_ptr<C2Buffer> &buffer,
+            size_t *index,
+            sp<MediaCodecBuffer> *clientBuffer) override;
+
+    status_t registerCsd(
+            const C2StreamInitDataInfo::output *csd,
+            size_t *index,
+            sp<MediaCodecBuffer> *clientBuffer) final;
+
+    bool releaseBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer) override;
+
+    void flush(
+            const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
+
+    std::unique_ptr<OutputBuffers> toArrayMode(size_t size) override;
+
+    size_t numClientBuffers() const final;
+
+    /**
+     * Return an appropriate Codec2Buffer object for the type of buffers.
+     *
+     * \param buffer  C2Buffer object to wrap.
+     *
+     * \return  appropriate Codec2Buffer object to wrap |buffer|.
+     */
+    virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0;
+
+    /**
+     * Return an appropriate Codec2Buffer object for the type of buffers, to be
+     * used as an empty array buffer.
+     *
+     * \return  appropriate Codec2Buffer object which can copy() from C2Buffers.
+     */
+    virtual sp<Codec2Buffer> allocateArrayBuffer() = 0;
+
+private:
+    FlexBuffersImpl mImpl;
+};
+
+class LinearOutputBuffers : public FlexOutputBuffers {
+public:
+    LinearOutputBuffers(const char *componentName, const char *name = "1D-Output")
+        : FlexOutputBuffers(componentName, name) { }
+
+    void flush(
+            const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
+
+    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
+
+    sp<Codec2Buffer> allocateArrayBuffer() override;
+};
+
+class GraphicOutputBuffers : public FlexOutputBuffers {
+public:
+    GraphicOutputBuffers(const char *componentName, const char *name = "2D-Output")
+        : FlexOutputBuffers(componentName, name) { }
+
+    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
+
+    sp<Codec2Buffer> allocateArrayBuffer() override;
+};
+
+class RawGraphicOutputBuffers : public FlexOutputBuffers {
+public:
+    RawGraphicOutputBuffers(
+            size_t numOutputSlots, const char *componentName, const char *name = "2D-BB-Output");
+    ~RawGraphicOutputBuffers() override = default;
+
+    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
+
+    sp<Codec2Buffer> allocateArrayBuffer() override;
+
+private:
+    std::shared_ptr<LocalBufferPool> mLocalBufferPool;
+};
+
+}  // namespace android
+
+#endif  // CCODEC_BUFFERS_H_
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index c6ca670..198bd72 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -26,6 +26,7 @@
         "C2PlatformStorePluginLoader.cpp",
         "C2Store.cpp",
         "platform/C2BqBuffer.cpp",
+        "types.cpp",
         "util/C2Debug.cpp",
         "util/C2InterfaceHelper.cpp",
         "util/C2InterfaceUtils.cpp",
@@ -38,7 +39,6 @@
 
     export_shared_lib_headers: [
         "libbase",
-        "libgui",
         "android.hardware.media.bufferpool@2.0",
     ],
 
@@ -60,13 +60,12 @@
         "libbinder",
         "libcutils",
         "libdl",
-        "libgui",
         "libhardware",
         "libhidlbase",
         "libion",
         "libfmq",
         "liblog",
-        "libstagefright_bufferqueue_helper",
+        "libnativewindow",
         "libstagefright_foundation",
         "libstagefright_bufferpool@2.0",
         "libui",
diff --git a/media/codec2/vndk/include/types.h b/media/codec2/vndk/include/types.h
new file mode 100644
index 0000000..b41d3f8
--- /dev/null
+++ b/media/codec2/vndk/include/types.h
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#ifndef CODEC2_VNDK_TYPES_H
+#define CODEC2_VNDK_TYPES_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <hidl/HidlSupport.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::
+        Status;
+
+// A status_t value may have flags encoded. These flags are decoded into boolean
+// values if their corresponding output pointers are not null.
+bool b2h(status_t from, HStatus* to,
+         bool* bufferNeedsReallocation = nullptr,
+         bool* releaseAllBuffers = nullptr);
+// Simple 1-to-1 mapping. If BUFFER_NEEDS_REALLOCATION or RELEASE_ALL_BUFFERS
+// needs to be added, it must be done manually afterwards.
+bool h2b(HStatus from, status_t* to);
+
+// Fence
+// =====
+
+using BFence = ::android::Fence;
+// This class manages the lifetime of a copied handle. Its destructor calls
+// native_handle_delete() but not native_handle_close().
+struct HFenceWrapper {
+    HFenceWrapper() = default;
+    // Sets mHandle to a new value.
+    HFenceWrapper(native_handle_t* h);
+    // Deletes mHandle without closing.
+    ~HFenceWrapper();
+    // Deletes mHandle without closing, then sets mHandle to a new value.
+    HFenceWrapper& set(native_handle_t* h);
+    HFenceWrapper& operator=(native_handle_t* h);
+    // Returns a non-owning hidl_handle pointing to mHandle.
+    hidl_handle getHandle() const;
+    operator hidl_handle() const;
+protected:
+    native_handle_t* mHandle{nullptr};
+};
+
+// Does not clone the fd---only copy the fd. The returned HFenceWrapper should
+// not outlive the input Fence object.
+bool b2h(sp<BFence> const& from, HFenceWrapper* to);
+// Clones the fd and puts it in a new Fence object.
+bool h2b(native_handle_t const* from, sp<BFence>* to);
+
+// ConnectionType
+// ==============
+
+using HConnectionType = ::android::hardware::graphics::bufferqueue::V2_0::
+        ConnectionType;
+
+bool b2h(int from, HConnectionType* to);
+bool h2b(HConnectionType from, int* to);
+
+// Rect
+// ====
+
+using BRect = ::android::Rect;
+using HRect = ::android::hardware::graphics::common::V1_2::Rect;
+
+bool b2h(BRect const& from, HRect* to);
+bool h2b(HRect const& from, BRect* to);
+
+// Region
+// ======
+
+using BRegion = ::android::Region;
+using HRegion = ::android::hardware::hidl_vec<HRect>;
+
+bool b2h(BRegion const& from, HRegion* to);
+bool h2b(HRegion const& from, BRegion* to);
+
+// GraphicBuffer
+// =============
+
+using HardwareBuffer = ::android::hardware::graphics::common::V1_2::
+        HardwareBuffer;
+using HardwareBufferDescription = ::android::hardware::graphics::common::V1_2::
+        HardwareBufferDescription;
+
+// Does not clone the handle. The returned HardwareBuffer should not outlive the
+// input GraphicBuffer. Note that HardwareBuffer does not carry the generation
+// number, so this function needs another output argument.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+         uint32_t* toGenerationNumber = nullptr);
+// Clones the handle and creates a new GraphicBuffer from the cloned handle.
+// Note that the generation number of the GraphicBuffer has to be set manually
+// afterwards because HardwareBuffer does not have such information.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to);
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_VNDK_TYPES_H
+
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 9cc5677..3f40e56 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -18,8 +18,12 @@
 #define LOG_TAG "C2BqBuffer"
 #include <utils/Log.h>
 
-#include <gui/BufferQueueDefs.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <ui/BufferQueueDefs.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Fence.h>
+
+#include <types.h>
+
 #include <hidl/HidlSupport.h>
 
 #include <C2AllocatorGralloc.h>
@@ -35,7 +39,6 @@
 using ::android::C2AndroidMemoryUsage;
 using ::android::Fence;
 using ::android::GraphicBuffer;
-using ::android::IGraphicBufferProducer;
 using ::android::sp;
 using ::android::status_t;
 using ::android::wp;
@@ -223,7 +226,6 @@
                         }
                     });
             if (!transResult.isOk() || status != android::OK) {
-                ALOGD("cannot dequeue buffer %d", status);
                 if (transResult.isOk()) {
                     if (status == android::INVALID_OPERATION ||
                         status == android::TIMED_OUT ||
@@ -233,6 +235,7 @@
                         return C2_BLOCKING;
                     }
                 }
+                ALOGD("cannot dequeue buffer %d", status);
                 return C2_BAD_VALUE;
             }
         }
@@ -355,39 +358,31 @@
             return mInit;
         }
 
-        static int kMaxIgbpRetry = 20; // TODO: small number can cause crash in releasing.
         static int kMaxIgbpRetryDelayUs = 10000;
 
-        int curTry = 0;
-
-        while (curTry++ < kMaxIgbpRetry) {
-            std::unique_lock<std::mutex> lock(mMutex);
-            // TODO: return C2_NO_INIT
-            if (mProducerId == 0) {
-                std::shared_ptr<C2GraphicAllocation> alloc;
-                c2_status_t err = mAllocator->newGraphicAllocation(
-                        width, height, format, usage, &alloc);
-                if (err != C2_OK) {
-                    return err;
-                }
-                std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
-                        std::make_shared<C2BufferQueueBlockPoolData>(
-                                0, (uint64_t)0, ~0, shared_from_this());
-                // TODO: config?
-                *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
-                ALOGV("allocated a buffer successfully");
-
-                return C2_OK;
+        std::unique_lock<std::mutex> lock(mMutex);
+        if (mProducerId == 0) {
+            std::shared_ptr<C2GraphicAllocation> alloc;
+            c2_status_t err = mAllocator->newGraphicAllocation(
+                    width, height, format, usage, &alloc);
+            if (err != C2_OK) {
+                return err;
             }
-            c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
-            if (status == C2_BLOCKING) {
-                lock.unlock();
-                ::usleep(kMaxIgbpRetryDelayUs);
-                continue;
-            }
-            return status;
+            std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+                    std::make_shared<C2BufferQueueBlockPoolData>(
+                            0, (uint64_t)0, ~0, shared_from_this());
+            *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+            ALOGV("allocated a buffer successfully");
+
+            return C2_OK;
         }
-        return C2_BLOCKING;
+        c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
+        if (status == C2_BLOCKING) {
+            lock.unlock();
+            // in order not to drain cpu from component's spinning
+            ::usleep(kMaxIgbpRetryDelayUs);
+        }
+        return status;
     }
 
     void setRenderCallback(const OnRenderCallback &renderCallback) {
diff --git a/media/codec2/vndk/types.cpp b/media/codec2/vndk/types.cpp
new file mode 100644
index 0000000..99b1e9b
--- /dev/null
+++ b/media/codec2/vndk/types.cpp
@@ -0,0 +1,309 @@
+/*
+ * 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 <cutils/native_handle.h>
+#include <ui/BufferQueueDefs.h>
+#include <types.h>
+#include <system/window.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// TODO: move this into ui/BufferQueueDefs.h so that we don't need
+// to include headers from libgui.
+enum {
+    // The API number used to indicate the currently connected producer
+    CURRENTLY_CONNECTED_API = -1,
+    // The API number used to indicate that no producer is connected
+    NO_CONNECTED_API        = 0,
+};
+
+// Status
+// ======
+
+bool b2h(status_t from, HStatus* to,
+         bool* bufferNeedsReallocation, bool* releaseAllBuffers) {
+    switch (from) {
+    case OK:
+        *to = HStatus::OK; break;
+    case NO_MEMORY:
+        *to = HStatus::NO_MEMORY; break;
+    case NO_INIT:
+        *to = HStatus::NO_INIT; break;
+    case BAD_VALUE:
+        *to = HStatus::BAD_VALUE; break;
+    case DEAD_OBJECT:
+        *to = HStatus::DEAD_OBJECT; break;
+    case INVALID_OPERATION:
+        *to = HStatus::INVALID_OPERATION; break;
+    case TIMED_OUT:
+        *to = HStatus::TIMED_OUT; break;
+    case WOULD_BLOCK:
+        *to = HStatus::WOULD_BLOCK; break;
+    case UNKNOWN_ERROR:
+        *to = HStatus::UNKNOWN_ERROR; break;
+    default:
+        status_t mask =
+                (bufferNeedsReallocation ? BufferQueueDefs::BUFFER_NEEDS_REALLOCATION : 0)
+                | (releaseAllBuffers ? BufferQueueDefs::RELEASE_ALL_BUFFERS : 0);
+        if (from & ~mask) {
+            *to = static_cast<HStatus>(from);
+        } else {
+            *to = HStatus::OK;
+            if (bufferNeedsReallocation) {
+                *bufferNeedsReallocation = from & BufferQueueDefs::BUFFER_NEEDS_REALLOCATION;
+            }
+            if (releaseAllBuffers) {
+                *releaseAllBuffers = from & BufferQueueDefs::RELEASE_ALL_BUFFERS;
+            }
+        }
+    }
+    return true;
+}
+
+bool h2b(HStatus from, status_t* to) {
+    switch (from) {
+    case HStatus::OK:
+        *to = OK; break;
+    case HStatus::NO_MEMORY:
+        *to = NO_MEMORY; break;
+    case HStatus::NO_INIT:
+        *to = NO_INIT; break;
+    case HStatus::BAD_VALUE:
+        *to = BAD_VALUE; break;
+    case HStatus::DEAD_OBJECT:
+        *to = DEAD_OBJECT; break;
+    case HStatus::INVALID_OPERATION:
+        *to = INVALID_OPERATION; break;
+    case HStatus::TIMED_OUT:
+        *to = TIMED_OUT; break;
+    case HStatus::WOULD_BLOCK:
+        *to = WOULD_BLOCK; break;
+    case HStatus::UNKNOWN_ERROR:
+        *to = UNKNOWN_ERROR; break;
+    default:
+        *to = static_cast<status_t>(from);
+    }
+    return true;
+}
+
+// Fence
+// =====
+
+HFenceWrapper::HFenceWrapper(native_handle_t* h) : mHandle{h} {
+}
+
+HFenceWrapper::~HFenceWrapper() {
+    native_handle_delete(mHandle);
+}
+
+HFenceWrapper& HFenceWrapper::set(native_handle_t* h) {
+    native_handle_delete(mHandle);
+    mHandle = h;
+    return *this;
+}
+
+HFenceWrapper& HFenceWrapper::operator=(native_handle_t* h) {
+    return set(h);
+}
+
+hidl_handle HFenceWrapper::getHandle() const {
+    return hidl_handle{mHandle};
+}
+
+HFenceWrapper::operator hidl_handle() const {
+    return getHandle();
+}
+
+bool b2h(sp<BFence> const& from, HFenceWrapper* to) {
+    if (!from) {
+        to->set(nullptr);
+        return true;
+    }
+    int fenceFd = from->get();
+    if (fenceFd == -1) {
+        to->set(nullptr);
+        return true;
+    }
+    native_handle_t* nh = native_handle_create(1, 0);
+    if (!nh) {
+        return false;
+    }
+    nh->data[0] = fenceFd;
+    to->set(nh);
+    return true;
+}
+
+bool h2b(native_handle_t const* from, sp<BFence>* to) {
+    if (!from || from->numFds == 0) {
+        *to = new ::android::Fence();
+        return true;
+    }
+    if (from->numFds != 1 || from->numInts != 0) {
+        return false;
+    }
+    *to = new BFence(dup(from->data[0]));
+    return true;
+}
+
+// ConnectionType
+// ==============
+
+bool b2h(int from, HConnectionType* to) {
+    *to = static_cast<HConnectionType>(from);
+    switch (from) {
+    case CURRENTLY_CONNECTED_API:
+        *to = HConnectionType::CURRENTLY_CONNECTED; break;
+    case NATIVE_WINDOW_API_EGL:
+        *to = HConnectionType::EGL; break;
+    case NATIVE_WINDOW_API_CPU:
+        *to = HConnectionType::CPU; break;
+    case NATIVE_WINDOW_API_MEDIA:
+        *to = HConnectionType::MEDIA; break;
+    case NATIVE_WINDOW_API_CAMERA:
+        *to = HConnectionType::CAMERA; break;
+    }
+    return true;
+}
+
+bool h2b(HConnectionType from, int* to) {
+    *to = static_cast<int>(from);
+    switch (from) {
+    case HConnectionType::CURRENTLY_CONNECTED:
+        *to = CURRENTLY_CONNECTED_API; break;
+    case HConnectionType::EGL:
+        *to = NATIVE_WINDOW_API_EGL; break;
+    case HConnectionType::CPU:
+        *to = NATIVE_WINDOW_API_CPU; break;
+    case HConnectionType::MEDIA:
+        *to = NATIVE_WINDOW_API_MEDIA; break;
+    case HConnectionType::CAMERA:
+        *to = NATIVE_WINDOW_API_CAMERA; break;
+    }
+    return true;
+}
+
+// Rect
+// ====
+
+bool b2h(BRect const& from, HRect* to) {
+    BRect* dst = reinterpret_cast<BRect*>(to->data());
+    dst->left = from.left;
+    dst->top = from.top;
+    dst->right = from.right;
+    dst->bottom = from.bottom;
+    return true;
+}
+
+bool h2b(HRect const& from, BRect* to) {
+    BRect const* src = reinterpret_cast<BRect const*>(from.data());
+    to->left = src->left;
+    to->top = src->top;
+    to->right = src->right;
+    to->bottom = src->bottom;
+    return true;
+}
+
+// Region
+// ======
+
+bool b2h(BRegion const& from, HRegion* to) {
+    size_t numRects;
+    BRect const* rectArray = from.getArray(&numRects);
+    to->resize(numRects);
+    for (size_t i = 0; i < numRects; ++i) {
+        if (!b2h(rectArray[i], &(*to)[i])) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool h2b(HRegion const& from, BRegion* to) {
+    if (from.size() > 0) {
+        BRect bRect;
+        if (!h2b(from[0], &bRect)) {
+            return false;
+        }
+        to->set(bRect);
+        for (size_t i = 1; i < from.size(); ++i) {
+            if (!h2b(from[i], &bRect)) {
+                return false;
+            }
+            to->addRectUnchecked(
+                    static_cast<int>(bRect.left),
+                    static_cast<int>(bRect.top),
+                    static_cast<int>(bRect.right),
+                    static_cast<int>(bRect.bottom));
+        }
+    } else {
+        to->clear();
+    }
+    return true;
+}
+
+// GraphicBuffer
+// =============
+
+// The handle is not cloned. Its lifetime is tied to the original GraphicBuffer.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+         uint32_t* toGenerationNumber) {
+    if (!from) {
+        return false;
+    }
+    AHardwareBuffer* hwBuffer = from->toAHardwareBuffer();
+    to->nativeHandle.setTo(
+          const_cast<native_handle_t*>(
+              AHardwareBuffer_getNativeHandle(hwBuffer)),
+          false);
+    AHardwareBuffer_describe(
+            hwBuffer,
+            reinterpret_cast<AHardwareBuffer_Desc*>(to->description.data()));
+    if (toGenerationNumber) {
+        *toGenerationNumber = from->getGenerationNumber();
+    }
+    return true;
+}
+
+// The handle is cloned.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to) {
+    AHardwareBuffer_Desc const* desc =
+            reinterpret_cast<AHardwareBuffer_Desc const*>(
+            from.description.data());
+    native_handle_t const* handle = from.nativeHandle;
+    AHardwareBuffer* hwBuffer;
+    if (AHardwareBuffer_createFromHandle(
+            desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+            &hwBuffer) != OK) {
+        return false;
+    }
+    *to = GraphicBuffer::fromAHardwareBuffer(hwBuffer);
+    AHardwareBuffer_release(hwBuffer);
+    return true;
+}
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index e284cda..a1c81f3 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -150,6 +150,7 @@
         AAC,
         HEVC,
         MP3,
+        PCM,
         OTHER
     };
 
@@ -270,6 +271,8 @@
         mType = AAC;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
         mType = MP3;
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+        mType = PCM;
     }
 }
 
@@ -1054,6 +1057,27 @@
                     AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
         }
 
+        if (mType == PCM) {
+            int32_t bitPerFrame = 16;
+            int32_t bigEndian = 0;
+            AMediaFormat *meta = AMediaFormat_new();
+            if (getFormat(meta) == AMEDIA_OK && meta != NULL) {
+                AMediaFormat_getInt32(meta,
+                                AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &bitPerFrame);
+                AMediaFormat_getInt32(meta,
+                                AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, &bigEndian);
+            }
+            AMediaFormat_delete(meta);
+            if (bigEndian == 1 && bitPerFrame == 16) {
+                // Big-endian -> little-endian
+                uint16_t *dstData = (uint16_t *)frame->data() + frame->range_offset();
+                uint16_t *srcData = (uint16_t *)frame->data() + frame->range_offset();
+                for (size_t i = 0; i < frame->range_length() / 2; i++) {
+                    dstData[i] = ntohs(srcData[i]);
+                }
+            }
+        }
+
         *out = frame;
 
         return AMEDIA_OK;
@@ -1170,6 +1194,51 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+enum WaveID {
+    MKV_RIFF_WAVE_FORMAT_PCM = 0x0001,
+    MKV_RIFF_WAVE_FORMAT_ADPCM_ms = 0x0002,
+    MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav = 0x0011,
+    MKV_RIFF_WAVE_FORMAT_MPEGL12 = 0x0050,
+    MKV_RIFF_WAVE_FORMAT_MPEGL3 = 0x0055,
+    MKV_RIFF_WAVE_FORMAT_WMAV1 = 0x0160,
+    MKV_RIFF_WAVE_FORMAT_WMAV2 = 0x0161,
+};
+
+static const char *MKVWave2MIME(uint16_t id) {
+    switch (id) {
+        case  MKV_RIFF_WAVE_FORMAT_MPEGL12:
+            return MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
+
+        case  MKV_RIFF_WAVE_FORMAT_MPEGL3:
+            return MEDIA_MIMETYPE_AUDIO_MPEG;
+
+        case MKV_RIFF_WAVE_FORMAT_PCM:
+            return MEDIA_MIMETYPE_AUDIO_RAW;
+
+        case MKV_RIFF_WAVE_FORMAT_ADPCM_ms:
+            return MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
+        case MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav:
+            return MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;
+
+        case MKV_RIFF_WAVE_FORMAT_WMAV1:
+        case MKV_RIFF_WAVE_FORMAT_WMAV2:
+            return MEDIA_MIMETYPE_AUDIO_WMA;
+        default:
+            ALOGW("unknown wave %x", id);
+            return "";
+    };
+}
+
+static bool isMkvAudioCsdSizeOK(const char* mime, size_t csdSize) {
+    if ((!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) && csdSize < 50) ||
+        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) && csdSize < 20) ||
+        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA) && csdSize < 28) ||
+        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) && csdSize < 30)) {
+        return false;
+    }
+    return true;
+}
+
 // trans all FOURCC  to lower char
 static uint32_t FourCCtoLower(uint32_t fourcc) {
     uint8_t ch_1 = tolower((fourcc >> 24) & 0xff);
@@ -2036,20 +2105,40 @@
                 } else if (!strcmp("A_FLAC", codecID)) {
                     AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
                     err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("A_MPEG/L2", codecID)) {
+                    AMediaFormat_setString(meta,
+                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+                } else if (!strcmp("A_PCM/INT/LIT", codecID) ||
+                         !strcmp("A_PCM/INT/BIG", codecID)) {
+                    AMediaFormat_setString(meta,
+                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+                    int32_t bigEndian = !strcmp("A_PCM/INT/BIG", codecID) ? 1: 0;
+                    AMediaFormat_setInt32(meta,
+                            AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, bigEndian);
                 } else if ((!strcmp("A_MS/ACM", codecID))) {
-                    if ((NULL == codecPrivate) || (codecPrivateSize < 30)) {
+                    if ((NULL == codecPrivate) || (codecPrivateSize < 18)) {
                         ALOGW("unsupported audio: A_MS/ACM has no valid private data: %s, size: %zu",
                                codecPrivate == NULL ? "null" : "non-null", codecPrivateSize);
                         continue;
                     } else {
                         uint16_t ID = *(uint16_t *)codecPrivate;
-                        if (ID == 0x0055) {
-                            AMediaFormat_setString(meta,
-                                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
+                        const char* mime = MKVWave2MIME(ID);
+                        ALOGV("A_MS/ACM type is %s", mime);
+                        if (!strncasecmp("audio/", mime, 6) &&
+                                isMkvAudioCsdSizeOK(mime, codecPrivateSize)) {
+                            AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, mime);
                         } else {
-                            ALOGW("A_MS/ACM unsupported type , continue");
+                            ALOGE("A_MS/ACM continue, unsupported audio type=%s, csdSize:%zu",
+                                mime, codecPrivateSize);
                             continue;
                         }
+                        if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA)) {
+                            addESDSFromCodecPrivate(meta, true, codecPrivate, codecPrivateSize);
+                        } else if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) ||
+                                    !strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM)) {
+                            uint32_t blockAlign = *(uint16_t*)(codecPrivate + 12);
+                            addESDSFromCodecPrivate(meta, true, &blockAlign, sizeof(blockAlign));
+                        }
                     }
                 } else {
                     ALOGW("%s is not supported.", codecID);
@@ -2058,6 +2147,7 @@
 
                 AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, atrack->GetSamplingRate());
                 AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, atrack->GetChannels());
+                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, atrack->GetBitDepth());
                 break;
             }
 
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 020951b..8b539c2ff 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -461,7 +461,7 @@
     }
 
     // maxBytesToRead may be reduced so that in-place data conversion will fit in buffer size.
-    const size_t bufferSize = buffer->size();
+    const size_t bufferSize = std::min(buffer->size(), kMaxFrameSize);
     size_t maxBytesToRead;
     if (mOutputFloat) { // destination is float at 4 bytes per sample, source may be less.
         maxBytesToRead = (mBitsPerSample / 8) * (bufferSize / 4);
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index dd620e3..7b0d31f 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -97,8 +97,7 @@
                 status_t status = binder->linkToDeath(mAAudioClient);
                 // TODO review what we should do if this fails
                 if (status != NO_ERROR) {
-                    ALOGE("getAAudioService: linkToDeath(mAAudioClient = %p) returned %d",
-                          mAAudioClient.get(), status);
+                    ALOGE("%s() - linkToDeath() returned %d", __func__, status);
                 }
                 mAAudioService = interface_cast<IAAudioService>(binder);
                 needToRegister = true;
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 67955e8..b6e8472 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -157,5 +157,4 @@
 void SharedMemoryParcelable::dump() {
     ALOGD("mFd = %d", mFd.get());
     ALOGD("mSizeInBytes = %d", mSizeInBytes);
-    ALOGD("mResolvedAddress = %p", mResolvedAddress);
 }
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index 3e43c6b..8f2c488 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -38,7 +38,7 @@
                           int32_t sinkChannelCount) {
     AudioFloatOutputPort *lastOutput = nullptr;
 
-    ALOGD("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
+    ALOGV("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
           __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount);
 
     switch (sourceFormat) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index ec270f3..db98d58 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -195,13 +195,13 @@
     if (isDataCallbackSet()) {
         mCallbackFrames = builder.getFramesPerDataCallback();
         if (mCallbackFrames > getBufferCapacity() / 2) {
-            ALOGE("%s - framesPerCallback too big = %d, capacity = %d",
+            ALOGW("%s - framesPerCallback too big = %d, capacity = %d",
                   __func__, mCallbackFrames, getBufferCapacity());
             result = AAUDIO_ERROR_OUT_OF_RANGE;
             goto error;
 
         } else if (mCallbackFrames < 0) {
-            ALOGE("%s - framesPerCallback negative", __func__);
+            ALOGW("%s - framesPerCallback negative", __func__);
             result = AAUDIO_ERROR_OUT_OF_RANGE;
             goto error;
 
@@ -225,7 +225,7 @@
 
 aaudio_result_t AudioStreamInternal::close() {
     aaudio_result_t result = AAUDIO_OK;
-    ALOGD("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
+    ALOGV("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
         // Don't close a stream while it is running.
         aaudio_stream_state_t currentState = getState();
@@ -236,7 +236,7 @@
             result = waitForStateChange(currentState, &nextState,
                                                        timeoutNanoseconds);
             if (result != AAUDIO_OK) {
-                ALOGE("%s() waitForStateChange() returned %d %s",
+                ALOGW("%s() waitForStateChange() returned %d %s",
                 __func__, result, AAudio_convertResultToText(result));
             }
         }
@@ -283,17 +283,17 @@
 {
     int64_t startTime;
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("requestStart() mServiceStreamHandle invalid");
+        ALOGD("requestStart() mServiceStreamHandle invalid");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     if (isActive()) {
-        ALOGE("requestStart() already active");
+        ALOGD("requestStart() already active");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
     aaudio_stream_state_t originalState = getState();
     if (originalState == AAUDIO_STREAM_STATE_DISCONNECTED) {
-        ALOGE("requestStart() but DISCONNECTED");
+        ALOGD("requestStart() but DISCONNECTED");
         return AAUDIO_ERROR_DISCONNECTED;
     }
     setState(AAUDIO_STREAM_STATE_STARTING);
@@ -356,8 +356,8 @@
     }
 
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
-              mServiceStreamHandle);
+        ALOGW("%s() mServiceStreamHandle invalid = 0x%08X",
+              __func__, mServiceStreamHandle);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -370,7 +370,7 @@
 
 aaudio_result_t AudioStreamInternal::registerThread() {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("registerThread() mServiceStreamHandle invalid");
+        ALOGW("%s() mServiceStreamHandle invalid", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.registerAudioThread(mServiceStreamHandle,
@@ -380,7 +380,7 @@
 
 aaudio_result_t AudioStreamInternal::unregisterThread() {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("unregisterThread() mServiceStreamHandle invalid");
+        ALOGW("%s() mServiceStreamHandle invalid", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index e1443d9..164ad2b 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -65,7 +65,7 @@
         return result;
     }
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("%s() mServiceStreamHandle invalid", __func__);
+        ALOGW("%s() mServiceStreamHandle invalid", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -77,7 +77,7 @@
 
 aaudio_result_t AudioStreamInternalPlay::requestFlush() {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("%s() mServiceStreamHandle invalid", __func__);
+        ALOGW("%s() mServiceStreamHandle invalid", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 8ae2644..44d5122 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -246,18 +246,20 @@
                                                      AAudioStream** streamPtr)
 {
     AudioStream *audioStream = nullptr;
+    aaudio_stream_id_t id = 0;
     // Please leave these logs because they are very helpful when debugging.
-    ALOGD("%s() called ----------------------------------------", __func__);
+    ALOGI("%s() called ----------------------------------------", __func__);
     AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
     aaudio_result_t result = streamBuilder->build(&audioStream);
-    ALOGD("AAudioStreamBuilder_openStream() returns %d = %s for (%p) ----------------",
-          result, AAudio_convertResultToText(result), audioStream);
     if (result == AAUDIO_OK) {
         audioStream->registerPlayerBase();
         *streamPtr = (AAudioStream*) audioStream;
+        id = audioStream->getId();
     } else {
         *streamPtr = nullptr;
     }
+    ALOGI("%s() returns %d = %s for s#%u ----------------",
+        __func__, result, AAudio_convertResultToText(result), id);
     return result;
 }
 
@@ -275,8 +277,9 @@
 {
     aaudio_result_t result = AAUDIO_ERROR_NULL;
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
-    ALOGD("%s(%p) called ---------------", __func__, stream);
     if (audioStream != nullptr) {
+        aaudio_stream_id_t id = audioStream->getId();
+        ALOGD("%s(s#%u) called ---------------", __func__, id);
         result = audioStream->safeClose();
         // Close will only fail if called illegally, for example, from a callback.
         // That would result in deleting an active stream, which would cause a crash.
@@ -286,42 +289,39 @@
         } else {
             ALOGW("%s attempt to close failed. Close it from another thread.", __func__);
         }
+        ALOGD("%s(s#%u) returned %d ---------", __func__, id, result);
     }
-    // We're potentially freeing `stream` above, so its use here makes some
-    // static analysis tools unhappy. Casting to uintptr_t helps assure
-    // said tools that we're not doing anything bad here.
-    ALOGD("%s(%#" PRIxPTR ") returned %d ---------", __func__,
-          reinterpret_cast<uintptr_t>(stream), result);
     return result;
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
-    ALOGD("%s(%p) called --------------", __func__, stream);
+    aaudio_stream_id_t id = audioStream->getId();
+    ALOGD("%s(s#%u) called --------------", __func__, id);
     aaudio_result_t result = audioStream->systemStart();
-    ALOGD("%s(%p) returned %d ---------", __func__, stream, result);
+    ALOGD("%s(s#%u) returned %d ---------", __func__, id, result);
     return result;
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
-    ALOGD("%s(%p) called", __func__, stream);
+    ALOGD("%s(s#%u) called", __func__, audioStream->getId());
     return audioStream->systemPause();
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
-    ALOGD("%s(%p) called", __func__, stream);
+    ALOGD("%s(s#%u) called", __func__, audioStream->getId());
     return audioStream->safeFlush();
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
-    ALOGD("%s(%p) called", __func__, stream);
+    ALOGD("%s(s#%u) called", __func__, audioStream->getId());
     return audioStream->systemStopFromApp();
 }
 
@@ -371,7 +371,7 @@
 
     // Don't allow writes when playing with a callback.
     if (audioStream->isDataCallbackActive()) {
-        ALOGE("Cannot write to a callback stream when running.");
+        ALOGD("Cannot write to a callback stream when running.");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index e5bda30..c9711da 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -56,7 +56,7 @@
         case AUDIO_FORMAT_PCM_FLOAT:
             break; // valid
         default:
-            ALOGE("audioFormat not valid, audio_format_t = 0x%08x", format);
+            ALOGD("audioFormat not valid, audio_format_t = 0x%08x", format);
             return AAUDIO_ERROR_INVALID_FORMAT;
             // break;
     }
@@ -66,12 +66,12 @@
 aaudio_result_t AAudioStreamParameters::validate() const {
     if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
         && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
-        ALOGE("channelCount out of range = %d", mSamplesPerFrame);
+        ALOGD("channelCount out of range = %d", mSamplesPerFrame);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
     if (mDeviceId < 0) {
-        ALOGE("deviceId out of range = %d", mDeviceId);
+        ALOGD("deviceId out of range = %d", mDeviceId);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
@@ -89,7 +89,7 @@
         case AAUDIO_SHARING_MODE_SHARED:
             break;
         default:
-            ALOGE("illegal sharingMode = %d", mSharingMode);
+            ALOGD("illegal sharingMode = %d", mSharingMode);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -99,12 +99,12 @@
 
     if (mSampleRate != AAUDIO_UNSPECIFIED
         && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
-        ALOGE("sampleRate out of range = %d", mSampleRate);
+        ALOGD("sampleRate out of range = %d", mSampleRate);
         return AAUDIO_ERROR_INVALID_RATE;
     }
 
     if (mBufferCapacity < 0) {
-        ALOGE("bufferCapacity out of range = %d", mBufferCapacity);
+        ALOGD("bufferCapacity out of range = %d", mBufferCapacity);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
@@ -113,7 +113,7 @@
         case AAUDIO_DIRECTION_OUTPUT:
             break; // valid
         default:
-            ALOGE("direction not valid = %d", mDirection);
+            ALOGD("direction not valid = %d", mDirection);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -134,7 +134,7 @@
         case AAUDIO_USAGE_ASSISTANT:
             break; // valid
         default:
-            ALOGE("usage not valid = %d", mUsage);
+            ALOGD("usage not valid = %d", mUsage);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -147,7 +147,7 @@
         case AAUDIO_CONTENT_TYPE_SPEECH:
             break; // valid
         default:
-            ALOGE("content type not valid = %d", mContentType);
+            ALOGD("content type not valid = %d", mContentType);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -162,7 +162,7 @@
         case AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE:
             break; // valid
         default:
-            ALOGE("input preset not valid = %d", mInputPreset);
+            ALOGD("input preset not valid = %d", mInputPreset);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -174,7 +174,7 @@
         case AAUDIO_ALLOW_CAPTURE_BY_NONE:
             break; // valid
         default:
-            ALOGE("allowed capture policy not valid = %d", mAllowedCapturePolicy);
+            ALOGD("allowed capture policy not valid = %d", mAllowedCapturePolicy);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 732d45c..25669be 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -28,9 +28,17 @@
 
 using namespace aaudio;
 
+
+// Sequential number assigned to streams solely for debugging purposes.
+static aaudio_stream_id_t AAudio_getNextStreamId() {
+    static std::atomic <aaudio_stream_id_t> nextStreamId{1};
+    return nextStreamId++;
+}
+
 AudioStream::AudioStream()
         : mPlayerBase(new MyPlayerBase(this))
-{
+        , mStreamId(AAudio_getNextStreamId())
+        {
     // mThread is a pthread_t of unknown size so we need memset.
     memset(&mThread, 0, sizeof(mThread));
     setPeriodNanoseconds(0);
@@ -48,22 +56,6 @@
     mPlayerBase->clearParentReference(); // remove reference to this AudioStream
 }
 
-static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
-    const char *result;
-    switch (sharingMode) {
-        case AAUDIO_SHARING_MODE_EXCLUSIVE:
-            result = "EX";
-            break;
-        case AAUDIO_SHARING_MODE_SHARED:
-            result = "SH";
-            break;
-        default:
-            result = "?!";
-            break;
-    }
-    return result;
-}
-
 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
 {
     // Call here as well because the AAudioService will call this without calling build().
@@ -106,20 +98,6 @@
     mDataCallbackUserData = builder.getDataCallbackUserData();
     mErrorCallbackUserData = builder.getErrorCallbackUserData();
 
-    // This is very helpful for debugging in the future. Please leave it in.
-    ALOGI("open() rate   = %d, channels    = %d, format   = %d, sharing = %s, dir = %s",
-          mSampleRate, mSamplesPerFrame, mFormat,
-          AudioStream_convertSharingModeToShortText(mSharingMode),
-          (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
-    ALOGI("open() device = %d, sessionId   = %d, perfMode = %d, callback: %s with frames = %d",
-          mDeviceId,
-          mSessionId,
-          mPerformanceMode,
-          (isDataCallbackSet() ? "ON" : "OFF"),
-          mFramesPerDataCallback);
-    ALOGI("open() usage  = %d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
-          mUsage, mContentType, mInputPreset, mAllowedCapturePolicy);
-
     return AAUDIO_OK;
 }
 
@@ -278,15 +256,15 @@
 }
 
 void AudioStream::setState(aaudio_stream_state_t state) {
-    ALOGV("%s(%p) from %d to %d", __func__, this, mState, state);
+    ALOGV("%s(%d) from %d to %d", __func__, getId(), mState, state);
     // CLOSED is a final state
     if (mState == AAUDIO_STREAM_STATE_CLOSED) {
-        ALOGE("%s(%p) tried to set to %d but already CLOSED", __func__, this, state);
+        ALOGE("%s(%d) tried to set to %d but already CLOSED", __func__, getId(), state);
 
     // Once DISCONNECTED, we can only move to CLOSED state.
     } else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
                && state != AAUDIO_STREAM_STATE_CLOSED) {
-        ALOGE("%s(%p) tried to set to %d but already DISCONNECTED", __func__, this, state);
+        ALOGE("%s(%d) tried to set to %d but already DISCONNECTED", __func__, getId(), state);
 
     } else {
         mState = state;
@@ -485,7 +463,6 @@
 }
 
 AudioStream::MyPlayerBase::~MyPlayerBase() {
-    ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this);
 }
 
 void AudioStream::MyPlayerBase::registerWithAudioManager() {
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 32713b1..044c979 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -36,6 +36,7 @@
 namespace aaudio {
 
 typedef void *(*aaudio_audio_thread_proc_t)(void *);
+typedef uint32_t aaudio_stream_id_t;
 
 class AudioStreamBuilder;
 
@@ -121,6 +122,12 @@
         return AAUDIO_OK;
     }
 
+    // This is only used to identify a stream in the logs without
+    // revealing any pointers.
+    aaudio_stream_id_t getId() {
+        return mStreamId;
+    }
+
     virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0;
 
     virtual aaudio_result_t createThread(int64_t periodNanoseconds,
@@ -587,6 +594,8 @@
     void                       *mThreadArg = nullptr;
     aaudio_result_t             mThreadRegistrationResult = AAUDIO_OK;
 
+    const aaudio_stream_id_t    mStreamId;
+
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 4ef765d..08f4958 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -104,6 +104,8 @@
     }
     *streamPtr = nullptr;
 
+    logParameters();
+
     aaudio_result_t result = validate();
     if (result != AAUDIO_OK) {
         return result;
@@ -217,3 +219,41 @@
 
     return AAUDIO_OK;
 }
+
+static const char *AAudio_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
+    switch (sharingMode) {
+        case AAUDIO_SHARING_MODE_EXCLUSIVE:
+            return "EX";
+        case AAUDIO_SHARING_MODE_SHARED:
+            return "SH";
+        default:
+            return "?!";
+    }
+}
+
+static const char *AAudio_convertDirectionToText(aaudio_direction_t direction) {
+    switch (direction) {
+        case AAUDIO_DIRECTION_OUTPUT:
+            return "OUTPUT";
+        case AAUDIO_DIRECTION_INPUT:
+            return "INPUT";
+        default:
+            return "?!";
+    }
+}
+
+void AudioStreamBuilder::logParameters() const {
+    // This is very helpful for debugging in the future. Please leave it in.
+    ALOGI("rate   = %6d, channels  = %d, format   = %d, sharing = %s, dir = %s",
+          getSampleRate(), getSamplesPerFrame(), getFormat(),
+          AAudio_convertSharingModeToShortText(getSharingMode()),
+          AAudio_convertDirectionToText(getDirection()));
+    ALOGI("device = %6d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
+          getDeviceId(),
+          getSessionId(),
+          getPerformanceMode(),
+          ((getDataCallbackProc() != nullptr) ? "ON" : "OFF"),
+          mFramesPerDataCallback);
+    ALOGI("usage  = %6d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
+          getUsage(), getContentType(), getInputPreset(), getAllowedCapturePolicy());
+}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index a43cfa8..8149af2 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -102,6 +102,8 @@
 
     virtual aaudio_result_t validate() const override;
 
+    void logParameters() const;
+
 private:
     bool                       mSharingModeMatchRequired = false; // must match sharing mode requested
     aaudio_performance_mode_t  mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 2edab58..91d2eff 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -206,7 +206,9 @@
 
 void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
 {
-    ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
+    // Device routing is a common source of errors and DISCONNECTS.
+    // Please leave this log in place.
+    ALOGD("%s() devId %d => %d", __func__, (int) getDeviceId(), (int)deviceId);
     if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
             getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
         // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index f324669..de82d2b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1067,6 +1067,13 @@
     return aps->setEffectEnabled(id, enabled);
 }
 
+status_t AudioSystem::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->moveEffectsToIo(ids, io);
+}
+
 status_t AudioSystem::isStreamActive(audio_stream_type_t stream, bool* state, uint32_t inPastMs)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 8d1f511..bd48f56 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -605,7 +605,10 @@
     mInUnderrun = false;
     mPreviousTimestampValid = false;
     mTimestampStartupGlitchReported = false;
-    mRetrogradeMotionReported = false;
+    mTimestampRetrogradePositionReported = false;
+    mTimestampRetrogradeTimeReported = false;
+    mTimestampStallReported = false;
+    mTimestampStaleTimeReported = false;
     mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
     mStartTs.mPosition = 0;
     mUnderrunCountOffset = 0;
@@ -656,7 +659,10 @@
         mPosition = 0;
         mPreviousTimestampValid = false;
         mTimestampStartupGlitchReported = false;
-        mRetrogradeMotionReported = false;
+        mTimestampRetrogradePositionReported = false;
+        mTimestampRetrogradeTimeReported = false;
+        mTimestampStallReported = false;
+        mTimestampStaleTimeReported = false;
         mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
 
         if (!isOffloadedOrDirect_l()
@@ -2607,9 +2613,14 @@
                         // A better start time is now.  The retrograde check ensures
                         // timestamp monotonicity.
                         const int64_t nowNs = systemTime();
-                        ALOGD("%s(%d) device stall, using current time %lld",
-                                __func__, mPortId, (long long)nowNs);
+                        if (!mTimestampStallReported) {
+                            ALOGD("%s(%d): device stall time corrected using current time %lld",
+                                    __func__, mPortId, (long long)nowNs);
+                            mTimestampStallReported = true;
+                        }
                         timestamp.mTime = convertNsToTimespec(nowNs);
+                    }  else {
+                        mTimestampStallReported = false;
                     }
                 }
 
@@ -2762,12 +2773,17 @@
         const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
         const int64_t limitNs = mStartNs - lagNs;
         if (currentTimeNanos < limitNs) {
-            ALOGD("%s(%d): correcting timestamp time for pause, "
-                    "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
-                    __func__, mPortId,
-                    (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
+            if (!mTimestampStaleTimeReported) {
+                ALOGD("%s(%d): stale timestamp time corrected, "
+                        "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
+                        __func__, mPortId,
+                        (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
+                mTimestampStaleTimeReported = true;
+            }
             timestamp.mTime = convertNsToTimespec(limitNs);
             currentTimeNanos = limitNs;
+        } else {
+            mTimestampStaleTimeReported = false;
         }
 
         // previousTimestampValid is set to false when starting after a stop or flush.
@@ -2777,11 +2793,15 @@
 
             // retrograde check
             if (currentTimeNanos < previousTimeNanos) {
-                ALOGW("%s(%d): retrograde timestamp time corrected, %lld < %lld",
-                        __func__, mPortId,
-                        (long long)currentTimeNanos, (long long)previousTimeNanos);
+                if (!mTimestampRetrogradeTimeReported) {
+                    ALOGW("%s(%d): retrograde timestamp time corrected, %lld < %lld",
+                            __func__, mPortId,
+                            (long long)currentTimeNanos, (long long)previousTimeNanos);
+                    mTimestampRetrogradeTimeReported = true;
+                }
                 timestamp.mTime = mPreviousTimestamp.mTime;
-                // currentTimeNanos not used below.
+            } else {
+                mTimestampRetrogradeTimeReported = false;
             }
 
             // Looking at signed delta will work even when the timestamps
@@ -2790,16 +2810,16 @@
                     - mPreviousTimestamp.mPosition).signedValue();
             if (deltaPosition < 0) {
                 // Only report once per position instead of spamming the log.
-                if (!mRetrogradeMotionReported) {
+                if (!mTimestampRetrogradePositionReported) {
                     ALOGW("%s(%d): retrograde timestamp position corrected, %d = %u - %u",
                             __func__, mPortId,
                             deltaPosition,
                             timestamp.mPosition,
                             mPreviousTimestamp.mPosition);
-                    mRetrogradeMotionReported = true;
+                    mTimestampRetrogradePositionReported = true;
                 }
             } else {
-                mRetrogradeMotionReported = false;
+                mTimestampRetrogradePositionReported = false;
             }
             if (deltaPosition < 0) {
                 timestamp.mPosition = mPreviousTimestamp.mPosition;
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index c997cfa..ee6c335 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -20,30 +20,13 @@
 #include <android-base/macros.h>
 #include <private/media/AudioTrackShared.h>
 #include <utils/Log.h>
+#include <audio_utils/safe_math.h>
 
 #include <linux/futex.h>
 #include <sys/syscall.h>
 
 namespace android {
 
-// TODO: consider pulling this into a shared header.
-// safe_sub_overflow is used ensure that subtraction occurs in the same native type
-// with proper 2's complement overflow.  Without calling this function, it is possible,
-// for example, that optimizing compilers may elect to treat 32 bit subtraction
-// as 64 bit subtraction when storing into a 64 bit destination as integer overflow is
-// technically undefined.
-template<typename T,
-         typename U,
-         typename = std::enable_if_t<std::is_same<std::decay_t<T>,
-                                       std::decay_t<U>>{}>>
-         // ensure arguments are same type (ignoring volatile, which is used in cblk variables).
-auto safe_sub_overflow(const T& a, const U& b) {
-    std::decay_t<T> result;
-    (void)__builtin_sub_overflow(a, b, &result);
-    // note if __builtin_sub_overflow returns true, an overflow occurred.
-    return result;
-}
-
 // used to clamp a value to size_t.  TODO: move to another file.
 template <typename T>
 size_t clampToSize(T x) {
@@ -204,7 +187,7 @@
             front = cblk->u.mStreaming.mFront;
         }
         // write to rear, read from front
-        ssize_t filled = safe_sub_overflow(rear, front);
+        ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
         // pipe should not be overfull
         if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
             if (mIsOut) {
@@ -702,7 +685,7 @@
         const size_t overflowBit = mFrameCountP2 << 1;
         const size_t mask = overflowBit - 1;
         int32_t newFront = (front & ~mask) | (flush & mask);
-        ssize_t filled = safe_sub_overflow(rear, newFront);
+        ssize_t filled = audio_utils::safe_sub_overflow(rear, newFront);
         if (filled >= (ssize_t)overflowBit) {
             // front and rear offsets span the overflow bit of the p2 mask
             // so rebasing newFront on the front offset is off by the overflow bit.
@@ -744,7 +727,7 @@
         const size_t overflowBit = mFrameCountP2 << 1;
         const size_t mask = overflowBit - 1;
         int32_t newRear = (rear & ~mask) | (stop & mask);
-        ssize_t filled = safe_sub_overflow(newRear, front);
+        ssize_t filled = audio_utils::safe_sub_overflow(newRear, front);
         // overflowBit is unsigned, so cast to signed for comparison.
         if (filled >= (ssize_t)overflowBit) {
             // front and rear offsets span the overflow bit of the p2 mask
@@ -796,7 +779,7 @@
         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
         rear = cblk->u.mStreaming.mRear;
     }
-    ssize_t filled = safe_sub_overflow(rear, front);
+    ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
     // pipe should not already be overfull
     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
         ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -923,7 +906,7 @@
         return mFrameCount;
     }
     const int32_t rear = getRear();
-    ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
+    ssize_t filled = audio_utils::safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
     // pipe should not already be overfull
     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
         ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -949,7 +932,7 @@
         return mFrameCount;
     }
     const int32_t rear = getRear();
-    const ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
+    const ssize_t filled = audio_utils::safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
         return 0; // error condition, silently return 0.
     }
@@ -1259,7 +1242,7 @@
     }
     const int32_t front = android_atomic_acquire_load(&mCblk->u.mStreaming.mFront);
     const int32_t rear = mCblk->u.mStreaming.mRear;
-    const ssize_t filled = safe_sub_overflow(rear, front);
+    const ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
         return 0; // error condition, silently return 0.
     }
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 825cd4e..dd95e34 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -89,6 +89,7 @@
     GET_MICROPHONES,
     SET_MASTER_BALANCE,
     GET_MASTER_BALANCE,
+    SET_EFFECT_SUSPENDED,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -718,6 +719,18 @@
         return reply.readInt32();
     }
 
+    virtual void setEffectSuspended(int effectId,
+                                    audio_session_t sessionId,
+                                    bool suspended)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(effectId);
+        data.writeInt32(sessionId);
+        data.writeInt32(suspended ? 1 : 0);
+        remote()->transact(SET_EFFECT_SUSPENDED, data, &reply);
+    }
+
     virtual audio_module_handle_t loadHwModule(const char *name)
     {
         Parcel data, reply;
@@ -913,6 +926,7 @@
         case INVALIDATE_STREAM:
         case SET_VOICE_VOLUME:
         case MOVE_EFFECTS:
+        case SET_EFFECT_SUSPENDED:
         case LOAD_HW_MODULE:
         case LIST_AUDIO_PORTS:
         case GET_AUDIO_PORT:
@@ -926,6 +940,7 @@
             // return status only for non void methods
             switch (code) {
                 case SET_RECORD_SILENCED:
+                case SET_EFFECT_SUSPENDED:
                     break;
                 default:
                     reply->writeInt32(static_cast<int32_t> (INVALID_OPERATION));
@@ -1371,6 +1386,14 @@
             reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
             return NO_ERROR;
         } break;
+        case SET_EFFECT_SUSPENDED: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int effectId = data.readInt32();
+            audio_session_t sessionId = (audio_session_t) data.readInt32();
+            bool suspended = data.readInt32() == 1;
+            setEffectSuspended(effectId, sessionId, suspended);
+            return NO_ERROR;
+        } break;
         case LOAD_HW_MODULE: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32(loadHwModule(data.readCString()));
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index bf98c60..4a8bb52 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -103,6 +103,7 @@
     LIST_AUDIO_VOLUME_GROUPS,
     GET_VOLUME_GROUP_FOR_ATTRIBUTES,
     SET_ALLOWED_CAPTURE_POLICY,
+    MOVE_EFFECTS_TO_IO,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -550,6 +551,22 @@
         return static_cast <status_t> (reply.readInt32());
     }
 
+    status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(ids.size());
+        for (auto id : ids) {
+            data.writeInt32(id);
+        }
+        data.writeInt32(io);
+        status_t status = remote()->transact(MOVE_EFFECTS_TO_IO, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast <status_t> (reply.readInt32());
+    }
+
     virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
     {
         Parcel data, reply;
@@ -1284,6 +1301,7 @@
         case GET_OUTPUT_FOR_ATTR:
         case ACQUIRE_SOUNDTRIGGER_SESSION:
         case RELEASE_SOUNDTRIGGER_SESSION:
+        case MOVE_EFFECTS_TO_IO:
             ALOGW("%s: transaction %d received from PID %d",
                   __func__, code, IPCThreadState::self()->getCallingPid());
             // return status only for non void methods
@@ -1700,6 +1718,31 @@
             return NO_ERROR;
         } break;
 
+        case MOVE_EFFECTS_TO_IO: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            std::vector<int> ids;
+            int32_t size;
+            status_t status = data.readInt32(&size);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            if (size > MAX_ITEMS_PER_LIST) {
+                return BAD_VALUE;
+            }
+            for (int32_t i = 0; i < size; i++) {
+                int id;
+                status =  data.readInt32(&id);
+                if (status != NO_ERROR) {
+                    return status;
+                }
+                ids.push_back(id);
+            }
+
+            audio_io_handle_t io = data.readInt32();
+            reply->writeInt32(static_cast <int32_t>(moveEffectsToIo(ids, io)));
+            return NO_ERROR;
+        } break;
+
         case IS_STREAM_ACTIVE: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 05a1d56..d180bbc 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -286,6 +286,7 @@
                                     int id);
     static status_t unregisterEffect(int id);
     static status_t setEffectEnabled(int id, bool enabled);
+    static status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io);
 
     // clear stream to output mapping cache (gStreamOutputMap)
     // and output configuration cache (gOutputs)
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 3926ead..df5eabc 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1151,8 +1151,11 @@
                                                     // AudioTracks.
 
     bool                    mPreviousTimestampValid;// true if mPreviousTimestamp is valid
-    bool                    mTimestampStartupGlitchReported; // reduce log spam
-    bool                    mRetrogradeMotionReported; // reduce log spam
+    bool                    mTimestampStartupGlitchReported;      // reduce log spam
+    bool                    mTimestampRetrogradePositionReported; // reduce log spam
+    bool                    mTimestampRetrogradeTimeReported;     // reduce log spam
+    bool                    mTimestampStallReported;              // reduce log spam
+    bool                    mTimestampStaleTimeReported;          // reduce log spam
     AudioTimestamp          mPreviousTimestamp;     // used to detect retrograde motion
     ExtendedTimestamp::Location mPreviousLocation;  // location used for previous timestamp
 
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index ef0ed0c..dcc18b6 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -457,6 +457,10 @@
     virtual status_t moveEffects(audio_session_t session, audio_io_handle_t srcOutput,
                                     audio_io_handle_t dstOutput) = 0;
 
+    virtual void setEffectSuspended(int effectId,
+                                    audio_session_t sessionId,
+                                    bool suspended) = 0;
+
     virtual audio_module_handle_t loadHwModule(const char *name) = 0;
 
     // helpers for android.media.AudioManager.getProperty(), see description there for meaning
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 95530ac..11983d5 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -114,6 +114,7 @@
                                     int id) = 0;
     virtual status_t unregisterEffect(int id) = 0;
     virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+    virtual status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) = 0;
     virtual bool     isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const = 0;
     virtual bool     isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0)
                              const = 0;
diff --git a/media/libaudioprocessing/RecordBufferConverter.cpp b/media/libaudioprocessing/RecordBufferConverter.cpp
index 54151f5..7d6fe72 100644
--- a/media/libaudioprocessing/RecordBufferConverter.cpp
+++ b/media/libaudioprocessing/RecordBufferConverter.cpp
@@ -117,6 +117,11 @@
         // format convert to destination buffer
         convertResampler(dst, mBuf, frames);
     }
+    // Release unused frames in the InputConverterProvider buffer so that
+    // the RecordThread is able to properly account for consumed frames.
+    if (mInputConverterProvider != nullptr) {
+        mInputConverterProvider->reset();
+    }
     return frames;
 }
 
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
index 37272e3..bdca5e3 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
@@ -1128,6 +1128,11 @@
     LVM_Instance_t      *pInstance  = (LVM_Instance_t  *)hInstance;
 #ifdef SUPPORT_MC
     LVM_INT16           NumChannels = pInstance->NrChannels;
+    if (NumChannels == 1)
+    {
+        /* Mono input is processed as stereo by LVM module */
+        NumChannels = 2;
+    }
 #undef NrFrames
 #define NrFrames (*pNumSamples) // alias for clarity
 #else
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
index 8d30a61..bc666a9 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
@@ -230,9 +230,15 @@
              */
             if (pToProcess != pProcessed)
             {
+#ifdef SUPPORT_MC
+                Copy_Float(pToProcess,                             /* Source */
+                           pProcessed,                             /* Destination */
+                           (LVM_INT16)(NrChannels * NrFrames));    /* Copy all samples */
+#else
                 Copy_Float(pToProcess,                             /* Source */
                            pProcessed,                             /* Destination */
                            (LVM_INT16)(2 * SampleCount));          /* Left and right */
+#endif
             }
 
             /*
diff --git a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
index 5079634..a97acc9 100755
--- a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
+++ b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
@@ -24,9 +24,32 @@
 echo "testing lvm"
 adb shell mkdir -p $testdir
 adb push $ANDROID_BUILD_TOP/cts/tests/tests/media/res/raw/sinesweepraw.raw $testdir
-adb push $OUT/testcases/lvmtest/arm64/lvmtest $testdir
 adb push $OUT/testcases/snr/arm64/snr $testdir
 
+E_VAL=1
+if [ -z "$1" ]
+then
+    cmds=("adb push $OUT/testcases/lvmtest/arm64/lvmtest $testdir"
+          "adb push $OUT/testcases/lvmtest/arm/lvmtest $testdir"
+         )
+elif [ "$1" == "32" ]
+then
+    cmds="adb push $OUT/testcases/lvmtest/arm/lvmtest $testdir"
+elif [ "$1" == "64" ]
+then
+    cmds="adb push $OUT/testcases/lvmtest/arm64/lvmtest $testdir"
+else
+    echo ""
+    echo "Invalid \"val\""
+    echo "Usage:"
+    echo "      "$0" [val]"
+    echo "      where, val can be either 32 or 64."
+    echo ""
+    echo "      If val is not specified then both 32 bit and 64 bit binaries"
+    echo "      are tested."
+    exit $E_VAL
+fi
+
 flags_arr=(
     "-csE"
     "-eqE"
@@ -61,42 +84,45 @@
 # run multichannel effects at different configs, saving only the stereo channel
 # pair.
 error_count=0
-for flags in "${flags_arr[@]}"
+for cmd in "${cmds[@]}"
 do
-    for fs in ${fs_arr[*]}
+    $cmd
+    for flags in "${flags_arr[@]}"
     do
-        for chMask in {0..22}
+        for fs in ${fs_arr[*]}
         do
-            adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw \
-                -o:$testdir/sinesweep_$((chMask))_$((fs)).raw -chMask:$chMask -fs:$fs $flags
+            for chMask in {0..22}
+            do
+                adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw \
+                    -o:$testdir/sinesweep_$((chMask))_$((fs)).raw -chMask:$chMask -fs:$fs $flags
 
-            shell_ret=$?
-            if [ $shell_ret -ne 0 ]; then
-                echo "error: $shell_ret"
-                ((++error_count))
-            fi
+                shell_ret=$?
+                if [ $shell_ret -ne 0 ]; then
+                    echo "error: $shell_ret"
+                    ((++error_count))
+                fi
 
 
-            # two channel files should be identical to higher channel
-            # computation (first 2 channels).
-            # Do not compare cases where -bE is in flags (due to mono computation)
-            if [[ $flags != *"-bE"* ]] && [[ "$chMask" -gt 1 ]]
-            then
-                adb shell cmp $testdir/sinesweep_1_$((fs)).raw \
-                    $testdir/sinesweep_$((chMask))_$((fs)).raw
-            elif [[ $flags == *"-bE"* ]] && [[ "$chMask" -gt 1 ]]
-            then
-                adb shell $testdir/snr $testdir/sinesweep_1_$((fs)).raw \
-                    $testdir/sinesweep_$((chMask))_$((fs)).raw -thr:90.308998
-            fi
+                # two channel files should be identical to higher channel
+                # computation (first 2 channels).
+                # Do not compare cases where -bE is in flags (due to mono computation)
+                if [[ $flags != *"-bE"* ]] && [[ "$chMask" -gt 1 ]]
+                then
+                    adb shell cmp $testdir/sinesweep_1_$((fs)).raw \
+                        $testdir/sinesweep_$((chMask))_$((fs)).raw
+                elif [[ $flags == *"-bE"* ]] && [[ "$chMask" -gt 1 ]]
+                then
+                    adb shell $testdir/snr $testdir/sinesweep_1_$((fs)).raw \
+                        $testdir/sinesweep_$((chMask))_$((fs)).raw -thr:90.308998
+                fi
 
-            # both cmp and snr return EXIT_FAILURE on mismatch.
-            shell_ret=$?
-            if [ $shell_ret -ne 0 ]; then
-                echo "error: $shell_ret"
-                ((++error_count))
-            fi
-
+                # both cmp and snr return EXIT_FAILURE on mismatch.
+                shell_ret=$?
+                if [ $shell_ret -ne 0 ]; then
+                    echo "error: $shell_ret"
+                    ((++error_count))
+                fi
+            done
         done
     done
 done
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 3a97905..3fbbc09 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -650,6 +650,9 @@
     params.SpeakerType            = LVM_HEADPHONES;
 
     pContext->pBundledContext->SampleRate = LVM_FS_44100;
+#ifdef SUPPORT_MC
+    pContext->pBundledContext->ChMask = AUDIO_CHANNEL_OUT_STEREO;
+#endif
 
     /* Concert Sound parameters */
     params.VirtualizerOperatingMode   = LVM_MODE_OFF;
@@ -695,6 +698,11 @@
     params.TE_OperatingMode       = LVM_TE_OFF;
     params.TE_EffectLevel         = 0;
 
+#ifdef SUPPORT_MC
+    params.NrChannels             =
+        audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
+    params.ChMask                 = AUDIO_CHANNEL_OUT_STEREO;
+#endif
     /* Activate the initial settings */
     LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance,
                                          &params);
@@ -1297,7 +1305,12 @@
         return -EINVAL;
     }
 
+#ifdef SUPPORT_MC
+    if (pContext->pBundledContext->SampleRate != SampleRate ||
+        pContext->pBundledContext->ChMask != pConfig->inputCfg.channels) {
+#else
     if(pContext->pBundledContext->SampleRate != SampleRate){
+#endif
 
         LVM_ControlParams_t     ActiveParams;
         LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;
@@ -1323,6 +1336,9 @@
         LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_setConfig")
         ALOGV("\tEffect_setConfig Succesfully called LVM_SetControlParameters\n");
         pContext->pBundledContext->SampleRate = SampleRate;
+#ifdef SUPPORT_MC
+        pContext->pBundledContext->ChMask = pConfig->inputCfg.channels;
+#endif
 
         LvmEffect_limitLevel(pContext);
 
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 6bf045d..6af4554 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -107,6 +107,9 @@
     LVM_FLOAT                       *pInputBuffer;
     LVM_FLOAT                       *pOutputBuffer;
 #endif
+#ifdef SUPPORT_MC
+    LVM_INT32                       ChMask;
+#endif
 };
 
 /* SessionContext : One session */
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 50c33c6..5fab5be 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -926,7 +926,7 @@
         delete session->revBuf;
         session->revBuf = NULL;
 
-        session->io = 0;
+        session->id = 0;
     }
 
     return 0;
@@ -1155,7 +1155,7 @@
 {
     size_t i;
     for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
-        if (sSessions[i].io == ioId) {
+        if (sSessions[i].id == sessionId) {
             if (sSessions[i].createdMsk & (1 << procId)) {
                 return NULL;
             }
@@ -1163,7 +1163,7 @@
         }
     }
     for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
-        if (sSessions[i].io == 0) {
+        if (sSessions[i].id == 0) {
             sSessions[i].id = sessionId;
             sSessions[i].io = ioId;
             return &sSessions[i];
@@ -1915,7 +1915,7 @@
     status = Session_CreateEffect(session, procId, pInterface);
 
     if (status < 0 && session->createdMsk == 0) {
-        session->io = 0;
+        session->id = 0;
     }
     return status;
 }
@@ -1929,7 +1929,7 @@
 
     preproc_effect_t *fx = (preproc_effect_t *)interface;
 
-    if (fx->session->io == 0) {
+    if (fx->session->id == 0) {
         return -EINVAL;
     }
     return Session_ReleaseEffect(fx->session, fx);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 0776172..6709585 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -2,6 +2,7 @@
 
     srcs: [
         "ActivityManager.cpp",
+        "DeathNotifier.cpp",
         "MediaPlayerFactory.cpp",
         "MediaPlayerService.cpp",
         "MediaRecorderClient.cpp",
@@ -17,6 +18,7 @@
         "libaudioclient",
         "libbinder",
         "libcamera_client",
+        "libcodec2_client",
         "libcrypto",
         "libcutils",
         "libdl",
diff --git a/media/libmediaplayerservice/DeathNotifier.cpp b/media/libmediaplayerservice/DeathNotifier.cpp
new file mode 100644
index 0000000..d13bdf5
--- /dev/null
+++ b/media/libmediaplayerservice/DeathNotifier.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaPlayerService-DeathNotifier"
+#include <android-base/logging.h>
+
+#include "DeathNotifier.h"
+
+namespace android {
+
+class DeathNotifier::DeathRecipient :
+        public IBinder::DeathRecipient,
+        public hardware::hidl_death_recipient {
+public:
+    using Notify = DeathNotifier::Notify;
+
+    DeathRecipient(Notify const& notify): mNotify{notify} {
+    }
+
+    virtual void binderDied(wp<IBinder> const&) override {
+        mNotify();
+    }
+
+    virtual void serviceDied(uint64_t, wp<HBase> const&) override {
+        mNotify();
+    }
+
+private:
+    Notify mNotify;
+};
+
+DeathNotifier::DeathNotifier(sp<IBinder> const& service, Notify const& notify)
+      : mService{std::in_place_index<1>, service},
+        mDeathRecipient{new DeathRecipient(notify)} {
+    service->linkToDeath(mDeathRecipient);
+}
+
+DeathNotifier::DeathNotifier(sp<HBase> const& service, Notify const& notify)
+      : mService{std::in_place_index<2>, service},
+        mDeathRecipient{new DeathRecipient(notify)} {
+    service->linkToDeath(mDeathRecipient, 0);
+}
+
+DeathNotifier::DeathNotifier(DeathNotifier&& other)
+      : mService{other.mService}, mDeathRecipient{other.mDeathRecipient} {
+    other.mService.emplace<0>();
+    other.mDeathRecipient = nullptr;
+}
+
+DeathNotifier::~DeathNotifier() {
+    switch (mService.index()) {
+    case 0:
+        break;
+    case 1:
+        std::get<1>(mService)->unlinkToDeath(mDeathRecipient);
+        break;
+    case 2:
+        std::get<2>(mService)->unlinkToDeath(mDeathRecipient);
+        break;
+    default:
+        CHECK(false) << "Corrupted service type during destruction.";
+    }
+}
+
+} // namespace android
+
diff --git a/media/libmediaplayerservice/DeathNotifier.h b/media/libmediaplayerservice/DeathNotifier.h
new file mode 100644
index 0000000..7bc2611
--- /dev/null
+++ b/media/libmediaplayerservice/DeathNotifier.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIASERVICE_DEATHNOTIFIER_H
+#define ANDROID_MEDIASERVICE_DEATHNOTIFIER_H
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <binder/Binder.h>
+#include <hidl/HidlSupport.h>
+
+#include <variant>
+
+namespace android {
+
+class DeathNotifier {
+public:
+    using HBase = hidl::base::V1_0::IBase;
+    using Notify = std::function<void()>;
+
+    DeathNotifier(sp<IBinder> const& service, Notify const& notify);
+    DeathNotifier(sp<HBase> const& service, Notify const& notify);
+    DeathNotifier(DeathNotifier&& other);
+    ~DeathNotifier();
+
+private:
+    std::variant<std::monostate, sp<IBinder>, sp<HBase>> mService;
+
+    class DeathRecipient;
+    sp<DeathRecipient> mDeathRecipient;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIASERVICE_DEATHNOTIFIER_H
+
diff --git a/media/libmediaplayerservice/DeathRecipient.h b/media/libmediaplayerservice/DeathRecipient.h
new file mode 100644
index 0000000..bf5ae5c
--- /dev/null
+++ b/media/libmediaplayerservice/DeathRecipient.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIASERVICE_DEATHRECIPIENT_H
+#define ANDROID_MEDIASERVICE_DEATHRECIPIENT_H
+
+#include <binder/binder.h>
+#include <hidl/HidlSupport.h>
+
+#include <variant>
+
+class DeathNotifier :
+        public IBinder::DeathRecipient,
+        public ::android::hardware::hidl_death_recipient {
+public:
+    using Service = std::variant<
+            sp<IBinder> const&,
+            sp<android::hidl::base::V1_0::IBase> const&>;
+
+    DeathNotifier(std::variant<sp<IBinder> const&, 
+            const sp<IBinder>& service,
+            const sp<MediaPlayerBase>& listener,
+            int which,
+            const std::string& name);
+    DeathNotifier(
+            const sp<android::hidl::base::V1_0::IBase>& hService,
+            const sp<MediaPlayerBase>& listener,
+            int which,
+            const std::string& name);
+    virtual ~DeathNotifier() = default;
+    virtual void binderDied(const wp<IBinder>& who);
+    virtual void serviceDied(
+            uint64_t cookie,
+            const wp<::android::hidl::base::V1_0::IBase>& who);
+    void unlinkToDeath();
+
+private:
+    sp<IBinder> mService;
+    sp<android::hidl::base::V1_0::IBase> mHService; // HIDL service
+    wp<MediaPlayerBase> mListener;
+    int mWhich;
+    std::string mName;
+};
+
+#endif // ANDROID_MEDIASERVICE_DEATHRECIPIENT_H
+
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 5061024..dfd3933 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -34,7 +34,7 @@
 
 #include <utils/misc.h>
 
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -47,6 +47,7 @@
 #include <utils/Timers.h>
 #include <utils/Vector.h>
 
+#include <codec2/hidl/client.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IRemoteDisplay.h>
 #include <media/IRemoteDisplayClient.h>
@@ -591,7 +592,6 @@
     if (mAudioAttributes != NULL) {
         free(mAudioAttributes);
     }
-    clearDeathNotifiers_l();
     mAudioDeviceUpdatedListener.clear();
 }
 
@@ -647,59 +647,6 @@
     return p;
 }
 
-MediaPlayerService::Client::ServiceDeathNotifier::ServiceDeathNotifier(
-        const sp<IBinder>& service,
-        const sp<MediaPlayerBase>& listener,
-        int which) {
-    mService = service;
-    mHService = nullptr;
-    mListener = listener;
-    mWhich = which;
-}
-
-MediaPlayerService::Client::ServiceDeathNotifier::ServiceDeathNotifier(
-        const sp<android::hidl::base::V1_0::IBase>& hService,
-        const sp<MediaPlayerBase>& listener,
-        int which) {
-    mService = nullptr;
-    mHService = hService;
-    mListener = listener;
-    mWhich = which;
-}
-
-MediaPlayerService::Client::ServiceDeathNotifier::~ServiceDeathNotifier() {
-}
-
-void MediaPlayerService::Client::ServiceDeathNotifier::binderDied(const wp<IBinder>& /*who*/) {
-    sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, mWhich);
-    } else {
-        ALOGW("listener for process %d death is gone", mWhich);
-    }
-}
-
-void MediaPlayerService::Client::ServiceDeathNotifier::serviceDied(
-        uint64_t /* cookie */,
-        const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
-    sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, mWhich);
-    } else {
-        ALOGW("listener for process %d death is gone", mWhich);
-    }
-}
-
-void MediaPlayerService::Client::ServiceDeathNotifier::unlinkToDeath() {
-    if (mService != nullptr) {
-        mService->unlinkToDeath(this);
-        mService = nullptr;
-    } else if (mHService != nullptr) {
-        mHService->unlinkToDeath(this);
-        mHService = nullptr;
-    }
-}
-
 void MediaPlayerService::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
         audio_io_handle_t audioIo,
         audio_port_handle_t deviceId) {
@@ -711,19 +658,6 @@
     }
 }
 
-void MediaPlayerService::Client::clearDeathNotifiers_l() {
-    if (mExtractorDeathListener != nullptr) {
-        mExtractorDeathListener->unlinkToDeath();
-        mExtractorDeathListener = nullptr;
-    }
-    for (const sp<ServiceDeathNotifier>& codecDeathListener : mCodecDeathListeners) {
-        if (codecDeathListener != nullptr) {
-            codecDeathListener->unlinkToDeath();
-        }
-    }
-    mCodecDeathListeners.clear();
-}
-
 sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
         player_type playerType)
 {
@@ -735,66 +669,83 @@
         return p;
     }
 
+    std::vector<DeathNotifier> deathNotifiers;
+
+    // Listen to death of media.extractor service
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> binder = sm->getService(String16("media.extractor"));
     if (binder == NULL) {
         ALOGE("extractor service not available");
         return NULL;
     }
-    sp<ServiceDeathNotifier> extractorDeathListener =
-            new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
-    binder->linkToDeath(extractorDeathListener);
+    deathNotifiers.emplace_back(
+            binder, [l = wp<MediaPlayerBase>(p)]() {
+        sp<MediaPlayerBase> listener = l.promote();
+        if (listener) {
+            ALOGI("media.extractor died. Sending death notification.");
+            listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
+                                MEDIAEXTRACTOR_PROCESS_DEATH);
+        } else {
+            ALOGW("media.extractor died without a death handler.");
+        }
+    });
 
-    std::vector<sp<ServiceDeathNotifier>> codecDeathListeners;
     {
         using ::android::hidl::base::V1_0::IBase;
 
-        // Listen to OMX's IOmxStore/default
+        // Listen to death of OMX service
         {
-            sp<IBase> store = ::android::hardware::media::omx::V1_0::
-                    IOmxStore::getService();
-            if (store == nullptr) {
+            sp<IBase> base = ::android::hardware::media::omx::V1_0::
+                    IOmx::getService();
+            if (base == nullptr) {
                 ALOGD("OMX service is not available");
             } else {
-                sp<ServiceDeathNotifier> codecDeathListener =
-                        new ServiceDeathNotifier(store, p, MEDIACODEC_PROCESS_DEATH);
-                store->linkToDeath(codecDeathListener, 0);
-                codecDeathListeners.emplace_back(codecDeathListener);
+                deathNotifiers.emplace_back(
+                        base, [l = wp<MediaPlayerBase>(p)]() {
+                    sp<MediaPlayerBase> listener = l.promote();
+                    if (listener) {
+                        ALOGI("OMX service died. "
+                              "Sending death notification.");
+                        listener->sendEvent(
+                                MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
+                                MEDIACODEC_PROCESS_DEATH);
+                    } else {
+                        ALOGW("OMX service died without a death handler.");
+                    }
+                });
             }
         }
 
-        // Listen to Codec2's IComponentStore/software
-        // TODO: Listen to all Codec2 services.
+        // Listen to death of Codec2 services
         {
-            sp<IBase> store = ::android::hardware::media::c2::V1_0::
-                    IComponentStore::getService();
-            if (store == nullptr) {
-                ALOGD("Codec2 system service is not available");
-            } else {
-                sp<ServiceDeathNotifier> codecDeathListener =
-                        new ServiceDeathNotifier(store, p, MEDIACODEC_PROCESS_DEATH);
-                store->linkToDeath(codecDeathListener, 0);
-                codecDeathListeners.emplace_back(codecDeathListener);
-            }
-
-            store = ::android::hardware::media::c2::V1_0::
-                    IComponentStore::getService("software");
-            if (store == nullptr) {
-                ALOGD("Codec2 swcodec service is not available");
-            } else {
-                sp<ServiceDeathNotifier> codecDeathListener =
-                        new ServiceDeathNotifier(store, p, MEDIACODEC_PROCESS_DEATH);
-                store->linkToDeath(codecDeathListener, 0);
-                codecDeathListeners.emplace_back(codecDeathListener);
+            for (std::shared_ptr<Codec2Client> const& client :
+                    Codec2Client::CreateFromAllServices()) {
+                sp<IBase> base = client->getBase();
+                deathNotifiers.emplace_back(
+                        base, [l = wp<MediaPlayerBase>(p),
+                               name = std::string(client->getServiceName())]() {
+                    sp<MediaPlayerBase> listener = l.promote();
+                    if (listener) {
+                        ALOGI("Codec2 service \"%s\" died. "
+                              "Sending death notification.",
+                              name.c_str());
+                        listener->sendEvent(
+                                MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
+                                MEDIACODEC_PROCESS_DEATH);
+                    } else {
+                        ALOGW("Codec2 service \"%s\" died "
+                              "without a death handler.",
+                              name.c_str());
+                    }
+                });
             }
         }
     }
 
     Mutex::Autolock lock(mLock);
 
-    clearDeathNotifiers_l();
-    mExtractorDeathListener = extractorDeathListener;
-    mCodecDeathListeners.swap(codecDeathListeners);
+    mDeathNotifiers.clear();
+    mDeathNotifiers.swap(deathNotifiers);
     mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
 
     if (!p->hardwareOutput()) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 26bfa71..49688ce 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -30,8 +30,6 @@
 #include <media/Metadata.h>
 #include <media/stagefright/foundation/ABase.h>
 
-#include <hidl/HidlSupport.h>
-
 #include <system/audio.h>
 
 namespace android {
@@ -39,6 +37,7 @@
 struct AudioPlaybackRate;
 class AudioTrack;
 struct AVSyncSettings;
+class DeathNotifier;
 class IDataSource;
 class IMediaRecorder;
 class IMediaMetadataRetriever;
@@ -388,33 +387,6 @@
         virtual status_t enableAudioDeviceCallback(bool enabled);
 
     private:
-        class ServiceDeathNotifier:
-                public IBinder::DeathRecipient,
-                public ::android::hardware::hidl_death_recipient
-        {
-        public:
-            ServiceDeathNotifier(
-                    const sp<IBinder>& service,
-                    const sp<MediaPlayerBase>& listener,
-                    int which);
-            ServiceDeathNotifier(
-                    const sp<android::hidl::base::V1_0::IBase>& hService,
-                    const sp<MediaPlayerBase>& listener,
-                    int which);
-            virtual ~ServiceDeathNotifier();
-            virtual void binderDied(const wp<IBinder>& who);
-            virtual void serviceDied(
-                    uint64_t cookie,
-                    const wp<::android::hidl::base::V1_0::IBase>& who);
-            void unlinkToDeath();
-
-        private:
-            int mWhich;
-            sp<IBinder> mService;
-            sp<android::hidl::base::V1_0::IBase> mHService; // HIDL service
-            wp<MediaPlayerBase> mListener;
-        };
-
         class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
         {
         public:
@@ -430,8 +402,6 @@
             wp<MediaPlayerBase> mListener;
         };
 
-        void clearDeathNotifiers_l();
-
         friend class MediaPlayerService;
                                 Client( const sp<MediaPlayerService>& service,
                                         pid_t pid,
@@ -506,8 +476,7 @@
         // getMetadata clears this set.
         media::Metadata::Filter mMetadataUpdated;  // protected by mLock
 
-        sp<ServiceDeathNotifier> mExtractorDeathListener;
-        std::vector<sp<ServiceDeathNotifier>> mCodecDeathListeners;
+        std::vector<DeathNotifier> mDeathNotifiers;
         sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
 #if CALLBACK_ANTAGONIZER
                     Antagonizer*                  mAntagonizer;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 9f4265b..703da4b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -18,27 +18,28 @@
 #define LOG_TAG "MediaRecorderService"
 #include <utils/Log.h>
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <string.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h> // for property_get
+#include "MediaRecorderClient.h"
+#include "MediaPlayerService.h"
+#include "StagefrightRecorder.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
-
+#include <codec2/hidl/client.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h> // for property_get
+#include <gui/IGraphicBufferProducer.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <system/audio.h>
 #include <utils/String16.h>
 
-#include <system/audio.h>
-
-#include "MediaRecorderClient.h"
-#include "MediaPlayerService.h"
-
-#include "StagefrightRecorder.h"
-#include <gui/IGraphicBufferProducer.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
 
 namespace android {
 
@@ -339,7 +340,7 @@
         wp<MediaRecorderClient> client(this);
         mMediaPlayerService->removeMediaRecorderClient(client);
     }
-    clearDeathNotifiers_l();
+    mDeathNotifiers.clear();
     return NO_ERROR;
 }
 
@@ -358,59 +359,6 @@
     release();
 }
 
-MediaRecorderClient::ServiceDeathNotifier::ServiceDeathNotifier(
-        const sp<IBinder>& service,
-        const sp<IMediaRecorderClient>& listener,
-        int which) {
-    mService = service;
-    mOmx = nullptr;
-    mListener = listener;
-    mWhich = which;
-}
-
-MediaRecorderClient::ServiceDeathNotifier::ServiceDeathNotifier(
-        const sp<IOmx>& omx,
-        const sp<IMediaRecorderClient>& listener,
-        int which) {
-    mService = nullptr;
-    mOmx = omx;
-    mListener = listener;
-    mWhich = which;
-}
-
-MediaRecorderClient::ServiceDeathNotifier::~ServiceDeathNotifier() {
-}
-
-void MediaRecorderClient::ServiceDeathNotifier::binderDied(const wp<IBinder>& /*who*/) {
-    sp<IMediaRecorderClient> listener = mListener.promote();
-    if (listener != NULL) {
-        listener->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, mWhich);
-    } else {
-        ALOGW("listener for process %d death is gone", mWhich);
-    }
-}
-
-void MediaRecorderClient::ServiceDeathNotifier::serviceDied(
-        uint64_t /* cookie */,
-        const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
-    sp<IMediaRecorderClient> listener = mListener.promote();
-    if (listener != NULL) {
-        listener->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, mWhich);
-    } else {
-        ALOGW("listener for process %d death is gone", mWhich);
-    }
-}
-
-void MediaRecorderClient::ServiceDeathNotifier::unlinkToDeath() {
-    if (mService != nullptr) {
-        mService->unlinkToDeath(this);
-        mService = nullptr;
-    } else if (mOmx != nullptr) {
-        mOmx->unlinkToDeath(this);
-        mOmx = nullptr;
-    }
-}
-
 MediaRecorderClient::AudioDeviceUpdatedNotifier::AudioDeviceUpdatedNotifier(
         const sp<IMediaRecorderClient>& listener) {
     mListener = listener;
@@ -430,22 +378,11 @@
     }
 }
 
-void MediaRecorderClient::clearDeathNotifiers_l() {
-    if (mCameraDeathListener != nullptr) {
-        mCameraDeathListener->unlinkToDeath();
-        mCameraDeathListener = nullptr;
-    }
-    if (mCodecDeathListener != nullptr) {
-        mCodecDeathListener->unlinkToDeath();
-        mCodecDeathListener = nullptr;
-    }
-}
-
 status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listener)
 {
     ALOGV("setListener");
     Mutex::Autolock lock(mLock);
-    clearDeathNotifiers_l();
+    mDeathNotifiers.clear();
     if (mRecorder == NULL) {
         ALOGE("recorder is not initialized");
         return NO_INIT;
@@ -463,20 +400,73 @@
     // If the device does not have a camera, do not create a death listener for it.
     if (binder != NULL) {
         sCameraVerified = true;
-        mCameraDeathListener = new ServiceDeathNotifier(binder, listener,
-                MediaPlayerService::CAMERA_PROCESS_DEATH);
-        binder->linkToDeath(mCameraDeathListener);
+        mDeathNotifiers.emplace_back(
+                binder, [l = wp<IMediaRecorderClient>(listener)](){
+            sp<IMediaRecorderClient> listener = l.promote();
+            if (listener) {
+                ALOGV("media.camera service died. "
+                      "Sending death notification.");
+                listener->notify(
+                        MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
+                        MediaPlayerService::CAMERA_PROCESS_DEATH);
+            } else {
+                ALOGW("media.camera service died without a death handler.");
+            }
+        });
     }
     sCameraChecked = true;
 
-    sp<IOmx> omx = IOmx::getService();
-    if (omx == nullptr) {
-        ALOGE("IOmx service is not available");
-        return NO_INIT;
+    {
+        using ::android::hidl::base::V1_0::IBase;
+
+        // Listen to OMX's IOmxStore/default
+        {
+            sp<IBase> base = ::android::hardware::media::omx::V1_0::
+                    IOmx::getService();
+            if (base == nullptr) {
+                ALOGD("OMX service is not available");
+            } else {
+                mDeathNotifiers.emplace_back(
+                        base, [l = wp<IMediaRecorderClient>(listener)](){
+                    sp<IMediaRecorderClient> listener = l.promote();
+                    if (listener) {
+                        ALOGV("OMX service died. "
+                              "Sending death notification.");
+                        listener->notify(
+                                MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
+                                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+                    } else {
+                        ALOGW("OMX service died without a death handler.");
+                    }
+                });
+            }
+        }
+
+        // Listen to Codec2's IComponentStore instances
+        {
+            for (std::shared_ptr<Codec2Client> const& client :
+                    Codec2Client::CreateFromAllServices()) {
+                sp<IBase> base = client->getBase();
+                mDeathNotifiers.emplace_back(
+                        base, [l = wp<IMediaRecorderClient>(listener),
+                               name = std::string(client->getServiceName())]() {
+                    sp<IMediaRecorderClient> listener = l.promote();
+                    if (listener) {
+                        ALOGV("Codec2 service \"%s\" died. "
+                              "Sending death notification",
+                              name.c_str());
+                        listener->notify(
+                                MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
+                                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+                    } else {
+                        ALOGW("Codec2 service \"%s\" died "
+                              "without a death handler",
+                              name.c_str());
+                    }
+                });
+            }
+        }
     }
-    mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
-            MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
-    omx->linkToDeath(mCodecDeathListener, 0);
 
     mAudioDeviceUpdatedNotifier = new AudioDeviceUpdatedNotifier(listener);
     mRecorder->setAudioDeviceCallback(mAudioDeviceUpdatedNotifier);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index e698819..9e0f877 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -18,10 +18,12 @@
 #ifndef ANDROID_MEDIARECORDERCLIENT_H
 #define ANDROID_MEDIARECORDERCLIENT_H
 
+#include "DeathNotifier.h"
+
 #include <media/AudioSystem.h>
 #include <media/IMediaRecorder.h>
 
-#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <vector>
 
 namespace android {
 
@@ -31,34 +33,6 @@
 
 class MediaRecorderClient : public BnMediaRecorder
 {
-    typedef ::android::hardware::media::omx::V1_0::IOmx IOmx;
-
-    class ServiceDeathNotifier :
-            public IBinder::DeathRecipient,
-            public ::android::hardware::hidl_death_recipient
-    {
-    public:
-        ServiceDeathNotifier(
-                const sp<IBinder>& service,
-                const sp<IMediaRecorderClient>& listener,
-                int which);
-        ServiceDeathNotifier(
-                const sp<IOmx>& omx,
-                const sp<IMediaRecorderClient>& listener,
-                int which);
-        virtual ~ServiceDeathNotifier();
-        virtual void binderDied(const wp<IBinder>& who);
-        virtual void serviceDied(
-                uint64_t cookie,
-                const wp<::android::hidl::base::V1_0::IBase>& who);
-        void unlinkToDeath();
-    private:
-        int mWhich;
-        sp<IBinder> mService;
-        sp<IOmx> mOmx;
-        wp<IMediaRecorderClient> mListener;
-    };
-
     class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
     {
     public:
@@ -71,8 +45,6 @@
         wp<IMediaRecorderClient> mListener;
     };
 
-    void clearDeathNotifiers_l();
-
 public:
     virtual     status_t   setCamera(const sp<hardware::ICamera>& camera,
                                     const sp<ICameraRecordingProxy>& proxy);
@@ -122,8 +94,7 @@
                                                                const String16& opPackageName);
     virtual                ~MediaRecorderClient();
 
-    sp<ServiceDeathNotifier> mCameraDeathListener;
-    sp<ServiceDeathNotifier> mCodecDeathListener;
+    std::vector<DeathNotifier> mDeathNotifiers;
     sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedNotifier;
 
     pid_t                  mPid;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d8de103..3b87462 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -780,6 +780,9 @@
     // need to enable allocation when attaching
     surface->getIGraphicBufferProducer()->allowAllocation(true);
 
+    // dequeueBuffer cannot time out
+    surface->setDequeueTimeout(-1);
+
     // for meta data mode, we move dequeud buffers to the new surface.
     // for non-meta mode, we must move all registered buffers
     for (size_t i = 0; i < buffers.size(); ++i) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a7d37e5..2ca5eee 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1659,10 +1659,12 @@
         return;
     }
     int32_t colorFormat;
-    if (mSoftRenderer != NULL
-            && mOutputFormat->contains("hdr-static-info")
+    if (mOutputFormat->contains("hdr-static-info")
             && mOutputFormat->findInt32("color-format", &colorFormat)
-            && (colorFormat == OMX_COLOR_FormatYUV420Planar16)) {
+            // check format for OMX only, for C2 the format is always opaque since the
+            // software rendering doesn't go through client
+            && ((mSoftRenderer != NULL && colorFormat == OMX_COLOR_FormatYUV420Planar16)
+                    || mOwnerName.equalsIgnoreCase("codec2::software"))) {
         int32_t left, top, right, bottom, width, height;
         int64_t totalPixel = 0;
         if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
@@ -1958,6 +1960,7 @@
                     } else {
                         mFlags &= ~kFlagUsesSoftwareRenderer;
                     }
+                    mOwnerName = owner;
 
                     MediaResource::Type resourceType;
                     if (mComponentName.endsWith(".secure")) {
@@ -2221,6 +2224,7 @@
                             }
 
                             if (mime.startsWithIgnoreCase("video/")) {
+                                mSurface->setDequeueTimeout(-1);
                                 mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees);
                             }
                         }
@@ -2508,6 +2512,7 @@
                                             && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
                                         pushBlankBuffersToNativeWindow(mSurface.get());
                                     }
+                                    surface->setDequeueTimeout(-1);
                                     mSoftRenderer = new SoftwareRenderer(surface);
                                     // TODO: check if this was successful
                                 } else {
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index a309ee4..d97591f 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <android/dlext.h>
+#include <android-base/logging.h>
 #include <binder/IPCThreadState.h>
 #include <binder/PermissionCache.h>
 #include <binder/IServiceManager.h>
@@ -244,20 +245,17 @@
             void *libHandle = android_dlopen_ext(
                     libPath.string(),
                     RTLD_NOW | RTLD_LOCAL, dlextinfo);
-            if (libHandle) {
-                GetExtractorDef getDef =
-                    (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
-                if (getDef) {
-                    ALOGV("registering sniffer for %s", libPath.string());
-                    RegisterExtractor(
-                            new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);
-                } else {
-                    ALOGW("%s does not contain sniffer", libPath.string());
-                    dlclose(libHandle);
-                }
-            } else {
-                ALOGW("couldn't dlopen(%s) %s", libPath.string(), strerror(errno));
-            }
+            CHECK(libHandle != nullptr)
+                    << "couldn't dlopen(" << libPath.string() << ") " << strerror(errno);
+
+            GetExtractorDef getDef =
+                (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+            CHECK(getDef != nullptr)
+                    << libPath.string() << " does not contain sniffer";
+
+            ALOGV("registering sniffer for %s", libPath.string());
+            RegisterExtractor(
+                    new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);
         }
         closedir(libDir);
     } else {
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 83b87d9..680d426 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -430,18 +430,6 @@
     return OK;
 }
 
-void NuMediaExtractor::releaseOneSample(TrackInfo *info) {
-    if (info == NULL || info->mSamples.empty()) {
-        return;
-    }
-
-    auto it = info->mSamples.begin();
-    if (it->mBuffer != NULL) {
-        it->mBuffer->release();
-    }
-    info->mSamples.erase(it);
-}
-
 void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
     if (info == NULL) {
         return;
@@ -472,7 +460,7 @@
         fetchTrackSamples(info, seekTimeUs, mode);
 
         status_t err = info->mFinalResult;
-        if (err != OK && err != ERROR_END_OF_STREAM) {
+        if (err != OK && err != ERROR_END_OF_STREAM && info->mSamples.empty()) {
             return err;
         }
 
@@ -527,14 +515,6 @@
     info->mFinalResult = err;
     if (err != OK && err != ERROR_END_OF_STREAM) {
         ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
-        size_t count = mediaBuffers.size();
-        for (size_t id = 0; id < count; ++id) {
-            MediaBufferBase *mbuf = mediaBuffers[id];
-            if (mbuf != NULL) {
-                mbuf->release();
-            }
-        }
-        return;
     }
 
     size_t count = mediaBuffers.size();
@@ -584,8 +564,26 @@
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
 
-    releaseOneSample(info);
+    if (info == NULL || info->mSamples.empty()) {
+        return ERROR_END_OF_STREAM;
+    }
 
+    auto it = info->mSamples.begin();
+    if (it->mBuffer != NULL) {
+        it->mBuffer->release();
+    }
+    info->mSamples.erase(it);
+
+    if (info->mSamples.empty()) {
+        minIndex = fetchAllTrackSamples();
+        if (minIndex < 0) {
+            return ERROR_END_OF_STREAM;
+        }
+        info = &mSelectedTracks.editItemAt(minIndex);
+        if (info == NULL || info->mSamples.empty()) {
+            return ERROR_END_OF_STREAM;
+        }
+    }
     return OK;
 }
 
@@ -756,6 +754,9 @@
 }
 
 status_t NuMediaExtractor::getMetrics(Parcel *reply) {
+    if (mImpl == NULL) {
+        return -EINVAL;
+    }
     status_t status = mImpl->getMetrics(reply);
     return status;
 }
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index c7b2719..537e4c0 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1756,7 +1756,11 @@
                 size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
                 meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
             }
-        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
+        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC ||
+                mime == MEDIA_MIMETYPE_VIDEO_MPEG4 ||
+                mime == MEDIA_MIMETYPE_AUDIO_WMA ||
+                mime == MEDIA_MIMETYPE_AUDIO_MS_ADPCM ||
+                mime == MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) {
             std::vector<char> esds(csd0size + 31);
             // The written ESDS is actually for an audio stream, but it's enough
             // for transporting the CSD to muxers.
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 35df6d7..68abcb5 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -32,6 +32,7 @@
 #include <media/hardware/MetadataBufferType.h>
 #include <ui/GraphicBuffer.h>
 #include <gui/BufferItem.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
 #include <media/hardware/HardwareAPI.h>
 
 #include <inttypes.h>
@@ -282,24 +283,36 @@
 };
 
 struct GraphicBufferSource::ConsumerProxy : public BufferQueue::ConsumerListener {
-    ConsumerProxy(const sp<GraphicBufferSource> &gbs) : mGbs(gbs) {}
+    ConsumerProxy(const wp<GraphicBufferSource> &gbs) : mGbs(gbs) {}
 
     ~ConsumerProxy() = default;
 
     void onFrameAvailable(const BufferItem& item) override {
-        mGbs->onFrameAvailable(item);
+        sp<GraphicBufferSource> gbs = mGbs.promote();
+        if (gbs != nullptr) {
+            gbs->onFrameAvailable(item);
+        }
     }
 
     void onBuffersReleased() override {
-        mGbs->onBuffersReleased();
+        sp<GraphicBufferSource> gbs = mGbs.promote();
+        if (gbs != nullptr) {
+            gbs->onBuffersReleased();
+        }
     }
 
     void onSidebandStreamChanged() override {
-        mGbs->onSidebandStreamChanged();
+        sp<GraphicBufferSource> gbs = mGbs.promote();
+        if (gbs != nullptr) {
+            gbs->onSidebandStreamChanged();
+        }
     }
 
 private:
-    sp<GraphicBufferSource> mGbs;
+    // Note that GraphicBufferSource is holding an sp to us, we can't hold
+    // an sp back to GraphicBufferSource as the circular dependency will
+    // make both immortal.
+    wp<GraphicBufferSource> mGbs;
 };
 
 GraphicBufferSource::GraphicBufferSource() :
@@ -376,6 +389,12 @@
     }
 }
 
+sp<::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer>
+GraphicBufferSource::getHGraphicBufferProducer() const {
+    return new ::android::hardware::graphics::bufferqueue::V2_0::utils::
+                    B2HGraphicBufferProducer(getIGraphicBufferProducer());
+}
+
 Status GraphicBufferSource::start() {
     Mutex::Autolock autoLock(mMutex);
     ALOGV("--> start; available=%zu, submittable=%zd",
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
index 99e444b..bf329b9 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
@@ -86,6 +86,11 @@
         return mProducer;
     }
 
+    // Returns the handle to the bufferqueue HAL producer side of the BufferQueue.
+    // Buffers queued on this will be received by GraphicBufferSource.
+    sp<::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer>
+        getHGraphicBufferProducer() const;
+
     // This is called when component transitions to running state, which means
     // we can start handing it buffers.  If we already have buffers of data
     // sitting in the BufferQueue, this will send them to the codec.
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 52b2765..a08fed1 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -59,6 +59,10 @@
 const char *MEDIA_MIMETYPE_AUDIO_AC4 = "audio/ac4";
 const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
 const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
+const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM = "audio/x-adpcm-ms";
+const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM = "audio/x-adpcm-dvi-ima";
+
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 007a09b..1f9e636 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -61,6 +61,10 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_AC4;
 extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
 extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
+extern const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
+extern const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;
+
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 7f6aae6..6cd4265 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -313,6 +313,7 @@
     sp<ALooper> mCodecLooper;
     sp<CodecBase> mCodec;
     AString mComponentName;
+    AString mOwnerName;
     sp<MediaCodecInfo> mCodecInfo;
     sp<AReplyToken> mReplyID;
     uint32_t mFlags;
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index f34f9b6..4307110 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -149,7 +149,6 @@
             MediaSource::ReadOptions::SeekMode mode =
                 MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
 
-    void releaseOneSample(TrackInfo *info);
     void releaseTrackSamples(TrackInfo *info);
     void releaseAllTrackSamples();
 
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index b4515e4..48bc8ce 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -75,6 +75,8 @@
 // a new sequence.
 static int32_t kMaxAllowedStaleAccessUnits = 20;
 
+static int64_t kTearDownTimeoutUs = 3000000ll;
+
 namespace android {
 
 static bool GetAttribute(const char *s, const char *key, AString *value) {
@@ -930,6 +932,14 @@
                 request.append("\r\n");
 
                 mConn->sendRequest(request.c_str(), reply);
+
+                // If the response of teardown hasn't been received in 3 seconds,
+                // post 'tear' message to avoid ANR.
+                if (!msg->findInt32("reconnect", &reconnect) || !reconnect) {
+                    sp<AMessage> teardown = reply->dup();
+                    teardown->setInt32("result", -ECONNABORTED);
+                    teardown->post(kTearDownTimeoutUs);
+                }
                 break;
             }
 
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index a11602b..3adb40f 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -49,6 +49,10 @@
         },
     },
 
+    include_dirs: [
+        // For android_mallopt definitions.
+        "bionic/libc/private"
+    ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 }
diff --git a/media/utils/MemoryLeakTrackUtil.cpp b/media/utils/MemoryLeakTrackUtil.cpp
index 18f5f25..2988b52 100644
--- a/media/utils/MemoryLeakTrackUtil.cpp
+++ b/media/utils/MemoryLeakTrackUtil.cpp
@@ -22,6 +22,8 @@
 #include "media/MemoryLeakTrackUtil.h"
 #include <sstream>
 
+#include <bionic_malloc.h>
+
 /*
  * The code here originally resided in MediaPlayerService.cpp
  */
@@ -47,29 +49,22 @@
 
 namespace android {
 
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
-        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
-
-extern "C" void free_malloc_leak_info(uint8_t* info);
-
 std::string dumpMemoryAddresses(size_t limit)
 {
-    uint8_t *info;
-    size_t overallSize;
-    size_t infoSize;
-    size_t totalMemory;
-    size_t backtraceSize;
-    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
+    android_mallopt_leak_info_t leak_info;
+    if (!android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))) {
+      return "";
+    }
 
     size_t count;
-    if (info == nullptr || overallSize == 0 || infoSize == 0
-            || (count = overallSize / infoSize) == 0) {
+    if (leak_info.buffer == nullptr || leak_info.overall_size == 0 || leak_info.info_size == 0
+            || (count = leak_info.overall_size / leak_info.info_size) == 0) {
         ALOGD("no malloc info, libc.debug.malloc.program property should be set");
-        return std::string();
+        return "";
     }
 
     std::ostringstream oss;
-    oss << totalMemory << " bytes in " << count << " allocations\n";
+    oss << leak_info.total_memory << " bytes in " << count << " allocations\n";
     oss << "  ABI: '" ABI_STRING "'" << "\n\n";
     if (count > limit) count = limit;
 
@@ -83,14 +78,14 @@
             uintptr_t backtrace[];
         };
 
-        const AllocEntry * const e = (AllocEntry *)(info + i * infoSize);
+        const AllocEntry * const e = (AllocEntry *)(leak_info.buffer + i * leak_info.info_size);
 
         oss << (e->size * e->allocations)
                 << " bytes ( " << e->size << " bytes * " << e->allocations << " allocations )\n";
-        oss << backtrace_string(e->backtrace, backtraceSize) << "\n";
+        oss << backtrace_string(e->backtrace, leak_info.backtrace_size) << "\n";
     }
     oss << "\n";
-    free_malloc_leak_info(info);
+    android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info));
     return oss.str();
 }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0825cb4..55db699 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -687,6 +687,10 @@
     bool updatePid = (input.clientInfo.clientPid == -1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     uid_t clientUid = input.clientInfo.clientUid;
+    audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE;
+    std::vector<int> effectIds;
+
+
     if (!isAudioServerOrMediaServerUid(callingUid)) {
         ALOGW_IF(clientUid != callingUid,
                 "%s uid %d tried to pass itself off as %d",
@@ -851,7 +855,10 @@
             // no risk of deadlock because AudioFlinger::mLock is held
             Mutex::Autolock _dl(thread->mLock);
             Mutex::Autolock _sl(effectThread->mLock);
-            moveEffectChain_l(sessionId, effectThread, thread, true);
+            if (moveEffectChain_l(sessionId, effectThread, thread) == NO_ERROR) {
+                effectThreadId = thread->id();
+                effectIds = thread->getEffectIds_l(sessionId);
+            }
         }
 
         // Look for sync events awaiting for a session to be used.
@@ -885,6 +892,12 @@
         goto Exit;
     }
 
+    // effectThreadId is not NONE if an effect chain corresponding to the track session
+    // was found on another thread and must be moved on this thread
+    if (effectThreadId != AUDIO_IO_HANDLE_NONE) {
+        AudioSystem::moveEffectsToIo(effectIds, effectThreadId);
+    }
+
     // return handle to client
     trackHandle = new TrackHandle(track);
 
@@ -1225,7 +1238,8 @@
     if (output == AUDIO_IO_HANDLE_NONE) {
         return BAD_VALUE;
     }
-    ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume");
+    LOG_ALWAYS_FATAL_IF(stream == AUDIO_STREAM_PATCH && value != 1.0f,
+                        "AUDIO_STREAM_PATCH must have full scale volume");
 
     AutoMutex lock(mLock);
     VolumeInterface *volumeInterface = getVolumeInterface_l(output);
@@ -1630,30 +1644,36 @@
 
 void AudioFlinger::removeNotificationClient(pid_t pid)
 {
-    Mutex::Autolock _l(mLock);
+    std::vector< sp<AudioFlinger::EffectModule> > removedEffects;
     {
-        Mutex::Autolock _cl(mClientLock);
-        mNotificationClients.removeItem(pid);
-    }
+        Mutex::Autolock _l(mLock);
+        {
+            Mutex::Autolock _cl(mClientLock);
+            mNotificationClients.removeItem(pid);
+        }
 
-    ALOGV("%d died, releasing its sessions", pid);
-    size_t num = mAudioSessionRefs.size();
-    bool removed = false;
-    for (size_t i = 0; i < num; ) {
-        AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
-        ALOGV(" pid %d @ %zu", ref->mPid, i);
-        if (ref->mPid == pid) {
-            ALOGV(" removing entry for pid %d session %d", pid, ref->mSessionid);
-            mAudioSessionRefs.removeAt(i);
-            delete ref;
-            removed = true;
-            num--;
-        } else {
-            i++;
+        ALOGV("%d died, releasing its sessions", pid);
+        size_t num = mAudioSessionRefs.size();
+        bool removed = false;
+        for (size_t i = 0; i < num; ) {
+            AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+            ALOGV(" pid %d @ %zu", ref->mPid, i);
+            if (ref->mPid == pid) {
+                ALOGV(" removing entry for pid %d session %d", pid, ref->mSessionid);
+                mAudioSessionRefs.removeAt(i);
+                delete ref;
+                removed = true;
+                num--;
+            } else {
+                i++;
+            }
+        }
+        if (removed) {
+            removedEffects = purgeStaleEffects_l();
         }
     }
-    if (removed) {
-        purgeStaleEffects_l();
+    for (auto& effect : removedEffects) {
+        effect->updatePolicyState();
     }
 }
 
@@ -1679,18 +1699,35 @@
 }
 
 // getEffectThread_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::PlaybackThread> AudioFlinger::getEffectThread_l(audio_session_t sessionId,
-        int EffectId)
+sp<AudioFlinger::ThreadBase> AudioFlinger::getEffectThread_l(audio_session_t sessionId,
+        int effectId)
 {
-    sp<PlaybackThread> thread;
+    sp<ThreadBase> thread;
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        if (mPlaybackThreads.valueAt(i)->getEffect(sessionId, EffectId) != 0) {
+        if (mPlaybackThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
             ALOG_ASSERT(thread == 0);
             thread = mPlaybackThreads.valueAt(i);
         }
     }
-
+    if (thread != nullptr) {
+        return thread;
+    }
+    for (size_t i = 0; i < mRecordThreads.size(); i++) {
+        if (mRecordThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
+            ALOG_ASSERT(thread == 0);
+            thread = mRecordThreads.valueAt(i);
+        }
+    }
+    if (thread != nullptr) {
+        return thread;
+    }
+    for (size_t i = 0; i < mMmapThreads.size(); i++) {
+        if (mMmapThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
+            ALOG_ASSERT(thread == 0);
+            thread = mMmapThreads.valueAt(i);
+        }
+    }
     return thread;
 }
 
@@ -2425,7 +2462,7 @@
                     Vector< sp<EffectChain> > effectChains = playbackThread->getEffectChains_l();
                     for (size_t i = 0; i < effectChains.size(); i ++) {
                         moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(),
-                                dstThread, true);
+                                dstThread);
                     }
                 }
             }
@@ -2792,31 +2829,40 @@
 
 void AudioFlinger::releaseAudioSessionId(audio_session_t audioSession, pid_t pid)
 {
-    Mutex::Autolock _l(mLock);
-    pid_t caller = IPCThreadState::self()->getCallingPid();
-    ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
-    const uid_t callerUid = IPCThreadState::self()->getCallingUid();
-    if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
-        caller = pid;
-    }
-    size_t num = mAudioSessionRefs.size();
-    for (size_t i = 0; i < num; i++) {
-        AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
-        if (ref->mSessionid == audioSession && ref->mPid == caller) {
-            ref->mCnt--;
-            ALOGV(" decremented refcount to %d", ref->mCnt);
-            if (ref->mCnt == 0) {
-                mAudioSessionRefs.removeAt(i);
-                delete ref;
-                purgeStaleEffects_l();
-            }
-            return;
+    std::vector< sp<EffectModule> > removedEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        pid_t caller = IPCThreadState::self()->getCallingPid();
+        ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
+        const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+        if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
+            caller = pid;
         }
+        size_t num = mAudioSessionRefs.size();
+        for (size_t i = 0; i < num; i++) {
+            AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+            if (ref->mSessionid == audioSession && ref->mPid == caller) {
+                ref->mCnt--;
+                ALOGV(" decremented refcount to %d", ref->mCnt);
+                if (ref->mCnt == 0) {
+                    mAudioSessionRefs.removeAt(i);
+                    delete ref;
+                    std::vector< sp<EffectModule> > effects = purgeStaleEffects_l();
+                    removedEffects.insert(removedEffects.end(), effects.begin(), effects.end());
+                }
+                goto Exit;
+            }
+        }
+        // If the caller is audioserver it is likely that the session being released was acquired
+        // on behalf of a process not in notification clients and we ignore the warning.
+        ALOGW_IF(!isAudioServerUid(callerUid),
+                 "session id %d not found for pid %d", audioSession, caller);
     }
-    // If the caller is audioserver it is likely that the session being released was acquired
-    // on behalf of a process not in notification clients and we ignore the warning.
-    ALOGW_IF(!isAudioServerUid(callerUid),
-            "session id %d not found for pid %d", audioSession, caller);
+
+Exit:
+    for (auto& effect : removedEffects) {
+        effect->updatePolicyState();
+    }
 }
 
 bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession)
@@ -2831,11 +2877,12 @@
     return false;
 }
 
-void AudioFlinger::purgeStaleEffects_l() {
+std::vector<sp<AudioFlinger::EffectModule>> AudioFlinger::purgeStaleEffects_l() {
 
     ALOGV("purging stale effects");
 
     Vector< sp<EffectChain> > chains;
+    std::vector< sp<EffectModule> > removedEffects;
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
@@ -2847,6 +2894,7 @@
             }
         }
     }
+
     for (size_t i = 0; i < mRecordThreads.size(); i++) {
         sp<RecordThread> t = mRecordThreads.valueAt(i);
         Mutex::Autolock _l(t->mLock);
@@ -2856,6 +2904,15 @@
         }
     }
 
+    for (size_t i = 0; i < mMmapThreads.size(); i++) {
+        sp<MmapThread> t = mMmapThreads.valueAt(i);
+        Mutex::Autolock _l(t->mLock);
+        for (size_t j = 0; j < t->mEffectChains.size(); j++) {
+            sp<EffectChain> ec = t->mEffectChains[j];
+            chains.push(ec);
+        }
+    }
+
     for (size_t i = 0; i < chains.size(); i++) {
         sp<EffectChain> ec = chains[i];
         int sessionid = ec->sessionId();
@@ -2884,11 +2941,11 @@
                 if (effect->purgeHandles()) {
                     t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
                 }
-                AudioSystem::unregisterEffect(effect->id());
+                removedEffects.push_back(effect);
             }
         }
     }
-    return;
+    return removedEffects;
 }
 
 // dumpToThreadLog_l() must be called with AudioFlinger::mLock held
@@ -3380,8 +3437,16 @@
         }
     }
 
-    if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
-        // handle must be cleared outside lock.
+    if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
+        // Check CPU and memory usage
+        sp<EffectModule> effect = handle->effect().promote();
+        if (effect != nullptr) {
+            status_t rStatus = effect->updatePolicyState();
+            if (rStatus != NO_ERROR) {
+                lStatus = rStatus;
+            }
+        }
+    } else {
         handle.clear();
     }
 
@@ -3413,14 +3478,30 @@
 
     Mutex::Autolock _dl(dstThread->mLock);
     Mutex::Autolock _sl(srcThread->mLock);
-    return moveEffectChain_l(sessionId, srcThread, dstThread, false);
+    return moveEffectChain_l(sessionId, srcThread, dstThread);
 }
 
+
+void AudioFlinger::setEffectSuspended(int effectId,
+                                audio_session_t sessionId,
+                                bool suspended)
+{
+    Mutex::Autolock _l(mLock);
+
+    sp<ThreadBase> thread = getEffectThread_l(sessionId, effectId);
+    if (thread == nullptr) {
+      return;
+    }
+    Mutex::Autolock _sl(thread->mLock);
+    sp<EffectModule> effect = thread->getEffect_l(sessionId, effectId);
+    thread->setEffectSuspended_l(&effect->desc().type, suspended, sessionId);
+}
+
+
 // moveEffectChain_l must be called with both srcThread and dstThread mLocks held
 status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId,
                                    AudioFlinger::PlaybackThread *srcThread,
-                                   AudioFlinger::PlaybackThread *dstThread,
-                                   bool reRegister)
+                                   AudioFlinger::PlaybackThread *dstThread)
 {
     ALOGV("moveEffectChain_l() session %d from thread %p to thread %p",
             sessionId, srcThread, dstThread);
@@ -3476,36 +3557,68 @@
             }
             strategy = dstChain->strategy();
         }
-        if (reRegister) {
-            AudioSystem::unregisterEffect(effect->id());
-            AudioSystem::registerEffect(&effect->desc(),
-                                        dstThread->id(),
-                                        strategy,
-                                        sessionId,
-                                        effect->id());
-            AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
-        }
         effect = chain->getEffectFromId_l(0);
     }
 
     if (status != NO_ERROR) {
         for (size_t i = 0; i < removed.size(); i++) {
             srcThread->addEffect_l(removed[i]);
-            if (dstChain != 0 && reRegister) {
-                AudioSystem::unregisterEffect(removed[i]->id());
-                AudioSystem::registerEffect(&removed[i]->desc(),
-                                            srcThread->id(),
-                                            strategy,
-                                            sessionId,
-                                            removed[i]->id());
-                AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
-            }
         }
     }
 
     return status;
 }
 
+status_t AudioFlinger::moveAuxEffectToIo(int EffectId,
+                                         const sp<PlaybackThread>& dstThread,
+                                         sp<PlaybackThread> *srcThread)
+{
+    status_t status = NO_ERROR;
+    Mutex::Autolock _l(mLock);
+    sp<PlaybackThread> thread =
+        static_cast<PlaybackThread *>(getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId).get());
+
+    if (EffectId != 0 && thread != 0 && dstThread != thread.get()) {
+        Mutex::Autolock _dl(dstThread->mLock);
+        Mutex::Autolock _sl(thread->mLock);
+        sp<EffectChain> srcChain = thread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
+        sp<EffectChain> dstChain;
+        if (srcChain == 0) {
+            return INVALID_OPERATION;
+        }
+
+        sp<EffectModule> effect = srcChain->getEffectFromId_l(EffectId);
+        if (effect == 0) {
+            return INVALID_OPERATION;
+        }
+        thread->removeEffect_l(effect);
+        status = dstThread->addEffect_l(effect);
+        if (status != NO_ERROR) {
+            thread->addEffect_l(effect);
+            status = INVALID_OPERATION;
+            goto Exit;
+        }
+
+        dstChain = effect->chain().promote();
+        if (dstChain == 0) {
+            thread->addEffect_l(effect);
+            status = INVALID_OPERATION;
+        }
+
+Exit:
+        // removeEffect_l() has stopped the effect if it was active so it must be restarted
+        if (effect->state() == EffectModule::ACTIVE ||
+            effect->state() == EffectModule::STOPPING) {
+            effect->start();
+        }
+    }
+
+    if (status == NO_ERROR && srcThread != nullptr) {
+        *srcThread = thread;
+    }
+    return status;
+}
+
 bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l()
 {
     if (mGlobalEffectEnableTime != 0 &&
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9960f0e..72e669a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -239,6 +239,10 @@
     virtual status_t moveEffects(audio_session_t sessionId, audio_io_handle_t srcOutput,
                         audio_io_handle_t dstOutput);
 
+            void setEffectSuspended(int effectId,
+                                    audio_session_t sessionId,
+                                    bool suspended) override;
+
     virtual audio_module_handle_t loadHwModule(const char *name);
 
     virtual uint32_t getPrimaryOutputSamplingRate();
@@ -369,7 +373,6 @@
 
     AudioHwDevice*          findSuitableHwDev_l(audio_module_handle_t module,
                                                 audio_devices_t devices);
-    void                    purgeStaleEffects_l();
 
     // Set kEnableExtendedChannels to true to enable greater than stereo output
     // for the MixerThread and device sink.  Number of channels allowed is
@@ -696,8 +699,11 @@
 
               status_t moveEffectChain_l(audio_session_t sessionId,
                                      PlaybackThread *srcThread,
-                                     PlaybackThread *dstThread,
-                                     bool reRegister);
+                                     PlaybackThread *dstThread);
+
+              status_t moveAuxEffectToIo(int EffectId,
+                                         const sp<PlaybackThread>& dstThread,
+                                         sp<PlaybackThread> *srcThread);
 
               // return thread associated with primary hardware device, or NULL
               PlaybackThread *primaryPlaybackThread_l() const;
@@ -706,7 +712,7 @@
               // return the playback thread with smallest HAL buffer size, and prefer fast
               PlaybackThread *fastPlaybackThread_l() const;
 
-              sp<PlaybackThread> getEffectThread_l(audio_session_t sessionId, int EffectId);
+              sp<ThreadBase> getEffectThread_l(audio_session_t sessionId, int effectId);
 
 
                 void        removeClient_l(pid_t pid);
@@ -732,6 +738,8 @@
                 // Return true if the effect was found in mOrphanEffectChains, false otherwise.
                 bool            updateOrphanEffectChains(const sp<EffectModule>& effect);
 
+                std::vector< sp<EffectModule> > purgeStaleEffects_l();
+
                 void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
                 void forwardParametersToDownstreamPatches_l(
                         audio_io_handle_t upStream, const String8& keyValuePairs,
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 2b34267..3c4fbba 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -168,6 +168,68 @@
     return status;
 }
 
+status_t AudioFlinger::EffectModule::updatePolicyState()
+{
+    status_t status = NO_ERROR;
+    bool doRegister = false;
+    bool registered = false;
+    bool doEnable = false;
+    bool enabled = false;
+    audio_io_handle_t io;
+    uint32_t strategy;
+
+    {
+        Mutex::Autolock _l(mLock);
+        // register effect when first handle is attached and unregister when last handle is removed
+        if (mPolicyRegistered != mHandles.size() > 0) {
+            doRegister = true;
+            mPolicyRegistered = mHandles.size() > 0;
+            if (mPolicyRegistered) {
+              sp <EffectChain> chain = mChain.promote();
+              sp <ThreadBase> thread = mThread.promote();
+
+              if (thread == nullptr || chain == nullptr) {
+                    return INVALID_OPERATION;
+                }
+                io = thread->id();
+                strategy = chain->strategy();
+            }
+        }
+        // enable effect when registered according to enable state requested by controlling handle
+        if (mHandles.size() > 0) {
+            EffectHandle *handle = controlHandle_l();
+            if (handle != nullptr && mPolicyEnabled != handle->enabled()) {
+                doEnable = true;
+                mPolicyEnabled = handle->enabled();
+            }
+        }
+        registered = mPolicyRegistered;
+        enabled = mPolicyEnabled;
+        mPolicyLock.lock();
+    }
+    ALOGV("%s name %s id %d session %d doRegister %d registered %d doEnable %d enabled %d",
+        __func__, mDescriptor.name, mId, mSessionId, doRegister, registered, doEnable, enabled);
+    if (doRegister) {
+        if (registered) {
+            status = AudioSystem::registerEffect(
+                &mDescriptor,
+                io,
+                strategy,
+                mSessionId,
+                mId);
+        } else {
+            status = AudioSystem::unregisterEffect(mId);
+        }
+    }
+    if (registered && doEnable) {
+        status = AudioSystem::setEffectEnabled(mId, enabled);
+    }
+    mPolicyLock.unlock();
+
+    return status;
+}
+
+
 ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
 {
     Mutex::Autolock _l(mLock);
@@ -230,7 +292,6 @@
     Mutex::Autolock _l(mLock);
     ssize_t numHandles = removeHandle_l(handle);
     if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
-        AudioSystem::unregisterEffect(mId);
         sp<AudioFlinger> af = mAudioFlinger.promote();
         if (af != 0) {
             mLock.unlock();
@@ -943,11 +1004,6 @@
     ALOGV("setEnabled %p enabled %d", this, enabled);
 
     if (enabled != isEnabled()) {
-        status_t status = AudioSystem::setEffectEnabled(mId, enabled);
-        if (enabled && status != NO_ERROR) {
-            return status;
-        }
-
         switch (mState) {
         // going from disabled to enabled
         case IDLE:
@@ -1253,14 +1309,11 @@
 {
     bool enabled = false;
     Mutex::Autolock _l(mLock);
-    for (size_t i = 0; i < mHandles.size(); i++) {
-        EffectHandle *handle = mHandles[i];
-        if (handle != NULL && !handle->disconnected()) {
-            if (handle->hasControl()) {
-                enabled = handle->enabled();
-            }
-        }
+    EffectHandle *handle = controlHandle_l();
+    if (handle != NULL) {
+        enabled = handle->enabled();
     }
+    mHandles.clear();
     return enabled;
 }
 
@@ -1435,9 +1488,10 @@
         result.append("\t\tCould not lock Fx mutex:\n");
     }
 
-    result.append("\t\tSession Status State Engine:\n");
-    result.appendFormat("\t\t%05d   %03d    %03d   %p\n",
-            mSessionId, mStatus, mState, mEffectInterface.get());
+    result.append("\t\tSession Status State Registered Enabled Suspended Engine:\n");
+    result.appendFormat("\t\t%05d   %03d    %03d   %s          %s       %s         %p\n",
+            mSessionId, mStatus, mState, mPolicyRegistered ? "y" : "n", mPolicyEnabled ? "y" : "n",
+            mSuspended ? "y" : "n", mEffectInterface.get());
 
     result.append("\t\tDescriptor:\n");
     char uuidStr[64];
@@ -1572,6 +1626,12 @@
 
     mEnabled = true;
 
+    status_t status = effect->updatePolicyState();
+    if (status != NO_ERROR) {
+        mEnabled = false;
+        return status;
+    }
+
     sp<ThreadBase> thread = effect->thread().promote();
     if (thread != 0) {
         thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId());
@@ -1582,7 +1642,7 @@
         return NO_ERROR;
     }
 
-    status_t status = effect->setEnabled(true);
+    status = effect->setEnabled(true);
     if (status != NO_ERROR) {
         if (thread != 0) {
             thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
@@ -1625,6 +1685,8 @@
     }
     mEnabled = false;
 
+    effect->updatePolicyState();
+
     if (effect->suspended()) {
         return NO_ERROR;
     }
@@ -1660,20 +1722,17 @@
         return;
     }
     mDisconnected = true;
-    sp<ThreadBase> thread;
     {
         sp<EffectModule> effect = mEffect.promote();
         if (effect != 0) {
-            thread = effect->thread().promote();
-        }
-    }
-    if (thread != 0) {
-        thread->disconnectEffectHandle(this, unpinIfLast);
-    } else {
-        // try to cleanup as much as we can
-        sp<EffectModule> effect = mEffect.promote();
-        if (effect != 0 && effect->disconnectHandle(this, unpinIfLast) > 0) {
-            ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this);
+            sp<ThreadBase> thread = effect->thread().promote();
+            if (thread != 0) {
+                thread->disconnectEffectHandle(this, unpinIfLast);
+            } else if (effect->disconnectHandle(this, unpinIfLast) > 0) {
+                ALOGW("%s Effect handle %p disconnected after thread destruction",
+                    __func__, this);
+            }
+            effect->updatePolicyState();
         }
     }
 
@@ -1947,6 +2006,16 @@
     return 0;
 }
 
+std::vector<int> AudioFlinger::EffectChain::getEffectIds()
+{
+    std::vector<int> ids;
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        ids.push_back(mEffects[i]->id());
+    }
+    return ids;
+}
+
 void AudioFlinger::EffectChain::clearInputBuffer()
 {
     Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 58ce351..220874d 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -142,6 +142,8 @@
     void             addEffectToHal_l();
     void             release_l();
 
+    status_t         updatePolicyState();
+
     void             dump(int fd, const Vector<String16>& args);
 
 private:
@@ -204,6 +206,16 @@
     static constexpr pid_t INVALID_PID = (pid_t)-1;
     // this tid is allowed to call setVolume() without acquiring the mutex.
     pid_t mSetVolumeReentrantTid = INVALID_PID;
+
+    // Audio policy effect state management
+    // Mutex protecting transactions with audio policy manager as mLock cannot
+    // be held to avoid cross deadlocks with audio policy mutex
+    Mutex   mPolicyLock;
+    // Effect is registered in APM or not
+    bool    mPolicyRegistered = false;
+    // Effect enabled state communicated to APM. Enabled state corresponds to
+    // state requested by the EffectHandle with control
+    bool    mPolicyEnabled = false;
 };
 
 // The EffectHandle class implements the IEffect interface. It provides resources
@@ -334,6 +346,7 @@
     sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
     sp<EffectModule> getEffectFromId_l(int id);
     sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
+    std::vector<int> getEffectIds();
     // FIXME use float to improve the dynamic range
     bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
     void resetVolume_l();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0bb2213..711a6dd 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -44,6 +44,7 @@
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
 #include <audio_utils/minifloat.h>
+#include <audio_utils/safe_math.h>
 #include <system/audio_effects/effect_ns.h>
 #include <system/audio_effects/effect_aec.h>
 #include <system/audio.h>
@@ -1305,7 +1306,6 @@
     sp<EffectChain> chain;
     bool chainCreated = false;
     bool effectCreated = false;
-    bool effectRegistered = false;
     audio_unique_id_t effectId = AUDIO_UNIQUE_ID_USE_UNSPECIFIED;
 
     lStatus = initCheck();
@@ -1341,13 +1341,6 @@
 
         if (effect == 0) {
             effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
-            // Check CPU and memory usage
-            lStatus = AudioSystem::registerEffect(
-                    desc, mId, chain->strategy(), sessionId, effectId);
-            if (lStatus != NO_ERROR) {
-                goto Exit;
-            }
-            effectRegistered = true;
             // create a new effect module if none present in the chain
             lStatus = chain->createEffect_l(effect, this, desc, effectId, sessionId, pinned);
             if (lStatus != NO_ERROR) {
@@ -1377,9 +1370,6 @@
         if (effectCreated) {
             chain->removeEffect_l(effect);
         }
-        if (effectRegistered) {
-            AudioSystem::unregisterEffect(effectId);
-        }
         if (chainCreated) {
             removeEffectChain_l(chain);
         }
@@ -1410,7 +1400,6 @@
     }
     if (remove) {
         mAudioFlinger->updateOrphanEffectChains(effect);
-        AudioSystem::unregisterEffect(effect->id());
         if (handle->enabled()) {
             checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
         }
@@ -1431,6 +1420,12 @@
     return chain != 0 ? chain->getEffectFromId_l(effectId) : 0;
 }
 
+std::vector<int> AudioFlinger::ThreadBase::getEffectIds_l(audio_session_t sessionId)
+{
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    return chain != nullptr ? chain->getEffectIds() : std::vector<int>{};
+}
+
 // PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
 // PlaybackThread::mLock held
 status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
@@ -2136,9 +2131,15 @@
             // notify every HAL buffer, regardless of the size of the track buffer
             maxNotificationFrames = mFrameCount;
         } else {
-            // For normal tracks, use at least double-buffering if no sample rate conversion,
-            // or at least triple-buffering if there is sample rate conversion
-            const int nBuffering = sampleRate == mSampleRate ? 2 : 3;
+            // Triple buffer the notification period for a triple buffered mixer period;
+            // otherwise, double buffering for the notification period is fine.
+            //
+            // TODO: This should be moved to AudioTrack to modify the notification period
+            // on AudioTrack::setBufferSizeInFrames() changes.
+            const int nBuffering =
+                    (uint64_t{frameCount} * mSampleRate)
+                            / (uint64_t{mNormalFrameCount} * sampleRate) == 3 ? 3 : 2;
+
             maxNotificationFrames = frameCount / nBuffering;
             // If client requested a fast track but this was denied, then use the smaller maximum.
             if (requestedFlags & AUDIO_OUTPUT_FLAG_FAST) {
@@ -2725,7 +2726,8 @@
     // create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
     Vector< sp<EffectChain> > effectChains = mEffectChains;
     for (size_t i = 0; i < effectChains.size(); i ++) {
-        mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this, false);
+        mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(),
+            this/* srcThread */, this/* dstThread */);
     }
 }
 
@@ -4191,6 +4193,7 @@
                                                                      // audio to FastMixer
         fastTrack->mFormat = mFormat; // mPipeSink format for audio to FastMixer
         fastTrack->mHapticPlaybackEnabled = mHapticChannelMask != AUDIO_CHANNEL_NONE;
+        fastTrack->mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE;
         fastTrack->mGeneration++;
         state->mFastTracksGen++;
         state->mTrackMask = 1;
@@ -7451,8 +7454,10 @@
             // we formerly checked for a callback handler (non-0 tid),
             // but that is no longer required for TRANSFER_OBTAIN mode
             //
-            // frame count is not specified, or is exactly the pipe depth
-            ((frameCount == 0) || (frameCount == mPipeFramesP2)) &&
+            // Frame count is not specified (0), or is less than or equal the pipe depth.
+            // It is OK to provide a higher capacity than requested.
+            // We will force it to mPipeFramesP2 below.
+            (frameCount <= mPipeFramesP2) &&
             // PCM data
             audio_is_linear_pcm(format) &&
             // hardware format
@@ -7897,7 +7902,7 @@
     RecordThread *recordThread = (RecordThread *) threadBase.get();
     const int32_t rear = recordThread->mRsmpInRear;
     const int32_t front = mRsmpInFront;
-    const ssize_t filled = rear - front;
+    const ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
 
     size_t framesIn;
     bool overrun = false;
@@ -7911,7 +7916,8 @@
     } else {
         // client is not keeping up with server, but give it latest data
         framesIn = recordThread->mRsmpInFrames;
-        mRsmpInFront = /* front = */ rear - framesIn;
+        mRsmpInFront = /* front = */ audio_utils::safe_sub_overflow(
+                rear, static_cast<int32_t>(framesIn));
         overrun = true;
     }
     if (framesAvailable != NULL) {
@@ -7935,7 +7941,7 @@
     RecordThread *recordThread = (RecordThread *) threadBase.get();
     int32_t rear = recordThread->mRsmpInRear;
     int32_t front = mRsmpInFront;
-    ssize_t filled = rear - front;
+    ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
     // FIXME should not be P2 (don't want to increase latency)
     // FIXME if client not keeping up, discard
     LOG_ALWAYS_FATAL_IF(!(0 <= filled && (size_t) filled <= recordThread->mRsmpInFrames));
@@ -7968,13 +7974,13 @@
 void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer(
         AudioBufferProvider::Buffer* buffer)
 {
-    size_t stepCount = buffer->frameCount;
+    int32_t stepCount = static_cast<int32_t>(buffer->frameCount);
     if (stepCount == 0) {
         return;
     }
     ALOG_ASSERT(stepCount <= mRsmpInUnrel);
     mRsmpInUnrel -= stepCount;
-    mRsmpInFront += stepCount;
+    mRsmpInFront = audio_utils::safe_add_overflow(mRsmpInFront, stepCount);
     buffer->raw = NULL;
     buffer->frameCount = 0;
 }
@@ -8244,11 +8250,6 @@
 
 status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
 {
-    // only one chain per input thread
-    if (!mEffectChains.isEmpty()) {
-        ALOGW("addEffectChain_l() already one chain %p on thread %p", chain.get(), this);
-        return INVALID_OPERATION;
-    }
     ALOGV("addEffectChain_l() %p on thread %p", chain.get(), this);
     chain->setThread(this);
     chain->setInBuffer(NULL);
@@ -8268,13 +8269,14 @@
 size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& chain)
 {
     ALOGV("removeEffectChain_l() %p from thread %p", chain.get(), this);
-    ALOGW_IF(mEffectChains.size() != 1,
-            "removeEffectChain_l() %p invalid chain size %zu on thread %p",
-            chain.get(), mEffectChains.size(), this);
-    if (mEffectChains.size() == 1) {
-        mEffectChains.removeAt(0);
+
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        if (chain == mEffectChains[i]) {
+            mEffectChains.removeAt(i);
+            break;
+        }
     }
-    return 0;
+    return mEffectChains.size();
 }
 
 status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *patch,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 18cb361..37b2d08 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -315,6 +315,7 @@
                 sp<EffectChain> getEffectChain(audio_session_t sessionId);
                 // same as getEffectChain() but must be called with ThreadBase mutex locked
                 sp<EffectChain> getEffectChain_l(audio_session_t sessionId) const;
+                std::vector<int> getEffectIds_l(audio_session_t sessionId);
                 // add an effect chain to the chain list (mEffectChains)
     virtual     status_t addEffectChain_l(const sp<EffectChain>& chain) = 0;
                 // remove an effect chain from the chain list (mEffectChains)
@@ -334,7 +335,8 @@
                 sp<AudioFlinger::EffectModule> getEffect(audio_session_t sessionId, int effectId);
                 sp<AudioFlinger::EffectModule> getEffect_l(audio_session_t sessionId, int effectId);
                 // add and effect module. Also creates the effect chain is none exists for
-                // the effects audio session
+                // the effects audio session. Only called in a context of moving an effect
+                // from one thread to another
                 status_t addEffect_l(const sp< EffectModule>& effect);
                 // remove and effect module. Also removes the effect chain is this was the last
                 // effect
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index bbda17f..2ff80c6 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1244,54 +1244,25 @@
 
 status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
 {
-    status_t status = DEAD_OBJECT;
     sp<ThreadBase> thread = mThread.promote();
-    if (thread != 0) {
-        PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
-        sp<AudioFlinger> af = mClient->audioFlinger();
+    if (thread == nullptr) {
+        return DEAD_OBJECT;
+    }
 
-        Mutex::Autolock _l(af->mLock);
+    sp<PlaybackThread> dstThread = (PlaybackThread *)thread.get();
+    sp<PlaybackThread> srcThread; // srcThread is initialized by call to moveAuxEffectToIo()
+    sp<AudioFlinger> af = mClient->audioFlinger();
+    status_t status = af->moveAuxEffectToIo(EffectId, dstThread, &srcThread);
 
-        sp<PlaybackThread> srcThread = af->getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId);
-
-        if (EffectId != 0 && srcThread != 0 && playbackThread != srcThread.get()) {
-            Mutex::Autolock _dl(playbackThread->mLock);
-            Mutex::Autolock _sl(srcThread->mLock);
-            sp<EffectChain> chain = srcThread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
-            if (chain == 0) {
-                return INVALID_OPERATION;
-            }
-
-            sp<EffectModule> effect = chain->getEffectFromId_l(EffectId);
-            if (effect == 0) {
-                return INVALID_OPERATION;
-            }
-            srcThread->removeEffect_l(effect);
-            status = playbackThread->addEffect_l(effect);
-            if (status != NO_ERROR) {
-                srcThread->addEffect_l(effect);
-                return INVALID_OPERATION;
-            }
-            // removeEffect_l() has stopped the effect if it was active so it must be restarted
-            if (effect->state() == EffectModule::ACTIVE ||
-                    effect->state() == EffectModule::STOPPING) {
-                effect->start();
-            }
-
-            sp<EffectChain> dstChain = effect->chain().promote();
-            if (dstChain == 0) {
-                srcThread->addEffect_l(effect);
-                return INVALID_OPERATION;
-            }
-            AudioSystem::unregisterEffect(effect->id());
-            AudioSystem::registerEffect(&effect->desc(),
-                                        srcThread->id(),
-                                        dstChain->strategy(),
-                                        AUDIO_SESSION_OUTPUT_MIX,
-                                        effect->id());
-            AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
+    if (EffectId != 0 && status == NO_ERROR) {
+        status = dstThread->attachAuxEffect(this, EffectId);
+        if (status == NO_ERROR) {
+            AudioSystem::moveEffectsToIo(std::vector<int>(EffectId), dstThread->id());
         }
-        status = playbackThread->attachAuxEffect(this, EffectId);
+    }
+
+    if (status != NO_ERROR && srcThread != nullptr) {
+        af->moveAuxEffectToIo(EffectId, srcThread, &dstThread);
     }
     return status;
 }
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index a2cf7aa..4b56a46 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -189,6 +189,7 @@
                                     int id) = 0;
     virtual status_t unregisterEffect(int id) = 0;
     virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+    virtual status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) = 0;
 
     virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const = 0;
     virtual bool isStreamActiveRemotely(audio_stream_type_t stream,
@@ -347,6 +348,10 @@
                                      audio_io_handle_t srcOutput,
                                      audio_io_handle_t dstOutput) = 0;
 
+    virtual void setEffectSuspended(int effectId,
+                                    audio_session_t sessionId,
+                                    bool suspended) = 0;
+
     /* Create a patch between several source and sink ports */
     virtual status_t createAudioPatch(const struct audio_patch *patch,
                                        audio_patch_handle_t *handle,
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 54c5c76..1dbd1eb 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -23,7 +23,6 @@
 
 namespace android {
 
-
 /**
  * VolumeSource is the discriminent for volume management on an output.
  * It used to be the stream type by legacy, it may be host volume group or a volume curves if
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index e071fe0..37f9d14 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -68,11 +68,13 @@
     bool isSourceActive(audio_source_t source) const;
     audio_source_t source() const;
     bool isSoundTrigger() const;
+    sp<RecordClientDescriptor> getHighestPriorityClient() const;
     audio_attributes_t getHighestPriorityAttributes() const;
     void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
     int32_t activeCount() { return mGlobalActiveCount; }
     void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
     EffectDescriptorCollection getEnabledEffects() const;
+    EffectDescriptorCollection getActiveEffects() const; // enabled and not suspended
     // implementation of AudioIODescriptorInterface
     audio_config_base_t getConfig() const override;
     audio_patch_handle_t getPatchHandle() const override;
@@ -100,6 +102,10 @@
     // implementation of ClientMapHandler<RecordClientDescriptor>
     void addClient(const sp<RecordClientDescriptor> &client) override;
 
+    // Go over all active clients and suspend or restore effects according highest priority
+    // active use case
+    void checkSuspendEffects();
+
  private:
 
     void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index 7f01dc5..c4eab30 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -29,8 +29,8 @@
 {
 public:
     EffectDescriptor(const effect_descriptor_t *desc, bool isMusicEffect,
-                     int id, int io, int session) :
-        mId(id), mIo(io), mSession(session), mEnabled(false),
+                     int id, audio_io_handle_t io, audio_session_t session) :
+        mId(id), mIo(io), mSession(session), mEnabled(false), mSuspended(false),
         mIsMusicEffect(isMusicEffect)
     {
         memcpy (&mDesc, desc, sizeof(effect_descriptor_t));
@@ -38,11 +38,12 @@
 
     void dump(String8 *dst, int spaces = 0) const;
 
-    int mId;                // effect unique ID
-    int mIo;                // io the effect is attached to
-    int mSession;               // audio session the effect is on
-    effect_descriptor_t mDesc;  // effect descriptor
-    bool mEnabled;              // enabled state: CPU load being used or not
+    int mId;                   // effect unique ID
+    audio_io_handle_t mIo;     // io the effect is attached to
+    audio_session_t mSession;  // audio session the effect is on
+    effect_descriptor_t mDesc; // effect descriptor
+    bool mEnabled;             // enabled state: CPU load being used or not
+    bool mSuspended;           // enabled but suspended by concurent capture policy
 
     bool isMusicEffect() const { return mIsMusicEffect; }
 
@@ -59,12 +60,18 @@
                             int session, int id, bool isMusicEffect);
     status_t unregisterEffect(int id);
     sp<EffectDescriptor> getEffect(int id) const;
+    EffectDescriptorCollection getEffectsForIo(audio_io_handle_t io) const;
     status_t setEffectEnabled(int id, bool enabled);
     bool     isEffectEnabled(int id) const;
     uint32_t getMaxEffectsCpuLoad() const;
     uint32_t getMaxEffectsMemory() const;
     bool isNonOffloadableEffectEnabled() const;
 
+    void moveEffects(audio_session_t session,
+                     audio_io_handle_t srcOutput,
+                     audio_io_handle_t dstOutput);
+    void moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput);
+
     void dump(String8 *dst, int spaces = 0, bool verbose = true) const;
 
 private:
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 5b4e2eb..58683be 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -128,6 +128,13 @@
 audio_attributes_t AudioInputDescriptor::getHighestPriorityAttributes() const
 {
     audio_attributes_t attributes = { .source = AUDIO_SOURCE_DEFAULT };
+    sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+    return topClient ? topClient->attributes() : attributes;
+}
+
+sp<RecordClientDescriptor> AudioInputDescriptor::getHighestPriorityClient() const
+{
+    sp<RecordClientDescriptor> topClient;
 
     for (bool activeOnly : { true, false }) {
         int32_t topPriority = -1;
@@ -139,18 +146,18 @@
             app_state_t curState = client->appState();
             if (curState >= topState) {
                 int32_t curPriority = source_priority(client->source());
-                if (curPriority > topPriority) {
-                    attributes = client->attributes();
+                if (curPriority >= topPriority) {
+                    topClient = client;
                     topPriority = curPriority;
                 }
                 topState = curState;
             }
         }
-        if (attributes.source != AUDIO_SOURCE_DEFAULT) {
+        if (topClient != nullptr) {
             break;
         }
     }
-    return attributes;
+    return topClient;
 }
 
 bool AudioInputDescriptor::isSoundTrigger() const {
@@ -326,9 +333,10 @@
 
     client->setActive(active);
 
+    checkSuspendEffects();
+
     int event = active ? RECORD_CONFIG_EVENT_START : RECORD_CONFIG_EVENT_STOP;
     updateClientRecordingConfiguration(event, client);
-
 }
 
 void AudioInputDescriptor::updateClientRecordingConfiguration(
@@ -397,44 +405,90 @@
         mEnabledEffects.replaceValueFor(effect->mId, effect);
     } else {
         mEnabledEffects.removeItem(effect->mId);
+        // always exit from suspend when disabling an effect as only enabled effects
+        // are managed by checkSuspendEffects()
+        if (effect->mSuspended) {
+            effect->mSuspended = false;
+            mClientInterface->setEffectSuspended(effect->mId, effect->mSession, effect->mSuspended);
+        }
     }
 
     RecordClientVector clients = getClientsForSession((audio_session_t)effect->mSession);
+    RecordClientVector updatedClients;
+
     for (const auto& client : clients) {
         sp<EffectDescriptor> clientEffect = client->getEnabledEffects().getEffect(effect->mId);
         bool changed = (enabled && clientEffect == nullptr)
                 || (!enabled && clientEffect != nullptr);
         client->trackEffectEnabled(effect, enabled);
         if (changed && client->active()) {
-            updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+            updatedClients.push_back(client);
         }
     }
+
+    checkSuspendEffects();
+
+    for (const auto& client : updatedClients) {
+        updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+    }
 }
 
 EffectDescriptorCollection AudioInputDescriptor::getEnabledEffects() const
 {
-    EffectDescriptorCollection enabledEffects;
     // report effects for highest priority active source as applied to all clients
-    RecordClientVector clients =
-        clientsList(true /*activeOnly*/, source(), false /*preferredDeviceOnly*/);
-    if (clients.size() > 0) {
-        enabledEffects = clients[0]->getEnabledEffects();
+    EffectDescriptorCollection enabledEffects;
+    sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+    if (topClient != nullptr) {
+        enabledEffects = topClient->getEnabledEffects();
     }
     return enabledEffects;
 }
 
-void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state) {
+void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state)
+{
     RecordClientVector clients = clientsList(false /*activeOnly*/);
+    RecordClientVector updatedClients;
 
     for (const auto& client : clients) {
         if (uid == client->uid()) {
             bool wasSilenced = client->isSilenced();
             client->setAppState(state);
             if (client->active() && wasSilenced != client->isSilenced()) {
-                updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+                updatedClients.push_back(client);
             }
         }
     }
+
+    checkSuspendEffects();
+
+    for (const auto& client : updatedClients) {
+        updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+    }
+}
+
+void AudioInputDescriptor::checkSuspendEffects()
+{
+    sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+    if (topClient == nullptr) {
+        return;
+    }
+
+    for (size_t i = 0; i < mEnabledEffects.size(); i++) {
+        sp<EffectDescriptor> effect = mEnabledEffects.valueAt(i);
+        if (effect->mSession == topClient->session()) {
+            if (effect->mSuspended) {
+                effect->mSuspended = false;
+                mClientInterface->setEffectSuspended(effect->mId,
+                                                     effect->mSession,
+                                                     effect->mSuspended);
+            }
+        } else if (!effect->mSuspended) {
+            effect->mSuspended = true;
+            mClientInterface->setEffectSuspended(effect->mId,
+                                                 effect->mSession,
+                                                 effect->mSuspended);
+        }
+    }
 }
 
 void AudioInputDescriptor::dump(String8 *dst) const
@@ -444,7 +498,7 @@
     dst->appendFormat(" Format: %d\n", mFormat);
     dst->appendFormat(" Channels: %08x\n", mChannelMask);
     dst->appendFormat(" Devices %s\n", mDevice->toString().c_str());
-    getEnabledEffects().dump(dst, 1 /*spaces*/, false /*verbose*/);
+    mEnabledEffects.dump(dst, 1 /*spaces*/, false /*verbose*/);
     dst->append(" AudioRecord Clients:\n");
     ClientMapHandler<RecordClientDescriptor>::dump(dst);
     dst->append("\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 89f9899..415962a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -30,6 +30,7 @@
     dst->appendFormat("%*sSession: %d\n", spaces, "", mSession);
     dst->appendFormat("%*sName: %s\n", spaces, "",  mDesc.name);
     dst->appendFormat("%*s%s\n", spaces, "",  mEnabled ? "Enabled" : "Disabled");
+    dst->appendFormat("%*s%s\n", spaces, "",  mSuspended ? "Suspended" : "Active");
 }
 
 EffectDescriptorCollection::EffectDescriptorCollection() :
@@ -63,7 +64,8 @@
             desc->name, io, session, id);
     ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
 
-    sp<EffectDescriptor> effectDesc = new EffectDescriptor(desc, isMusicEffect, id, io, session);
+    sp<EffectDescriptor> effectDesc =
+        new EffectDescriptor(desc, isMusicEffect, id, io, (audio_session_t)session);
     add(id, effectDesc);
 
     return NO_ERROR;
@@ -174,6 +176,43 @@
     return MAX_EFFECTS_MEMORY;
 }
 
+void EffectDescriptorCollection::moveEffects(audio_session_t session,
+                                             audio_io_handle_t srcOutput,
+                                             audio_io_handle_t dstOutput)
+{
+    ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput);
+    for (size_t i = 0; i < size(); i++) {
+        sp<EffectDescriptor> effect = valueAt(i);
+        if (effect->mSession == session && effect->mIo == srcOutput) {
+            effect->mIo = dstOutput;
+        }
+    }
+}
+
+void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids,
+                                             audio_io_handle_t dstOutput)
+{
+    ALOGV("%s num effects %zu, first ID %d, dstOutput %d",
+        __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput);
+    for (size_t i = 0; i < size(); i++) {
+        sp<EffectDescriptor> effect = valueAt(i);
+        if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) {
+            effect->mIo = dstOutput;
+        }
+    }
+}
+
+EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
+{
+    EffectDescriptorCollection effects;
+    for (size_t i = 0; i < size(); i++) {
+        if (valueAt(i)->mIo == io) {
+            effects.add(keyAt(i), valueAt(i));
+        }
+    }
+    return effects;
+}
+
 void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
 {
     if (verbose) {
diff --git a/services/audiopolicy/engineconfigurable/config/example/Android.mk b/services/audiopolicy/engineconfigurable/config/example/Android.mk
index 37271b5..f879afc 100644
--- a/services/audiopolicy/engineconfigurable/config/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/config/example/Android.mk
@@ -137,9 +137,7 @@
 LOCAL_MODULE := audio_policy_engine_criterion_types.xml
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-    $(TARGET_OUT_VENDOR_ETC)/audio_policy_configuration.xml
-
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_VENDOR_ETC)/primary_audio_policy_configuration.xml
 ANDROID_AUDIO_BASE_HEADER_FILE := system/media/audio/include/system/audio-base.h
 AUDIO_POLICY_CONFIGURATION_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_configuration.xml
 CRITERION_TYPES_FILE := $(LOCAL_PATH)/common/$(LOCAL_MODULE).in
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
index c487da9..0ee83a2 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
@@ -166,5 +166,20 @@
             <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
+
+    <!-- Routing Strategy rerouting may be removed as following media??? -->
+    <ProductStrategy name="rerouting">
+        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
+            <Attributes></Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
+    <ProductStrategy name="patch">
+        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
+            <Attributes></Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
 </ProductStrategies>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
index 9ec3d77..6e72dc5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -188,5 +188,26 @@
             <point>100,0</point>
         </volume>
     </volumeGroup>
+
+    <volumeGroup>
+        <name>rerouting</name>
+        <indexMin>0</indexMin>
+        <indexMax>1</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,0</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>patch</name>
+        <indexMin>0</indexMin>
+        <indexMax>1</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,0</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
 </volumeGroups>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
index c487da9..adcbd83 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
@@ -166,5 +166,19 @@
             <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
+
+    <!-- Routing Strategy rerouting may be removed as following media??? -->
+    <ProductStrategy name="rerouting">
+        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
+            <Attributes></Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
+    <ProductStrategy name="patch">
+        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
+            <Attributes></Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
 </ProductStrategies>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
index 9ec3d77..6e72dc5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
@@ -188,5 +188,26 @@
             <point>100,0</point>
         </volume>
     </volumeGroup>
+
+    <volumeGroup>
+        <name>rerouting</name>
+        <indexMin>0</indexMin>
+        <indexMax>1</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,0</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>patch</name>
+        <indexMin>0</indexMin>
+        <indexMax>1</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,0</point>
+            <point>100,0</point>
+        </volume>
+    </volumeGroup>
+
 </volumeGroups>
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
index 782fe83..ddc8721 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
@@ -38,6 +38,9 @@
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework
 LOCAL_SRC_FILES := $(LOCAL_MODULE).in
+LOCAL_REQUIRED_MODULES := \
+    PolicySubsystem.xml\
+    PolicyClass.xml
 
 # external/parameter-framework prevents from using debug interface
 AUDIO_PATTERN = @TUNING_ALLOWED@
@@ -60,9 +63,7 @@
 LOCAL_VENDOR_MODULE := true
 LOCAL_REQUIRED_MODULES := \
     PolicySubsystem-CommonTypes.xml \
-    ProductStrategies.xml \
-    PolicySubsystem-Volume.xml \
-    libpolicy-subsystem \
+    ProductStrategies.xml
 
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
 LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
@@ -92,7 +93,7 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
+
 AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := \
     $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
 STRATEGIES_STRUCTURE_FILE := $(LOCAL_PATH)/common/Structure/$(LOCAL_MODULE).in
@@ -110,15 +111,27 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
-    PolicySubsystem-CommonTypes.xml \
-    PolicySubsystem-Volume.xml \
-    libpolicy-subsystem \
+LOCAL_REQUIRED_MODULES := PolicySubsystem-CommonTypes.xml
 
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
 LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE_STEM)
 include $(BUILD_PREBUILT)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := ParameterFrameworkConfigurationPolicy.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := parameter-framework
+LOCAL_SRC_FILES := $(LOCAL_MODULE).in
+LOCAL_REQUIRED_MODULES := \
+    PolicySubsystem-no-strategy.xml\
+    PolicyClass.xml
+AUDIO_VALUE = false
+LOCAL_POST_INSTALL_CMD := $(hide) sed -i -e 's|$(AUDIO_PATTERN)|$(AUDIO_VALUE)|g' $(TARGET_OUT_VENDOR_ETC)/$(LOCAL_MODULE_RELATIVE_PATH)/$(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
+
 endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
 
 ######### Policy PFW Settings - No Output #########
@@ -130,12 +143,6 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := \
-    audio_policy_engine_criteria.xml \
-    audio_policy_engine_criterion_types.xml \
-    PolicySubsystem-no-strategy.xml \
-    PolicyClass.xml \
-    ParameterFrameworkConfigurationPolicy.xml
 
 PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
 PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
@@ -143,9 +150,10 @@
 PFW_EDD_FILES := \
         $(LOCAL_PATH)/SettingsNoOutput/device_for_strategies.pfw \
         $(LOCAL_PATH)/Settings/device_for_input_source.pfw \
-        $(LOCAL_PATH)/Settings/volumes.pfw
-
+        $(LOCAL_PATH)/Settings/volumes.pfw        
+LOCAL_REQUIRED_MODULES := libpolicy-subsystem
 include $(BUILD_PFW_SETTINGS)
+
 endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
 ######### Policy PFW Settings - No Input #########
 ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
@@ -156,12 +164,6 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := \
-    audio_policy_engine_criteria.xml \
-    audio_policy_engine_criterion_types.xml \
-    PolicySubsystem-no-strategy.xml \
-    PolicyClass.xml \
-    ParameterFrameworkConfigurationPolicy.xml
 
 PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
 PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
@@ -169,7 +171,7 @@
 PFW_EDD_FILES := \
         $(LOCAL_PATH)/SettingsNoInput/device_for_input_source.pfw \
         $(LOCAL_PATH)/Settings/volumes.pfw
-
+LOCAL_REQUIRED_MODULES := libpolicy-subsystem
 include $(BUILD_PFW_SETTINGS)
 
 endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
index 20ca8e2..7304ec2 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
@@ -30,27 +30,16 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
+LOCAL_REQUIRED_MODULES := libpolicy-subsystem
 
 PFW_EDD_FILES := \
-        $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
-        $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
-        $(LOCAL_PATH)/../Settings/volumes.pfw
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-    $(PFW_EDD_FILES)
-
-LOCAL_REQUIRED_MODULES := \
-    PolicySubsystem.xml \
-    PolicyClass.xml \
-    audio_policy_engine_criteria.xml \
-    audio_policy_engine_criterion_types.xml \
-    ParameterFrameworkConfigurationPolicy.xml
+    $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
+    $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
+    $(LOCAL_PATH)/../Settings/volumes.pfw
 
 PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
 PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-
 PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-
 PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
 
 include $(BUILD_PFW_SETTINGS)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
index 8fa8f0a..f5eb7d1 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
@@ -30,27 +30,15 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
+LOCAL_REQUIRED_MODULES := libpolicy-subsystem
 
 PFW_EDD_FILES := \
-        $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
-        $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
-        $(LOCAL_PATH)/../Settings/volumes.pfw
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-    $(PFW_EDD_FILES)
-
-LOCAL_REQUIRED_MODULES := \
-    PolicySubsystem.xml \
-    PolicyClass.xml \
-    audio_policy_engine_criteria.xml \
-    audio_policy_engine_criterion_types.xml \
-    ParameterFrameworkConfigurationPolicy.xml
-
+    $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
+    $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
+    $(LOCAL_PATH)/../Settings/volumes.pfw
 PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
 PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-
 PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-
 PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
 
 include $(BUILD_PFW_SETTINGS)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
index d1845b8..0b20781 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
@@ -29,6 +29,7 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
+LOCAL_REQUIRED_MODULES := libpolicy-subsystem
 
 PFW_EDD_FILES := \
         $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
@@ -43,22 +44,9 @@
         $(LOCAL_PATH)/Settings/device_for_product_strategy_transmitted_through_speaker.pfw \
         $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
         $(LOCAL_PATH)/Settings/device_for_product_strategy_patch.pfw
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-    $(PFW_EDD_FILES)
-
-LOCAL_REQUIRED_MODULES := \
-    PolicySubsystem.xml \
-    PolicyClass.xml \
-    audio_policy_engine_criteria.xml \
-    audio_policy_engine_criterion_types.xml \
-    ParameterFrameworkConfigurationPolicy.xml
-
 PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
 PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-
 PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-
 PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
 
 include $(BUILD_PFW_SETTINGS)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index 4706d7d..b060524 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -1,7 +1,5 @@
 LOCAL_PATH := $(call my-dir)
 
-ifneq ($(USE_CUSTOM_PARAMETER_FRAMEWORK), true)
-
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
@@ -40,9 +38,6 @@
     libpfw_utility \
     libaudiopolicycomponents
 
-LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := libpolicy-subsystem
 
 include $(BUILD_SHARED_LIBRARY)
-
-endif # ifneq ($(USE_CUSTOM_PARAMETER_FRAMEWORK), true)
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index 0fb70a6..a63c858 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -101,8 +101,16 @@
         for criterion_name, values_list in addressCriteria.items():
             for criterion_type in criterion_types_root.findall('criterion_type'):
                 if criterion_type.get('name') == criterion_name:
-                    values_node = ET.SubElement(criterion_type, "values")
                     index = 0
+                    existing_values_node = criterion_type.find("values")
+                    if existing_values_node is not None:
+                        for existing_value in existing_values_node.findall('value'):
+                            if existing_value.get('numerical') == str(1 << index):
+                                index += 1
+                        values_node = existing_values_node
+                    else:
+                        values_node = ET.SubElement(criterion_type, "values")
+
                     for value in values_list:
                         value_node = ET.SubElement(values_node, "value", literal=value)
                         value_node.set('numerical', str(1 << index))
@@ -240,4 +248,4 @@
 
 # If this file is directly executed
 if __name__ == "__main__":
-    exit(main())
+    sys.exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
index ee70b26..af40602 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -136,4 +136,4 @@
 
 # If this file is directly executed
 if __name__ == "__main__":
-    exit(main())
+    sys.exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk b/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
index 2b86469..ac60ef7 100644
--- a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
+++ b/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
@@ -1,10 +1,13 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES += \
+    $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py \
+    $(PFW_TOPLEVEL_FILE) $(PFW_CRITERIA_FILE) $(PFW_CRITERION_TYPES_FILE)
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
 $(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): MY_TOOL := domainGeneratorPolicy.py
+$(LOCAL_BUILT_MODULE): MY_TOOL := $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py
 $(LOCAL_BUILT_MODULE): MY_TOPLEVEL_FILE := $(PFW_TOPLEVEL_FILE)
 $(LOCAL_BUILT_MODULE): MY_CRITERIA_FILE := $(PFW_CRITERIA_FILE)
 $(LOCAL_BUILT_MODULE): MY_TUNING_FILE := $(PFW_TUNING_FILE)
@@ -12,7 +15,7 @@
 $(LOCAL_BUILT_MODULE): MY_DOMAIN_FILES := $(PFW_DOMAIN_FILES)
 $(LOCAL_BUILT_MODULE): MY_SCHEMAS_DIR := $(PFW_SCHEMAS_DIR)
 $(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) domainGeneratorPolicy.py
+$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
 
 	"$(MY_TOOL)" --validate \
 		--toplevel-config "$(MY_TOPLEVEL_FILE)" \
diff --git a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
index 7929402..4dec9a2 100755
--- a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
+++ b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
@@ -129,7 +129,7 @@
                 criterion_values = []
 
                 values_node = criterion_types.find('values')
-                if values_node:
+                if values_node is not None:
                     for value in values_node.findall('value'):
                         criterion_values.append(value.get('literal'))
 
@@ -265,4 +265,4 @@
 
 # If this file is directly executed
 if __name__ == "__main__":
-    exit(main())
+    sys.exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
index eebdfd6..dab5a0f 100644
--- a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
+++ b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
@@ -1,15 +1,17 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES += \
+    $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py \
+    $(CRITERION_TYPES_FILE) $(AUDIO_POLICY_CONFIGURATION_FILE) \
+    $(ANDROID_AUDIO_BASE_HEADER_FILE)
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
 $(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(CRITERION_TYPES_FILE)
 $(LOCAL_BUILT_MODULE): MY_ANDROID_AUDIO_BASE_HEADER_FILE := $(ANDROID_AUDIO_BASE_HEADER_FILE)
 $(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_CONFIGURATION_FILE := $(AUDIO_POLICY_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TOOL := $(HOST_OUT)/bin/buildPolicyCriterionTypes.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) \
-    $(CRITERION_TYPES_FILE) \
-    $(ANDROID_AUDIO_BASE_HEADER_FILE)
+$(LOCAL_BUILT_MODULE): MY_CRITERION_TOOL := $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py
+$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
 
 	"$(MY_CRITERION_TOOL)" \
 		--androidaudiobaseheader "$(MY_ANDROID_AUDIO_BASE_HEADER_FILE)" \
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
index 72c938c..f2b1a19 100644
--- a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
+++ b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
@@ -1,15 +1,15 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES += \
+    $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py \
+    $(STRATEGIES_STRUCTURE_FILE) $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
 $(LOCAL_BUILT_MODULE): MY_STRATEGIES_STRUCTURE_FILE := $(STRATEGIES_STRUCTURE_FILE)
 $(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_PROVISION_TOOL := $(HOST_OUT)/bin/buildStrategiesStructureFile.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) \
-    buildStrategiesStructureFile.py \
-    $(STRATEGIES_STRUCTURE_FILE) \
-    $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
+$(LOCAL_BUILT_MODULE): MY_PROVISION_TOOL := $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py
+$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
 
 	"$(MY_PROVISION_TOOL)" \
 		--audiopolicyengineconfigurationfile "$(MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)" \
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 4135f01..04170ac 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -506,7 +506,9 @@
     const DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
     audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
-
+    sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
+    audio_devices_t availablePrimaryDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
+        primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
     uint32_t device = AUDIO_DEVICE_NONE;
 
     // when a call is active, force device selection to match source VOICE_COMMUNICATION
@@ -528,13 +530,6 @@
     }
 
     switch (inputSource) {
-    case AUDIO_SOURCE_VOICE_UPLINK:
-      if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
-          device = AUDIO_DEVICE_IN_VOICE_CALL;
-          break;
-      }
-      break;
-
     case AUDIO_SOURCE_DEFAULT:
     case AUDIO_SOURCE_MIC:
     if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
@@ -558,9 +553,7 @@
         // to voice call path.
         if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
                 (availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
-            sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
-            availableDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
-                    primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
+            availableDeviceTypes = availablePrimaryDeviceTypes;
         }
 
         switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
@@ -597,6 +590,9 @@
     case AUDIO_SOURCE_VOICE_RECOGNITION:
     case AUDIO_SOURCE_UNPROCESSED:
     case AUDIO_SOURCE_HOTWORD:
+        if (inputSource == AUDIO_SOURCE_HOTWORD) {
+            availableDeviceTypes = availablePrimaryDeviceTypes;
+        }
         if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO &&
                 availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
             device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
@@ -622,6 +618,7 @@
         break;
     case AUDIO_SOURCE_VOICE_DOWNLINK:
     case AUDIO_SOURCE_VOICE_CALL:
+    case AUDIO_SOURCE_VOICE_UPLINK:
         if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
             device = AUDIO_DEVICE_IN_VOICE_CALL;
         }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index af29f87..7011ef7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -142,18 +142,7 @@
                     __func__, device->toString().c_str(), encodedFormat);
 
             // register new device as available
-            index = mAvailableOutputDevices.add(device);
-            if (index >= 0) {
-                sp<HwModule> module = mHwModules.getModuleForDevice(device, encodedFormat);
-                if (module == 0) {
-                    ALOGD("setDeviceConnectionState() could not find HW module for device %s",
-                          device->toString().c_str());
-                    mAvailableOutputDevices.remove(device);
-                    return INVALID_OPERATION;
-                }
-                ALOGV("setDeviceConnectionState() module name=%s", module->getName());
-                mAvailableOutputDevices[index]->attach(module);
-            } else {
+            if (mAvailableOutputDevices.add(device) < 0) {
                 return NO_MEMORY;
             }
 
@@ -284,8 +273,6 @@
 
     // handle input devices
     if (audio_is_input_device(deviceType)) {
-        SortedVector <audio_io_handle_t> inputs;
-
         ssize_t index = mAvailableInputDevices.indexOf(device);
         switch (state)
         {
@@ -295,18 +282,18 @@
                 ALOGW("%s() device already connected: %s", __func__, device->toString().c_str());
                 return INVALID_OPERATION;
             }
-            sp<HwModule> module = mHwModules.getModuleForDevice(device, AUDIO_FORMAT_DEFAULT);
-            if (module == NULL) {
-                ALOGW("setDeviceConnectionState(): could not find HW module for device %s",
-                      device->toString().c_str());
-                return INVALID_OPERATION;
+
+            if (mAvailableInputDevices.add(device) < 0) {
+                return NO_MEMORY;
             }
 
             // Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
             // parameters on newly connected devices (instead of opening the inputs...)
             broadcastDeviceConnectionState(device, state);
 
-            if (checkInputsForDevice(device, state, inputs) != NO_ERROR) {
+            if (checkInputsForDevice(device, state) != NO_ERROR) {
+                mAvailableInputDevices.remove(device);
+
                 broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
 
                 mHwModules.cleanUpForDevice(device);
@@ -314,9 +301,6 @@
                 return INVALID_OPERATION;
             }
 
-            if (mAvailableInputDevices.add(device) < 0) {
-                return NO_MEMORY;
-            }
         } break;
 
         // handle input device disconnection
@@ -331,8 +315,9 @@
             // Set Disconnect to HALs
             broadcastDeviceConnectionState(device, state);
 
-            checkInputsForDevice(device, state, inputs);
             mAvailableInputDevices.remove(device);
+
+            checkInputsForDevice(device, state);
         } break;
 
         default:
@@ -343,7 +328,7 @@
         // Propagate device availability to Engine
         setEngineDeviceConnectionState(device, state);
 
-        closeAllInputs();
+        checkCloseInputs();
         // As the input device list can impact the output device selection, update
         // getDeviceForStrategy() cache
         updateDevicesAndOutputs();
@@ -2360,26 +2345,39 @@
     releaseInput(portId);
 }
 
-void AudioPolicyManager::closeAllInputs() {
-    bool patchRemoved = false;
-
-    for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
-        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(input_index);
-        ssize_t patch_index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
-        if (patch_index >= 0) {
-            sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patch_index);
-            (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
-            mAudioPatches.removeItemsAt(patch_index);
-            patchRemoved = true;
+void AudioPolicyManager::checkCloseInputs() {
+    // After connecting or disconnecting an input device, close input if:
+    // - it has no client (was just opened to check profile)  OR
+    // - none of its supported devices are connected anymore OR
+    // - one of its clients cannot be routed to one of its supported
+    // devices anymore. Otherwise update device selection
+    std::vector<audio_io_handle_t> inputsToClose;
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
+        if (input->clientsList().size() == 0
+                || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) {
+            inputsToClose.push_back(mInputs.keyAt(i));
+        } else {
+            bool close = false;
+            for (const auto& client : input->clientsList()) {
+                sp<DeviceDescriptor> device =
+                    mEngine->getInputDeviceForAttributes(client->attributes());
+                if (!input->supportedDevices().contains(device)) {
+                    close = true;
+                    break;
+                }
+            }
+            if (close) {
+                inputsToClose.push_back(mInputs.keyAt(i));
+            } else {
+                setInputDevice(input->mIoHandle, getNewInputDevice(input));
+            }
         }
-        inputDesc->close();
     }
-    mInputs.clear();
-    SoundTrigger::setCaptureState(false);
-    nextAudioPortGeneration();
 
-    if (patchRemoved) {
-        mpClientInterface->onAudioPatchListUpdate();
+    for (const audio_io_handle_t handle : inputsToClose) {
+        ALOGV("%s closing input %d", __func__, handle);
+        closeInput(handle);
     }
 }
 
@@ -2481,7 +2479,7 @@
         // HW Gain management, do not change the volume
         bool applyVolume = false;
         if (desc->useHwGain()) {
-            if (!(desc->isActive(group) || isInCall())) {
+            if (!(desc->isActive(toVolumeSource(group)) || isInCall())) {
                 continue;
             }
             for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
@@ -2675,6 +2673,7 @@
     }
 
     if (output != mMusicEffectOutput) {
+        mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
         mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
         mMusicEffectOutput = output;
     }
@@ -2712,7 +2711,6 @@
     if (mEffects.getEffect(id) == nullptr) {
         return INVALID_OPERATION;
     }
-
     if (mEffects.isEffectEnabled(id)) {
         ALOGW("%s effect %d enabled", __FUNCTION__, id);
         setEffectEnabled(id, false);
@@ -2720,6 +2718,16 @@
     return mEffects.unregisterEffect(id);
 }
 
+void AudioPolicyManager::cleanUpEffectsForIo(audio_io_handle_t io)
+{
+    EffectDescriptorCollection effects = mEffects.getEffectsForIo(io);
+    for (size_t i = 0; i < effects.size(); i++) {
+        ALOGW("%s removing stale effect %s, id %d on closed IO %d",
+              __func__, effects.valueAt(i)->mDesc.name, effects.keyAt(i), io);
+        unregisterEffect(effects.keyAt(i));
+    }
+}
+
 status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled)
 {
     sp<EffectDescriptor> effect = mEffects.getEffect(id);
@@ -2734,6 +2742,13 @@
     return status;
 }
 
+
+status_t AudioPolicyManager::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+   mEffects.moveEffects(ids, io);
+   return NO_ERROR;
+}
+
 bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
 {
     return mOutputs.isActive(toVolumeSource(stream), inPastMs);
@@ -4105,15 +4120,8 @@
 void AudioPolicyManager::setAppState(uid_t uid, app_state_t state)
 {
     ALOGV("%s(uid:%d, state:%d)", __func__, uid, state);
-
     for (size_t i = 0; i < mInputs.size(); i++) {
-        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
-        RecordClientVector clients = inputDesc->clientsList(false /*activeOnly*/);
-        for (const auto& client : clients) {
-            if (uid == client->uid()) {
-                client->setAppState(state);
-            }
-        }
+        mInputs.valueAt(i)->setAppState(uid, state);
     }
 }
 
@@ -4709,8 +4717,7 @@
 }
 
 status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor>& device,
-                                                  audio_policy_dev_state_t state,
-                                                  SortedVector<audio_io_handle_t>& inputs)
+                                                  audio_policy_dev_state_t state)
 {
     sp<AudioInputDescriptor> desc;
 
@@ -4720,16 +4727,7 @@
     }
 
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
-        // first list already open inputs that can be routed to this device
-        for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
-            desc = mInputs.valueAt(input_index);
-            if (desc->mProfile->supportsDeviceTypes(device->type())) {
-                ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
-               inputs.add(mInputs.keyAt(input_index));
-            }
-        }
-
-        // then look for input profiles that can be routed to this device
+        // look for input profiles that can be routed to this device
         SortedVector< sp<IOProfile> > profiles;
         for (const auto& hwModule : mHwModules) {
             for (size_t profile_index = 0;
@@ -4745,8 +4743,9 @@
             }
         }
 
-        if (profiles.isEmpty() && inputs.isEmpty()) {
-            ALOGW("%s: No input available for device %s", __func__, device->toString().c_str());
+        if (profiles.isEmpty()) {
+            ALOGW("%s: No input profile available for device %s",
+                __func__, device->toString().c_str());
             return BAD_VALUE;
         }
 
@@ -4799,7 +4798,7 @@
                     input = AUDIO_IO_HANDLE_NONE;
                 }
 
-                if (input != 0) {
+                if (input != AUDIO_IO_HANDLE_NONE) {
                     addInput(input, desc);
                 }
             } // endif input != 0
@@ -4810,7 +4809,6 @@
                 profiles.removeAt(profile_index);
                 profile_index--;
             } else {
-                inputs.add(input);
                 if (audio_device_is_digital(device->type())) {
                     device->importAudioPort(profile);
                 }
@@ -4824,15 +4822,6 @@
         }
     } else {
         // Disconnect
-        // check if one opened input is not needed any more after disconnecting one device
-        for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
-            desc = mInputs.valueAt(input_index);
-            if (!mAvailableInputDevices.containsAtLeastOne(desc->supportedDevices())) {
-                ALOGV("checkInputsForDevice(): disconnecting adding input %d",
-                      mInputs.keyAt(input_index));
-                inputs.add(mInputs.keyAt(input_index));
-            }
-        }
         // Clear any profiles associated with the disconnected device.
         for (const auto& hwModule : mHwModules) {
             for (size_t profile_index = 0;
@@ -4924,6 +4913,8 @@
             setMsdPatch();
         }
     }
+
+    cleanUpEffectsForIo(output);
 }
 
 void AudioPolicyManager::closeInput(audio_io_handle_t input)
@@ -4955,6 +4946,8 @@
             mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
         SoundTrigger::setCaptureState(false);
     }
+
+    cleanUpEffectsForIo(input);
 }
 
 SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevices(
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index de447fb..8ca06e7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -142,7 +142,7 @@
         // indicates to the audio policy manager that the input stops being used.
         virtual status_t stopInput(audio_port_handle_t portId);
         virtual void releaseInput(audio_port_handle_t portId);
-        virtual void closeAllInputs();
+        virtual void checkCloseInputs();
         /**
          * @brief initStreamVolume: even if the engine volume files provides min and max, keep this
          * api for compatibility reason.
@@ -200,6 +200,7 @@
                                         int id);
         virtual status_t unregisterEffect(int id);
         virtual status_t setEffectEnabled(int id, bool enabled);
+        status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override;
 
         virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
         // return whether a stream is playing remotely, override to change the definition of
@@ -344,7 +345,7 @@
         }
         virtual const DeviceVector getAvailableOutputDevices() const
         {
-            return mAvailableOutputDevices.filterForEngine();
+            return mAvailableOutputDevices;
         }
         virtual const DeviceVector getAvailableInputDevices() const
         {
@@ -485,8 +486,7 @@
                                        SortedVector<audio_io_handle_t>& outputs);
 
         status_t checkInputsForDevice(const sp<DeviceDescriptor>& device,
-                                      audio_policy_dev_state_t state,
-                                      SortedVector<audio_io_handle_t>& inputs);
+                                      audio_policy_dev_state_t state);
 
         // close an output and its companion duplicating output.
         void closeOutput(audio_io_handle_t output);
@@ -869,6 +869,8 @@
                 int delayMs,
                 uid_t uid,
                 sp<AudioPatch> *patchDescPtr);
+
+        void cleanUpEffectsForIo(audio_io_handle_t io);
 };
 
 };
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 5748334..d51cc6e 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -172,6 +172,13 @@
     return af->moveEffects(session, src_output, dst_output);
 }
 
+void AudioPolicyService::AudioPolicyClient::setEffectSuspended(int effectId,
+                                audio_session_t sessionId,
+                                bool suspended)
+{
+    mAudioPolicyService->setEffectSuspended(effectId, sessionId, suspended);
+}
+
 status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch,
                                                                   audio_patch_handle_t *handle,
                                                                   int delayMs)
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 6ad01f7..dcf093b 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -225,6 +225,8 @@
                          size_t *totSize);
 
     // protects access to mInputSources, mInputSessions, mOutputStreams, mOutputSessions
+    // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+    // those can call back into AudioPolicyService methods and try to acquire the mutex
     Mutex mLock;
     // Automatic input effects are configured per audio_source_t
     KeyedVector< audio_source_t, EffectDescVector* > mInputSources;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 2eb272e..2e47eb6 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -797,7 +797,7 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
-    Mutex::Autolock _l(mEffectsLock);
+    Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
     return mAudioPolicyManager->registerEffect(desc, io, strategy, session, id);
 }
@@ -807,7 +807,7 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
-    Mutex::Autolock _l(mEffectsLock);
+    Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
     return mAudioPolicyManager->unregisterEffect(id);
 }
@@ -817,11 +817,21 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
-    Mutex::Autolock _l(mEffectsLock);
+    Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
     return mAudioPolicyManager->setEffectEnabled(id, enabled);
 }
 
+status_t AudioPolicyService::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->moveEffectsToIo(ids, io);
+}
+
 bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
 {
     if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
@@ -973,8 +983,6 @@
         return false;
     }
     Mutex::Autolock _l(mLock);
-    Mutex::Autolock _le(mEffectsLock); // isOffloadSupported queries for
-                                      // non-offloadable effects
     AutoCallerClear acc;
     return mAudioPolicyManager->isOffloadSupported(info);
 }
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index f63fa81..5389c08 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1196,6 +1196,17 @@
                             data->mPatchHandle, data->mSource);
                     mLock.lock();
                     } break;
+                case SET_EFFECT_SUSPENDED: {
+                    SetEffectSuspendedData *data = (SetEffectSuspendedData *)command->mParam.get();
+                    ALOGV("AudioCommandThread() processing set effect suspended");
+                    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+                    if (af != 0) {
+                        mLock.unlock();
+                        af->setEffectSuspended(data->mEffectId, data->mSessionId, data->mSuspended);
+                        mLock.lock();
+                    }
+                    } break;
+
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                 }
@@ -1327,6 +1338,23 @@
     return sendCommand(command, delayMs);
 }
 
+void AudioPolicyService::AudioCommandThread::setEffectSuspendedCommand(int effectId,
+                                                                       audio_session_t sessionId,
+                                                                       bool suspended)
+{
+    sp<AudioCommand> command = new AudioCommand();
+    command->mCommand = SET_EFFECT_SUSPENDED;
+    sp<SetEffectSuspendedData> data = new SetEffectSuspendedData();
+    data->mEffectId = effectId;
+    data->mSessionId = sessionId;
+    data->mSuspended = suspended;
+    command->mParam = data;
+    ALOGV("AudioCommandThread() adding set suspended effectId %d sessionId %d suspended %d",
+        effectId, sessionId, suspended);
+    sendCommand(command);
+}
+
+
 void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_port_handle_t portId)
 {
     sp<AudioCommand> command = new AudioCommand();
@@ -1707,6 +1735,14 @@
     return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
 }
 
+void AudioPolicyService::setEffectSuspended(int effectId,
+                                            audio_session_t sessionId,
+                                            bool suspended)
+{
+    mAudioCommandThread->setEffectSuspendedCommand(effectId, sessionId, suspended);
+}
+
+
 extern "C" {
 audio_module_handle_t aps_load_hw_module(void *service __unused,
                                              const char *name);
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 189322f..6c19912 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -134,6 +134,7 @@
                                     int id);
     virtual status_t unregisterEffect(int id);
     virtual status_t setEffectEnabled(int id, bool enabled);
+    status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override;
     virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
     virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
     virtual bool isSourceActive(audio_source_t source) const;
@@ -292,6 +293,9 @@
 
             void onAudioVolumeGroupChanged(volume_group_t group, int flags);
             void doOnAudioVolumeGroupChanged(volume_group_t group, int flags);
+            void setEffectSuspended(int effectId,
+                                    audio_session_t sessionId,
+                                    bool suspended);
 
 private:
                         AudioPolicyService() ANDROID_API;
@@ -426,7 +430,8 @@
             CHANGED_AUDIOVOLUMEGROUP,
             SET_AUDIOPORT_CONFIG,
             DYN_POLICY_MIX_STATE_UPDATE,
-            RECORDING_CONFIGURATION_UPDATE
+            RECORDING_CONFIGURATION_UPDATE,
+            SET_EFFECT_SUSPENDED,
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -469,6 +474,9 @@
                                                     std::vector<effect_descriptor_t> effects,
                                                     audio_patch_handle_t patchHandle,
                                                     audio_source_t source);
+                    void        setEffectSuspendedCommand(int effectId,
+                                                          audio_session_t sessionId,
+                                                          bool suspended);
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
     private:
         class AudioCommandData;
@@ -566,6 +574,13 @@
             audio_source_t mSource;
         };
 
+        class SetEffectSuspendedData : public AudioCommandData {
+        public:
+            int mEffectId;
+            audio_session_t mSessionId;
+            bool mSuspended;
+        };
+
         Mutex   mLock;
         Condition mWaitWorkCV;
         Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -651,6 +666,10 @@
                                          audio_io_handle_t srcOutput,
                                          audio_io_handle_t dstOutput);
 
+                void setEffectSuspended(int effectId,
+                                        audio_session_t sessionId,
+                                        bool suspended) override;
+
         /* Create a patch between several source and sink ports */
         virtual status_t createAudioPatch(const struct audio_patch *patch,
                                            audio_patch_handle_t *handle,
@@ -810,7 +829,6 @@
 
     mutable Mutex mLock;    // prevents concurrent access to AudioPolicy manager functions changing
                             // device connection state  or routing
-    mutable Mutex mEffectsLock; // serialize access to Effect state within APM.
     // Note: lock acquisition order is always mLock > mEffectsLock:
     // mLock protects AudioPolicyManager methods that can call into audio flinger
     // and possibly back in to audio policy service and acquire mEffectsLock.
@@ -824,6 +842,8 @@
     DefaultKeyedVector< int64_t, sp<NotificationClient> >    mNotificationClients;
     Mutex mNotificationClientsLock;  // protects mNotificationClients
     // Manage all effects configured in audio_effects.conf
+    // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+    // those can call back into AudioPolicyService methods and try to acquire the mutex
     sp<AudioPolicyEffects> mAudioPolicyEffects;
     audio_mode_t mPhoneState;
 
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 8854eb2..e4c64e5 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -84,6 +84,9 @@
                                         std::vector<effect_descriptor_t> effects __unused,
                                         audio_patch_handle_t patchHandle __unused,
                                         audio_source_t source __unused) override { }
+    void setEffectSuspended(int effectId __unused,
+                            audio_session_t sessionId __unused,
+                            bool suspended __unused) {}
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index cca4049..fc6d6be 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -973,11 +973,14 @@
 
     // Make sure the UID is in an active state to use the camera
     if (!mUidPolicy->isUidActive(callingUid, String16(clientName8))) {
+        int32_t procState = mUidPolicy->getProcState(callingUid);
         ALOGE("Access Denial: can't use the camera from an idle UID pid=%d, uid=%d",
             clientPid, clientUid);
         return STATUS_ERROR_FMT(ERROR_DISABLED,
-                "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" from background",
-                clientName8.string(), clientUid, clientPid, cameraId.string());
+                "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" from background ("
+                "calling UID %d proc state %" PRId32 ")",
+                clientName8.string(), clientUid, clientPid, cameraId.string(),
+                callingUid, procState);
     }
 
     // If sensor privacy is enabled then prevent access to the camera
@@ -1635,6 +1638,11 @@
         }
     }
 
+    int clientPid = CameraThreadState::getCallingPid();
+    const char *id_cstr = id.c_str();
+    const char *torchState = enabled ? "on" : "off";
+    ALOGI("Torch for camera id %s turned %s for client PID %d", id_cstr, torchState, clientPid);
+    logTorchEvent(id_cstr, torchState , clientPid);
     return Status::ok();
 }
 
@@ -2119,6 +2127,12 @@
             cameraId, clientPackage, clientPid, reason));
 }
 
+void CameraService::logTorchEvent(const char* cameraId, const char *torchState, int clientPid) {
+    // Log torch event
+    logEvent(String8::format("Torch for camera id %s turned %s for client PID %d", cameraId,
+            torchState, clientPid));
+}
+
 void CameraService::logUserSwitch(const std::set<userid_t>& oldUserIds,
         const std::set<userid_t>& newUserIds) {
     String8 newUsers = toString(newUserIds);
@@ -2736,6 +2750,19 @@
     return active;
 }
 
+int32_t CameraService::UidPolicy::getProcState(uid_t uid) {
+    Mutex::Autolock _l(mUidLock);
+    return getProcStateLocked(uid);
+}
+
+int32_t CameraService::UidPolicy::getProcStateLocked(uid_t uid) {
+    int32_t procState = ActivityManager::PROCESS_STATE_UNKNOWN;
+    if (mMonitoredUids.find(uid) != mMonitoredUids.end()) {
+        procState = mMonitoredUids[uid].first;
+    }
+    return procState;
+}
+
 void CameraService::UidPolicy::UidPolicy::addOverrideUid(uid_t uid,
         String16 callingPackage, bool active) {
     updateOverrideUid(uid, callingPackage, active, true);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 4bcdeb2..b8cec2c 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -542,6 +542,7 @@
         void unregisterSelf();
 
         bool isUidActive(uid_t uid, String16 callingPackage);
+        int32_t getProcState(uid_t uid);
 
         void onUidGone(uid_t uid, bool disabled);
         void onUidActive(uid_t uid);
@@ -558,6 +559,7 @@
         virtual void binderDied(const wp<IBinder> &who);
     private:
         bool isUidActiveLocked(uid_t uid, String16 callingPackage);
+        int32_t getProcStateLocked(uid_t uid);
         void updateOverrideUid(uid_t uid, String16 callingPackage, bool active, bool insert);
 
         Mutex mUidLock;
@@ -746,6 +748,11 @@
             const char* reason);
 
     /**
+     * Add an event log message when a client calls setTorchMode succesfully.
+     */
+    void logTorchEvent(const char* cameraId, const char *torchState, int clientPid);
+
+    /**
      * Add an event log message that the current device user has been switched.
      */
     void logUserSwitch(const std::set<userid_t>& oldUserIds,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index bc0dafe..415b2d8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -132,13 +132,24 @@
     bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
     if (isLogical) {
         for (auto& physicalId : physicalCameraIds) {
-            res = manager->getCameraCharacteristics(physicalId, &mPhysicalDeviceInfoMap[physicalId]);
+            res = manager->getCameraCharacteristics(
+                    physicalId, &mPhysicalDeviceInfoMap[physicalId]);
             if (res != OK) {
                 SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
                         physicalId.c_str(), strerror(-res), res);
                 session->close();
                 return res;
             }
+
+            if (DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId])) {
+                mDistortionMappers[physicalId].setupStaticInfo(mPhysicalDeviceInfoMap[physicalId]);
+                if (res != OK) {
+                    SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
+                            "correction", physicalId.c_str());
+                    session->close();
+                    return res;
+                }
+            }
         }
     }
 
@@ -308,7 +319,7 @@
     }
 
     if (DistortionMapper::isDistortionSupported(mDeviceInfo)) {
-        res = mDistortionMapper.setupStaticInfo(mDeviceInfo);
+        res = mDistortionMappers[mId.c_str()].setupStaticInfo(mDeviceInfo);
         if (res != OK) {
             SET_ERR_L("Unable to read necessary calibration fields for distortion correction");
             return res;
@@ -3503,12 +3514,27 @@
     }
 
     // Fix up some result metadata to account for HAL-level distortion correction
-    status_t res = mDistortionMapper.correctCaptureResult(&captureResult.mMetadata);
+    status_t res =
+            mDistortionMappers[mId.c_str()].correctCaptureResult(&captureResult.mMetadata);
     if (res != OK) {
         SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
                 frameNumber, strerror(res), res);
         return;
     }
+    for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+        String8 cameraId8(physicalMetadata.mPhysicalCameraId);
+        if (mDistortionMappers.find(cameraId8.c_str()) == mDistortionMappers.end()) {
+            continue;
+        }
+        res = mDistortionMappers[cameraId8.c_str()].correctCaptureResult(
+                &physicalMetadata.mPhysicalCameraMetadata);
+        if (res != OK) {
+            SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
+                    frameNumber, strerror(res), res);
+            return;
+        }
+    }
+
     // Fix up result metadata for monochrome camera.
     res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
     if (res != OK) {
@@ -4278,12 +4304,13 @@
         // Start scan at i, with the assumption that the stream order matches
         size_t realIdx = i;
         bool found = false;
-        for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
+        size_t halStreamCount = finalConfiguration.streams.size();
+        for (size_t idx = 0; idx < halStreamCount; idx++) {
             if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
                 found = true;
                 break;
             }
-            realIdx = (realIdx >= finalConfiguration.streams.size()) ? 0 : realIdx + 1;
+            realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
         }
         if (!found) {
             ALOGE("%s: Stream %d not found in stream configuration response from HAL",
@@ -5481,13 +5508,21 @@
                 // Correct metadata regions for distortion correction if enabled
                 sp<Camera3Device> parent = mParent.promote();
                 if (parent != nullptr) {
-                    res = parent->mDistortionMapper.correctCaptureRequest(
-                        &(captureRequest->mSettingsList.begin()->metadata));
-                    if (res != OK) {
-                        SET_ERR("RequestThread: Unable to correct capture requests "
-                                "for lens distortion for request %d: %s (%d)",
-                                halRequest->frame_number, strerror(-res), res);
-                        return INVALID_OPERATION;
+                    List<PhysicalCameraSettings>::iterator it;
+                    for (it = captureRequest->mSettingsList.begin();
+                            it != captureRequest->mSettingsList.end(); it++) {
+                        if (parent->mDistortionMappers.find(it->cameraId) ==
+                                parent->mDistortionMappers.end()) {
+                            continue;
+                        }
+                        res = parent->mDistortionMappers[it->cameraId].correctCaptureRequest(
+                            &(it->metadata));
+                        if (res != OK) {
+                            SET_ERR("RequestThread: Unable to correct capture requests "
+                                    "for lens distortion for request %d: %s (%d)",
+                                    halRequest->frame_number, strerror(-res), res);
+                            return INVALID_OPERATION;
+                        }
                     }
                 }
             }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index d3bb212..f8245df 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1250,8 +1250,10 @@
     /**
      * Distortion correction support
      */
-
-    camera3::DistortionMapper mDistortionMapper;
+    // Map from camera IDs to its corresponding distortion mapper. Only contains
+    // 1 ID if the device isn't a logical multi-camera. Otherwise contains both
+    // logical camera and its physical subcameras.
+    std::unordered_map<std::string, camera3::DistortionMapper> mDistortionMappers;
 
     // Debug tracker for metadata tag value changes
     // - Enabled with the -m <taglist> option to dumpsys, such as
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 1c77581..acb8b3c 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -491,8 +491,11 @@
      * sets the mBufferManager if device version is > HAL3.2, which guarantees that the buffer
      * manager setup is skipped in below code. Note that HAL3.2 is also excluded here, as some
      * HAL3.2 devices may not support the dynamic buffer registeration.
+     * Also Camera3BufferManager does not support display/texture streams as they have its own
+     * buffer management logic.
      */
-    if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID) {
+    if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID &&
+            !(isConsumedByHWComposer() || isConsumedByHWTexture())) {
         uint64_t consumerUsage = 0;
         getEndpointUsage(&consumerUsage);
         StreamInfo streamInfo(
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index a5db031..d91b788 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -33,11 +33,12 @@
 
 extern "C" void RegisterCodecServices();
 
-int main(int argc __unused, char** /*argv*/)
+int main(int argc __unused, char** argv)
 {
     LOG(INFO) << "media swcodec service starting";
     signal(SIGPIPE, SIG_IGN);
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
+    strcpy(argv[0], "media.swcodec");
 
     ::android::hardware::configureRpcThreadpool(64, false);
 
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 845f84b..d9c4045 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -45,6 +45,7 @@
 exit_group: 1
 rt_sigreturn: 1
 ugetrlimit: 1
+readlink: 1
 readlinkat: 1
 _llseek: 1
 fstatfs64: 1
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 7264a9b..83704ba 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -101,7 +101,7 @@
 aaudio_result_t
 AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
     aaudio_result_t result = AAUDIO_OK;
-    ALOGV("registerClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGV("registerClientStream(%d,)\n", pid);
     std::lock_guard<std::mutex> lock(mLock);
     sp<NotificationClient> notificationClient = mNotificationClients[pid];
     if (notificationClient == 0) {
@@ -118,27 +118,23 @@
 aaudio_result_t
 AAudioClientTracker::unregisterClientStream(pid_t pid,
                                             sp<AAudioServiceStreamBase> serviceStream) {
-    ALOGV("unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGV("unregisterClientStream(%d,)\n", pid);
     std::lock_guard<std::mutex> lock(mLock);
     auto it = mNotificationClients.find(pid);
     if (it != mNotificationClients.end()) {
-        ALOGV("unregisterClientStream(%d, %p) found NotificationClient\n",
-              pid, serviceStream.get());
+        ALOGV("unregisterClientStream(%d,) found NotificationClient\n", pid);
         it->second->unregisterClientStream(serviceStream);
     } else {
-        ALOGE("unregisterClientStream(%d, %p) missing NotificationClient\n",
-              pid, serviceStream.get());
+        ALOGE("unregisterClientStream(%d,) missing NotificationClient\n", pid);
     }
     return AAUDIO_OK;
 }
 
 AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
         : mProcessId(pid) {
-    //ALOGD("NotificationClient(%d) created %p\n", pid, this);
 }
 
 AAudioClientTracker::NotificationClient::~NotificationClient() {
-    //ALOGD("~NotificationClient() destroyed %p\n", this);
 }
 
 int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 2fbaeb4..e6a8375 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -132,11 +132,10 @@
 
     if (result != AAUDIO_OK) {
         serviceStream.clear();
-        ALOGW("openStream(): failed, return %d = %s", result, AAudio_convertResultToText(result));
         return result;
     } else {
         aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
-        ALOGD("openStream(): handle = 0x%08X", handle);
+        ALOGV("openStream(): handle = 0x%08X", handle);
         serviceStream->setHandle(handle);
         pid_t pid = request.getProcessId();
         AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 4dfb62a..553754e 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -90,7 +90,8 @@
     std::lock_guard<std::mutex> lock(mLockStreams);
     mConnected.store(false);
     for (const auto& stream : mRegisteredStreams) {
-        ALOGD("disconnectRegisteredStreams() stop and disconnect %p", stream.get());
+        ALOGD("disconnectRegisteredStreams() stop and disconnect port %d",
+              stream->getPortHandle());
         stream->stop();
         stream->disconnect();
     }
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 3616fa2..a2f66a5 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -61,7 +61,7 @@
 
     virtual aaudio_result_t startClient(const android::AudioClient& client,
                                         audio_port_handle_t *clientHandle) {
-        ALOGD("AAudioServiceEndpoint::startClient(%p, ...) AAUDIO_ERROR_UNAVAILABLE", &client);
+        ALOGD("AAudioServiceEndpoint::startClient(...) AAUDIO_ERROR_UNAVAILABLE");
         return AAUDIO_ERROR_UNAVAILABLE;
     }
 
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index fbf7d10..447f32c 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -163,7 +163,9 @@
     ALOGD("%s() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
           __func__, mMmapClient.clientUid,  mMmapClient.clientPid, mPortHandle);
     if (status != OK) {
-        ALOGE("%s() - openMmapStream() returned status %d",  __func__, status);
+        // This can happen if the resource is busy or the config does
+        // not match the hardware.
+        ALOGD("%s() - openMmapStream() returned status %d",  __func__, status);
         return AAUDIO_ERROR_UNAVAILABLE;
     }
 
@@ -196,9 +198,9 @@
         result = AAUDIO_ERROR_UNAVAILABLE;
         goto error;
     } else {
-        ALOGD("%s() createMmapBuffer() returned = %d, buffer_size = %d, burst_size %d"
+        ALOGD("%s() createMmapBuffer() buffer_size = %d fr, burst_size %d fr"
                       ", Sharable FD: %s",
-              __func__, status,
+              __func__,
               mMmapBufferinfo.buffer_size_frames,
               mMmapBufferinfo.burst_size_frames,
               isBufferShareable ? "Yes" : "No");
@@ -243,14 +245,13 @@
         burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
     } while (burstMicros < burstMinMicros);
 
-    ALOGD("%s() original burst = %d, minMicros = %d, to burst = %d\n",
+    ALOGD("%s() original burst = %d, minMicros = %d => burst = %d\n",
           __func__, mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
 
-    ALOGD("%s() actual rate = %d, channels = %d"
-          ", deviceId = %d, capacity = %d\n",
-          __func__, getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
+    ALOGD("%s() actual rate = %d, channels = %d, deviceId = %d\n",
+          __func__, getSampleRate(), getSamplesPerFrame(), deviceId);
 
-    ALOGD("%s() format = =x%08x, frame size = %d",
+    ALOGD("%s() format = 0x%08x, frame size = %d",
           __func__, getFormat(), calculateBytesPerFrame());
 
     return result;
@@ -262,7 +263,6 @@
 
 aaudio_result_t AAudioServiceEndpointMMAP::close() {
     if (mMmapStream != 0) {
-        ALOGD("%s() clear() endpoint", __func__);
         // Needs to be explicitly cleared or CTS will fail but it is not clear why.
         mMmapStream.clear();
         // Apparently the above close is asynchronous. An attempt to open a new device
@@ -284,7 +284,7 @@
     LOG_ALWAYS_FATAL_IF(tempHandle != mPortHandle,
                         "%s() port handle not expected to change from %d to %d",
                         __func__, mPortHandle, tempHandle);
-    ALOGV("%s(%p) mPortHandle = %d", __func__, stream.get(), mPortHandle);
+    ALOGV("%s() mPortHandle = %d", __func__, mPortHandle);
     return result;
 }
 
@@ -299,26 +299,20 @@
     mFramesTransferred.roundUp64(getBufferCapacity());
 
     // Use the port handle that was provided by openMmapStream().
-    ALOGV("%s(%p) mPortHandle = %d", __func__, stream.get(), mPortHandle);
+    ALOGV("%s() mPortHandle = %d", __func__, mPortHandle);
     return stopClient(mPortHandle);
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
                                                        audio_port_handle_t *clientHandle) {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-    ALOGD("%s(%p(uid=%d, pid=%d))", __func__, &client, client.clientUid, client.clientPid);
-    audio_port_handle_t originalHandle =  *clientHandle;
     status_t status = mMmapStream->start(client, clientHandle);
-    aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
-    ALOGD("%s() , portHandle %d => %d, returns %d", __func__, originalHandle, *clientHandle, result);
-    return result;
+    return AAudioConvert_androidToAAudioResult(status);
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
-    ALOGD("%s(portHandle = %d), called", __func__, clientHandle);
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
     aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
-    ALOGD("%s(portHandle = %d), returns %d", __func__, clientHandle, result);
     return result;
 }
 
@@ -371,7 +365,7 @@
     // TODO Do we really need a different volume for each channel?
     // We get called with an array filled with a single value!
     float volume = values[0];
-    ALOGD("%s(%p) volume[0] = %f", __func__, this, volume);
+    ALOGD("%s() volume[0] = %f", __func__, volume);
     std::lock_guard<std::mutex> lock(mLockStreams);
     for(const auto& stream : mRegisteredStreams) {
         stream->onVolumeChanged(volume);
@@ -379,7 +373,7 @@
 };
 
 void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
-    ALOGD("%s(%p) called with dev %d, old = %d", __func__, this, deviceId, getDeviceId());
+    ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
     if (getDeviceId() != AUDIO_PORT_HANDLE_NONE  && getDeviceId() != deviceId) {
         disconnectRegisteredStreams();
     }
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 1e1c552..bda4b90 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -43,7 +43,6 @@
 
 AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService)
         : mStreamInternalPlay(audioService, true) {
-    ALOGD("%s(%p) created", __func__, this);
     mStreamInternal = &mStreamInternalPlay;
 }
 
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 14742dd..2ca847a 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -111,7 +111,7 @@
               capacityInFrames, MAX_FRAMES_PER_BUFFER);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
-    ALOGD("calculateBufferCapacity() requested %d frames, actual = %d",
+    ALOGV("calculateBufferCapacity() requested %d frames, actual = %d",
           requestedCapacityFrames, capacityInFrames);
     return capacityInFrames;
 }
@@ -144,7 +144,7 @@
     if (getFormat() == AUDIO_FORMAT_DEFAULT) {
         setFormat(AUDIO_FORMAT_PCM_FLOAT);
     } else if (getFormat() != AUDIO_FORMAT_PCM_FLOAT) {
-        ALOGE("%s() audio_format_t mAudioFormat = %d, need FLOAT", __func__, getFormat());
+        ALOGD("%s() audio_format_t mAudioFormat = %d, need FLOAT", __func__, getFormat());
         result = AAUDIO_ERROR_INVALID_FORMAT;
         goto error;
     }
@@ -153,7 +153,7 @@
     if (getSampleRate() == AAUDIO_UNSPECIFIED) {
         setSampleRate(endpoint->getSampleRate());
     } else if (getSampleRate() != endpoint->getSampleRate()) {
-        ALOGE("%s() mSampleRate = %d, need %d",
+        ALOGD("%s() mSampleRate = %d, need %d",
               __func__, getSampleRate(), endpoint->getSampleRate());
         result = AAUDIO_ERROR_INVALID_RATE;
         goto error;
@@ -163,7 +163,7 @@
     if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
         setSamplesPerFrame(endpoint->getSamplesPerFrame());
     } else if (getSamplesPerFrame() != endpoint->getSamplesPerFrame()) {
-        ALOGE("%s() mSamplesPerFrame = %d, need %d",
+        ALOGD("%s() mSamplesPerFrame = %d, need %d",
               __func__, getSamplesPerFrame(), endpoint->getSamplesPerFrame());
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
@@ -190,9 +190,6 @@
         }
     }
 
-    ALOGD("%s() actual rate = %d, channels = %d, deviceId = %d",
-          __func__, getSampleRate(), getSamplesPerFrame(), endpoint->getDeviceId());
-
     result = endpoint->registerStream(keep);
     if (result != AAUDIO_OK) {
         goto error;
@@ -227,7 +224,7 @@
 {
     std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
     if (mAudioDataQueue == nullptr) {
-        ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
+        ALOGW("%s(): mUpMessageQueue null! - stream not open", __func__);
         return AAUDIO_ERROR_NULL;
     }
     // Gather information on the data queue.
@@ -262,7 +259,7 @@
     int64_t position = 0;
     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
     if (endpoint == nullptr) {
-        ALOGE("%s() has no endpoint", __func__);
+        ALOGW("%s() has no endpoint", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }