Merge "Accessing tee patches with holding the thread lock." into udc-qpr-dev
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 1bd3603..bd679e5 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -4487,8 +4487,8 @@
      * <p>The guaranteed stream combinations related to stream use case for a camera device with
      * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE</a>
      * capability is documented in the camera device
-     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">guideline</a>. The
-     * application is strongly recommended to use one of the guaranteed stream combinations.
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">guideline</a>. The application is strongly recommended to use one of the guaranteed stream
+     * combinations.
      * If the application creates a session with a stream combination not in the guaranteed
      * list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
      * the camera device may ignore some stream use cases due to hardware constraints
@@ -9866,9 +9866,10 @@
      * </ul>
      * <p><a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_AVAILABLE_STREAM_USE_CASES">CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES</a>
      * lists all of the supported stream use cases.</p>
-     * <p>Refer to <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for the
-     * mandatory stream combinations involving stream use cases, which can also be queried
-     * via <a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">MandatoryStreamCombination</a>.</p>
+     * <p>Refer to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">CameraDevice#stream-use-case-capability-additional-guaranteed-configurations</a>
+     * for the mandatory stream combinations involving stream use cases, which can also be
+     * queried via <a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">MandatoryStreamCombination</a>.</p>
      */
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE           = 19,
 
@@ -10728,7 +10729,8 @@
      * <p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
      * better.</p>
      * <p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
-     * {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+     * {@link ACameraDevice_createCaptureSession }
+     * documentation are guaranteed to be supported.</p>
      * <p>All <code>LIMITED</code> devices support the <code>BACKWARDS_COMPATIBLE</code> capability, indicating basic
      * support for color image capture. The only exception is that the device may
      * alternatively support only the <code>DEPTH_OUTPUT</code> capability, if it can only output depth
@@ -10754,7 +10756,8 @@
     /**
      * <p>This camera device is capable of supporting advanced imaging applications.</p>
      * <p>The stream configurations listed in the <code>FULL</code>, <code>LEGACY</code> and <code>LIMITED</code> tables in the
-     * {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+     * {@link ACameraDevice_createCaptureSession }
+     * documentation are guaranteed to be supported.</p>
      * <p>A <code>FULL</code> device will support below capabilities:</p>
      * <ul>
      * <li><code>BURST_CAPTURE</code> capability (ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
@@ -10781,7 +10784,9 @@
 
     /**
      * <p>This camera device is running in backward compatibility mode.</p>
-     * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are supported.</p>
+     * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the
+     * {@link ACameraDevice_createCaptureSession }
+     * documentation are supported.</p>
      * <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
      * post-processing, arbitrary cropping regions, and has relaxed performance constraints.
      * No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
@@ -10803,7 +10808,9 @@
      * <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
      * FULL-level capabilities.</p>
      * <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
-     * <code>LIMITED</code> tables in the {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+     * <code>LIMITED</code> tables in the
+     * {@link ACameraDevice_createCaptureSession }
+     * documentation are guaranteed to be supported.</p>
      * <p>The following additional capabilities are guaranteed to be supported:</p>
      * <ul>
      * <li><code>YUV_REPROCESSING</code> capability (ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index e18dd59..453a0d2 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -637,10 +637,6 @@
             if (encoder) {
                 attrs |= MediaCodecInfo::kFlagIsEncoder;
             }
-            if (codec.quirkSet.find("attribute::enforce-xml-capabilities") !=
-                codec.quirkSet.end()) {
-                attrs |= MediaCodecInfo::kFlagIsEnforceXmlCapabilities;
-            }
             if (trait.owner == "software") {
                 attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
             } else {
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index bd10e44..2377fc8 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -528,7 +528,7 @@
 ConversionResult<media::AudioTimestampInternal>
 legacy2aidl_AudioTimestamp_AudioTimestampInternal(const AudioTimestamp& legacy) {
     media::AudioTimestampInternal aidl;
-    aidl.position = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.mPosition));
+    aidl.position = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy.mPosition));
     aidl.sec = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy.mTime.tv_sec));
     aidl.nsec = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.mTime.tv_nsec));
     return aidl;
diff --git a/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl b/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl
index 8bbfb57..1f16525 100644
--- a/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl
@@ -22,8 +22,11 @@
  * {@hide}
  */
 parcelable AudioTimestampInternal {
-    /** A frame position in AudioTrack::getPosition() units. */
-    int position;
+    /**
+     * A frame position in AudioTrack::getPosition() units. Use 'long' to accommodate
+     * all values from 'uint32_t'.
+     */
+    long position;
     /** corresponding CLOCK_MONOTONIC when frame is expected to present. */
     long sec;
     int nsec;
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index b1b7e00..ae15190 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -32,6 +32,7 @@
 #include <utils/Log.h>
 
 #include "DeviceHalAidl.h"
+#include "EffectHalAidl.h"
 #include "StreamHalAidl.h"
 
 using aidl::android::aidl_utils::statusTFromBinderStatus;
@@ -882,25 +883,64 @@
     return OK;
 }
 
-status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
-        sp<EffectHalInterface> effect) {
+status_t DeviceHalAidl::addDeviceEffect(
+        const struct audio_port_config *device, sp<EffectHalInterface> effect) {
+    TIME_CHECK();
+    if (!mModule) return NO_INIT;
     if (!effect) {
         return BAD_VALUE;
     }
-    TIME_CHECK();
-    if (!mModule) return NO_INIT;
-    ALOGE("%s not implemented yet", __func__);
+    bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+                    device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
+    auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
+                    *device, isInput, 0));
+    if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
+        ALOGE("%s: provided port config is not a device port config: %s",
+                __func__, requestedPortConfig.toString().c_str());
+        return BAD_VALUE;
+    }
+    AudioPortConfig devicePortConfig;
+    bool created;
+    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+                    requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
+    Cleanups cleanups;
+    if (created) {
+        cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
+    }
+    auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
+                            devicePortConfig.id, aidlEffect->getIEffect())));
+    cleanups.disarmAll();
     return OK;
 }
-status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
-                            sp<EffectHalInterface> effect) {
+status_t DeviceHalAidl::removeDeviceEffect(
+        const struct audio_port_config *device, sp<EffectHalInterface> effect) {
+    TIME_CHECK();
+    if (!mModule) return NO_INIT;
     if (!effect) {
         return BAD_VALUE;
     }
-    TIME_CHECK();
-    if (!mModule) return NO_INIT;
-    ALOGE("%s not implemented yet", __func__);
-    return OK;
+    bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+                    device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
+    auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
+                    *device, isInput, 0));
+    if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
+        ALOGE("%s: provided port config is not a device port config: %s",
+                __func__, requestedPortConfig.toString().c_str());
+        return BAD_VALUE;
+    }
+    auto existingPortConfigIt = findPortConfig(
+            requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
+    if (existingPortConfigIt == mPortConfigs.end()) {
+        ALOGE("%s: could not find a configured device port for the config %s",
+                __func__, requestedPortConfig.toString().c_str());
+        return BAD_VALUE;
+    }
+    auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
+    return statusTFromBinderStatus(mModule->removeDeviceEffect(
+                    existingPortConfigIt->first, aidlEffect->getIEffect()));
 }
 
 status_t DeviceHalAidl::getMmapPolicyInfos(
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 03afbb7..74a8b51 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -149,9 +149,11 @@
     // List microphones
     status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones) override;
 
-    status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+    status_t addDeviceEffect(
+            const struct audio_port_config *device, sp<EffectHalInterface> effect) override;
 
-    status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+    status_t removeDeviceEffect(
+            const struct audio_port_config *device, sp<EffectHalInterface> effect) override;
 
     status_t getMmapPolicyInfos(media::audio::common::AudioMMapPolicyType policyType __unused,
                                 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 826461f..f96d419 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -32,6 +32,7 @@
 #include <util/CoreUtils.h>
 
 #include "DeviceHalHidl.h"
+#include "EffectHalHidl.h"
 #include "ParameterUtils.h"
 #include "StreamHalHidl.h"
 
@@ -523,30 +524,32 @@
 
 #if MAJOR_VERSION >= 6
 status_t DeviceHalHidl::addDeviceEffect(
-        audio_port_handle_t device, sp<EffectHalInterface> effect) {
+        const struct audio_port_config *device, sp<EffectHalInterface> effect) {
     TIME_CHECK();
     if (mDevice == 0) return NO_INIT;
+    auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
     return processReturn("addDeviceEffect", mDevice->addDeviceEffect(
-            static_cast<AudioPortHandle>(device), effect->effectId()));
+            static_cast<AudioPortHandle>(device->id), hidlEffect->effectId()));
 }
 #else
 status_t DeviceHalHidl::addDeviceEffect(
-        audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+        const struct audio_port_config *device __unused, sp<EffectHalInterface> effect __unused) {
     return INVALID_OPERATION;
 }
 #endif
 
 #if MAJOR_VERSION >= 6
 status_t DeviceHalHidl::removeDeviceEffect(
-        audio_port_handle_t device, sp<EffectHalInterface> effect) {
+        const struct audio_port_config *device, sp<EffectHalInterface> effect) {
     TIME_CHECK();
     if (mDevice == 0) return NO_INIT;
+    auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
     return processReturn("removeDeviceEffect", mDevice->removeDeviceEffect(
-            static_cast<AudioPortHandle>(device), effect->effectId()));
+            static_cast<AudioPortHandle>(device->id), hidlEffect->effectId()));
 }
 #else
 status_t DeviceHalHidl::removeDeviceEffect(
-        audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+        const struct audio_port_config *device __unused, sp<EffectHalInterface> effect __unused) {
     return INVALID_OPERATION;
 }
 #endif
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index c5addde..989c1f5 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -105,8 +105,10 @@
     // List microphones
     status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones) override;
 
-    status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
-    status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+    status_t addDeviceEffect(
+            const struct audio_port_config *device, sp<EffectHalInterface> effect) override;
+    status_t removeDeviceEffect(
+            const struct audio_port_config *device, sp<EffectHalInterface> effect) override;
 
     status_t getMmapPolicyInfos(
             media::audio::common::AudioMMapPolicyType policyType __unused,
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 52fed91..72aa7d8 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <csignal>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
@@ -72,14 +73,13 @@
 
 EffectConversionHelperAidl::EffectConversionHelperAidl(
         std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
-        int32_t sessionId, int32_t ioId, const Descriptor& desc)
+        int32_t sessionId, int32_t ioId, const Descriptor& desc, bool isProxy)
     : mSessionId(sessionId),
       mIoId(ioId),
       mDesc(desc),
       mEffect(std::move(effect)),
       mIsInputStream(mDesc.common.flags.type == Flags::Type::PRE_PROC),
-      mIsProxyEffect(mDesc.common.id.proxy.has_value() &&
-                     mDesc.common.id.proxy.value() == mDesc.common.id.uuid) {
+      mIsProxyEffect(isProxy) {
     mCommon.session = sessionId;
     mCommon.ioHandle = ioId;
     mCommon.input = mCommon.output = kDefaultAudioConfig;
@@ -195,11 +195,9 @@
                 statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn)));
 
         if (mIsProxyEffect) {
-            const auto& ret =
-                    std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam();
-            mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ);
-            mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ);
-            mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ);
+            mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
+            mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
+            mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
         } else {
             mStatusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
             mInputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
@@ -207,6 +205,7 @@
         }
 
         if (status_t status = updateEventFlags(); status != OK) {
+            ALOGV("%s closing at status %d", __func__, status);
             mEffect->close();
             return status;
         }
@@ -319,17 +318,25 @@
             mEffect->setParameter(Parameter::make<Parameter::deviceDescription>(aidlDevices))));
     return *static_cast<int32_t*>(pReplyData) = OK;
 }
+
 status_t EffectConversionHelperAidl::handleSetVolume(uint32_t cmdSize, const void* pCmdData,
-                                                     uint32_t* replySize __unused,
-                                                     void* pReplyData __unused) {
+                                                     uint32_t* replySize, void* pReplyData) {
     if (cmdSize != 2 * sizeof(uint32_t) || !pCmdData) {
         ALOGE("%s parameter invalid %u %p", __func__, cmdSize, pCmdData);
         return BAD_VALUE;
     }
-    Parameter::VolumeStereo volume = {.left = (float)(*(uint32_t*)pCmdData) / (1 << 24),
-                                      .right = (float)(*(uint32_t*)pCmdData + 1) / (1 << 24)};
+
+    constexpr uint32_t unityGain = 1 << 24;
+    Parameter::VolumeStereo volume = {.left = (float)(*(uint32_t*)pCmdData) / unityGain,
+                                      .right = (float)(*(uint32_t*)pCmdData + 1) / unityGain};
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
             mEffect->setParameter(Parameter::make<Parameter::volumeStereo>(volume))));
+
+    // write unity gain back if volume was successfully set
+    if (replySize && *replySize == 2 * sizeof(uint32_t) && pReplyData) {
+        constexpr uint32_t vol_ret[2] = {unityGain, unityGain};
+        memcpy(pReplyData, vol_ret, sizeof(vol_ret));
+    }
     return OK;
 }
 
@@ -346,14 +353,15 @@
         ALOGI("%s offload param offload %s ioHandle %d", __func__,
               offload->isOffload ? "true" : "false", offload->ioHandle);
         mCommon.ioHandle = offload->ioHandle;
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-                std::static_pointer_cast<EffectProxy>(mEffect)->setOffloadParam(offload)));
-        // update FMQs
-        const auto& ret = std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam();
-        mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ);
-        mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ);
-        mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ);
-        RETURN_STATUS_IF_ERROR(updateEventFlags());
+        const auto& effectProxy = std::static_pointer_cast<EffectProxy>(mEffect);
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(effectProxy->setOffloadParam(offload)));
+        // update FMQs if the effect instance already open
+        if (State state; effectProxy->getState(&state).isOk() && state != State::INIT) {
+            mStatusQ = effectProxy->getStatusMQ();
+            mInputQ = effectProxy->getInputMQ();
+            mOutputQ = effectProxy->getOutputMQ();
+            updateEventFlags();
+        }
     }
     return *static_cast<int32_t*>(pReplyData) = OK;
 }
@@ -401,17 +409,27 @@
 status_t EffectConversionHelperAidl::updateEventFlags() {
     status_t status = BAD_VALUE;
     EventFlag* efGroup = nullptr;
-    if (mStatusQ->isValid()) {
+    if (mStatusQ && mStatusQ->isValid()) {
         status = EventFlag::createEventFlag(mStatusQ->getEventFlagWord(), &efGroup);
         if (status != OK || !efGroup) {
             ALOGE("%s: create EventFlagGroup failed, ret %d, egGroup %p", __func__, status,
                   efGroup);
             status = (status == OK) ? BAD_VALUE : status;
         }
+    } else if (isBypassing()) {
+        // for effect with bypass (no processing) flag, it's okay to not have statusQ
+        return OK;
     }
+
     mEfGroup.reset(efGroup, EventFlagDeleter());
     return status;
 }
 
+bool EffectConversionHelperAidl::isBypassing() const {
+    return mEffect &&
+           (mDesc.common.flags.bypass ||
+            (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isBypassing()));
+}
+
 }  // namespace effect
 }  // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 0c682ff..7c8f11b 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -41,6 +41,7 @@
     std::shared_ptr<DataMQ> getInputMQ() { return mInputQ; }
     std::shared_ptr<DataMQ> getOutputMQ() { return mOutputQ; }
     std::shared_ptr<android::hardware::EventFlag> getEventFlagGroup() { return mEfGroup; }
+    bool isBypassing() const;
 
   protected:
     const int32_t mSessionId;
@@ -54,7 +55,7 @@
     EffectConversionHelperAidl(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc);
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxy);
 
     status_t handleSetParameter(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
                                 void* pReplyData);
diff --git a/media/libaudiohal/impl/EffectConversionHelperHidl.h b/media/libaudiohal/impl/EffectConversionHelperHidl.h
index 4371d12..ed696bf 100644
--- a/media/libaudiohal/impl/EffectConversionHelperHidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperHidl.h
@@ -19,9 +19,9 @@
 
 #include "ConversionHelperHidl.h"
 
-#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h)
+#include PATH(android/hardware/audio/effect/COMMON_TYPES_FILE_VERSION/types.h)
 
-using EffectResult = ::android::hardware::audio::effect::CPP_VERSION::Result;
+using EffectResult = ::android::hardware::audio::effect::COMMON_TYPES_CPP_VERSION::Result;
 
 namespace android {
 
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index faf5f45..e4c3309 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -61,12 +61,11 @@
 namespace effect {
 
 EffectHalAidl::EffectHalAidl(const std::shared_ptr<IFactory>& factory,
-                             const std::shared_ptr<IEffect>& effect, uint64_t effectId,
+                             const std::shared_ptr<IEffect>& effect,
                              int32_t sessionId, int32_t ioId, const Descriptor& desc,
                              bool isProxyEffect)
     : mFactory(factory),
       mEffect(effect),
-      mEffectId(effectId),
       mSessionId(sessionId),
       mIoId(ioId),
       mDesc(desc),
@@ -75,9 +74,12 @@
 }
 
 EffectHalAidl::~EffectHalAidl() {
-    if (mEffect) {
-        mIsProxyEffect ? std::static_pointer_cast<EffectProxy>(mEffect)->destroy()
-                       : mFactory->destroyEffect(mEffect);
+    if (mFactory && mEffect) {
+        if (mIsProxyEffect) {
+            std::static_pointer_cast<EffectProxy>(mEffect)->destroy();
+        } else {
+            mFactory->destroyEffect(mEffect);
+        }
     }
 }
 
@@ -89,64 +91,64 @@
     ALOGI("%s create UUID %s", __func__, typeUuid.toString().c_str());
     if (typeUuid ==
         ::aidl::android::hardware::audio::effect::getEffectTypeUuidAcousticEchoCanceler()) {
-        mConversion =
-                std::make_unique<android::effect::AidlConversionAec>(effect, sessionId, ioId, desc);
+        mConversion = std::make_unique<android::effect::AidlConversionAec>(effect, sessionId, ioId,
+                                                                           desc, mIsProxyEffect);
     } else if (typeUuid == ::aidl::android::hardware::audio::effect::
                                    getEffectTypeUuidAutomaticGainControlV1()) {
         mConversion = std::make_unique<android::effect::AidlConversionAgc1>(effect, sessionId, ioId,
-                                                                            desc);
+                                                                            desc, mIsProxyEffect);
     } else if (typeUuid == ::aidl::android::hardware::audio::effect::
                                    getEffectTypeUuidAutomaticGainControlV2()) {
         mConversion = std::make_unique<android::effect::AidlConversionAgc2>(effect, sessionId, ioId,
-                                                                            desc);
+                                                                            desc, mIsProxyEffect);
     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost()) {
-        mConversion = std::make_unique<android::effect::AidlConversionBassBoost>(effect, sessionId,
-                                                                                 ioId, desc);
+        mConversion = std::make_unique<android::effect::AidlConversionBassBoost>(
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix()) {
-        mConversion = std::make_unique<android::effect::AidlConversionDownmix>(effect, sessionId,
-                                                                               ioId, desc);
+        mConversion = std::make_unique<android::effect::AidlConversionDownmix>(
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing()) {
-        mConversion =
-                std::make_unique<android::effect::AidlConversionDp>(effect, sessionId, ioId, desc);
+        mConversion = std::make_unique<android::effect::AidlConversionDp>(effect, sessionId, ioId,
+                                                                          desc, mIsProxyEffect);
     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb()) {
-        mConversion = std::make_unique<android::effect::AidlConversionEnvReverb>(effect, sessionId,
-                                                                                 ioId, desc);
+        mConversion = std::make_unique<android::effect::AidlConversionEnvReverb>(
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer()) {
-        mConversion =
-                std::make_unique<android::effect::AidlConversionEq>(effect, sessionId, ioId, desc);
+        mConversion = std::make_unique<android::effect::AidlConversionEq>(effect, sessionId, ioId,
+                                                                          desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator()) {
         mConversion = std::make_unique<android::effect::AidlConversionHapticGenerator>(
-                effect, sessionId, ioId, desc);
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer()) {
         mConversion = std::make_unique<android::effect::AidlConversionLoudnessEnhancer>(
-                effect, sessionId, ioId, desc);
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidNoiseSuppression()) {
         mConversion = std::make_unique<android::effect::AidlConversionNoiseSuppression>(
-                effect, sessionId, ioId, desc);
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb()) {
         mConversion = std::make_unique<android::effect::AidlConversionPresetReverb>(
-                effect, sessionId, ioId, desc);
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer()) {
         mConversion = std::make_unique<android::effect::AidlConversionSpatializer>(
-                effect, sessionId, ioId, desc);
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer()) {
         mConversion = std::make_unique<android::effect::AidlConversionVirtualizer>(
-                effect, sessionId, ioId, desc);
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else if (typeUuid ==
                ::aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer()) {
-        mConversion = std::make_unique<android::effect::AidlConversionVisualizer>(effect, sessionId,
-                                                                                  ioId, desc);
+        mConversion = std::make_unique<android::effect::AidlConversionVisualizer>(
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     } else {
         // For unknown UUID, use vendor extension implementation
         mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
-                effect, sessionId, ioId, desc);
+                effect, sessionId, ioId, desc, mIsProxyEffect);
     }
     return OK;
 }
@@ -167,6 +169,9 @@
     auto inputQ = mConversion->getInputMQ();
     auto outputQ = mConversion->getOutputMQ();
     auto efGroup = mConversion->getEventFlagGroup();
+    if (mConversion->isBypassing()) {
+        return OK;
+    }
     if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
         !outputQ->isValid() || !efGroup) {
         ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__,
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
index 47049d7..1b7a3d6 100644
--- a/media/libaudiohal/impl/EffectHalAidl.h
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -56,13 +56,8 @@
     // Free resources on the remote side.
     status_t close() override;
 
-    // Whether it's a local implementation.
-    bool isLocal() const override { return false; }
-
     status_t dump(int fd) override;
 
-    uint64_t effectId() const override { return mEffectId; }
-
     const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> getIEffect() const {
         return mEffect;
     }
@@ -75,7 +70,6 @@
 
     const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory> mFactory;
     const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
-    const uint64_t mEffectId;
     const int32_t mSessionId;
     const int32_t mIoId;
     const ::aidl::android::hardware::audio::effect::Descriptor mDesc;
@@ -93,7 +87,7 @@
     EffectHalAidl(
             const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory,
             const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
-            uint64_t effectId, int32_t sessionId, int32_t ioId,
+            int32_t sessionId, int32_t ioId,
             const ::aidl::android::hardware::audio::effect::Descriptor& desc,
             bool isProxyEffect);
     bool setEffectReverse(bool reverse);
diff --git a/media/libaudiohal/impl/EffectHalHidl.h b/media/libaudiohal/impl/EffectHalHidl.h
index 94dcd7e..dda21ed 100644
--- a/media/libaudiohal/impl/EffectHalHidl.h
+++ b/media/libaudiohal/impl/EffectHalHidl.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_HARDWARE_EFFECT_HAL_HIDL_H
 #define ANDROID_HARDWARE_EFFECT_HAL_HIDL_H
 
-#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffect.h)
+#include PATH(android/hardware/audio/effect/COMMON_TYPES_FILE_VERSION/IEffect.h)
 #include <media/audiohal/EffectHalInterface.h>
 #include <fmq/EventFlag.h>
 #include <fmq/MessageQueue.h>
@@ -31,7 +31,7 @@
 namespace android {
 namespace effect {
 
-using namespace ::android::hardware::audio::effect::CPP_VERSION;
+using namespace ::android::hardware::audio::effect::COMMON_TYPES_CPP_VERSION;
 
 class EffectHalHidl : public EffectHalInterface, public EffectConversionHelperHidl
 {
@@ -59,12 +59,9 @@
     // Free resources on the remote side.
     virtual status_t close();
 
-    // Whether it's a local implementation.
-    virtual bool isLocal() const { return false; }
-
     virtual status_t dump(int fd);
 
-    virtual uint64_t effectId() const { return mEffectId; }
+    uint64_t effectId() const { return mEffectId; }
 
   private:
     friend class EffectsFactoryHalHidl;
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index b61532d..f83d479 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -15,15 +15,18 @@
  */
 
 #include <algorithm>
+#include <iterator>
 #include <memory>
 #define LOG_TAG "EffectProxy"
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 
 #include <fmq/AidlMessageQueue.h>
+#include <system/audio_aidl_utils.h>
 #include <utils/Log.h>
 
 #include "EffectProxy.h"
 
+using ::aidl::android::hardware::audio::effect::Capability;
 using ::aidl::android::hardware::audio::effect::CommandId;
 using ::aidl::android::hardware::audio::effect::Descriptor;
 using ::aidl::android::hardware::audio::effect::Flags;
@@ -33,17 +36,27 @@
 using ::aidl::android::hardware::audio::effect::State;
 using ::aidl::android::media::audio::common::AudioUuid;
 
-namespace android {
-namespace effect {
+namespace android::effect {
 
-EffectProxy::EffectProxy(const Descriptor::Identity& id, const std::shared_ptr<IFactory>& factory)
-    : mIdentity([](const Descriptor::Identity& subId) {
-          // update EffectProxy implementation UUID to the sub-effect proxy UUID
-          ALOG_ASSERT(subId.proxy.has_value(), "Sub-effect Identity must have valid proxy UUID");
-          Descriptor::Identity tempId = subId;
-          tempId.uuid = subId.proxy.value();
-          return tempId;
-      }(id)),
+EffectProxy::EffectProxy(const AudioUuid& uuid, const std::vector<Descriptor>& descriptors,
+                         const std::shared_ptr<IFactory>& factory)
+    : mDescriptorCommon(buildDescriptorCommon(uuid, descriptors)),
+      mSubEffects(
+              [](const std::vector<Descriptor>& descs, const std::shared_ptr<IFactory>& factory) {
+                  std::vector<SubEffect> subEffects;
+                  ALOG_ASSERT(factory, "invalid EffectFactory handle");
+                  ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
+                  for (const auto& desc : descs) {
+                      SubEffect sub({.descriptor = desc});
+                      status = factory->createEffect(desc.common.id.uuid, &sub.handle);
+                      if (!status.isOk() || !sub.handle) {
+                          ALOGW("%s create sub-effect %s failed", __func__,
+                                ::android::audio::utils::toString(desc.common.id.uuid).c_str());
+                      }
+                      subEffects.emplace_back(sub);
+                  }
+                  return subEffects;
+              }(descriptors, factory)),
       mFactory(factory) {}
 
 EffectProxy::~EffectProxy() {
@@ -52,68 +65,9 @@
     mSubEffects.clear();
 }
 
-// sub effect must have same proxy UUID as EffectProxy, and the type UUID must match.
-ndk::ScopedAStatus EffectProxy::addSubEffect(const Descriptor& sub) {
-    ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
-    if (0 != mSubEffects.count(sub.common.id) || !sub.common.id.proxy.has_value() ||
-        sub.common.id.proxy.value() != mIdentity.uuid) {
-        ALOGE("%s sub effect already exist or mismatch %s", __func__, sub.toString().c_str());
-        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
-                                                                "illegalSubEffect");
-    }
-
-    // not create sub-effect yet
-    std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[sub.common.id]) = nullptr;
-    std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[sub.common.id]) = sub;
-    // set the last added sub-effect to active before setOffloadParam()
-    mActiveSub = sub.common.id;
-    ALOGI("%s add %s to proxy %s flag %s", __func__, mActiveSub.toString().c_str(),
-          mIdentity.toString().c_str(), sub.common.flags.toString().c_str());
-
-    if (sub.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) {
-        mSubFlags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL;
-    }
-
-    // initial flag values before we know which sub-effect to active (with setOffloadParam)
-    // same as HIDL EffectProxy flags
-    mSubFlags.type = Flags::Type::INSERT;
-    mSubFlags.insert = Flags::Insert::LAST;
-    mSubFlags.volume = Flags::Volume::CTRL;
-
-    // set indication if any sub-effect indication was set
-    mSubFlags.offloadIndication |= sub.common.flags.offloadIndication;
-    mSubFlags.deviceIndication |= sub.common.flags.deviceIndication;
-    mSubFlags.audioModeIndication |= sub.common.flags.audioModeIndication;
-    mSubFlags.audioSourceIndication |= sub.common.flags.audioSourceIndication;
-
-    // set bypass when all sub-effects are bypassing
-    mSubFlags.bypass &= sub.common.flags.bypass;
-    return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus EffectProxy::create() {
-    ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
-    ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
-
-    for (auto& sub : mSubEffects) {
-        auto& effectHandle = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
-        ALOGI("%s sub-effect %s", __func__, sub.first.uuid.toString().c_str());
-        status = mFactory->createEffect(sub.first.uuid, &effectHandle);
-        if (!status.isOk() || !effectHandle) {
-            ALOGE("%s sub-effect failed %s", __func__, sub.first.uuid.toString().c_str());
-            break;
-        }
-    }
-
-    // destroy all created effects if failure
-    if (!status.isOk()) {
-        destroy();
-    }
-    return status;
-}
-
 ndk::ScopedAStatus EffectProxy::destroy() {
-    ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
+    ALOGV("%s: %s", __func__,
+          ::android::audio::utils::toString(mDescriptorCommon.id.type).c_str());
     return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
         ndk::ScopedAStatus status = mFactory->destroyEffect(effect);
         if (status.isOk()) {
@@ -123,28 +77,24 @@
     });
 }
 
-const IEffect::OpenEffectReturn* EffectProxy::getEffectReturnParam() {
-    return &std::get<SubEffectTupleIndex::RETURN>(mSubEffects[mActiveSub]);
-}
-
 ndk::ScopedAStatus EffectProxy::setOffloadParam(const effect_offload_param_t* offload) {
     const auto& itor = std::find_if(mSubEffects.begin(), mSubEffects.end(), [&](const auto& sub) {
-        const auto& desc = std::get<SubEffectTupleIndex::DESCRIPTOR>(sub.second);
-        ALOGI("%s: isOffload %d sub-effect: %s, flags %s", __func__, offload->isOffload,
-              desc.common.id.uuid.toString().c_str(), desc.common.flags.toString().c_str());
+        const auto& desc = sub.descriptor;
         return offload->isOffload ==
                (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL);
     });
     if (itor == mSubEffects.end()) {
         ALOGE("%s no %soffload sub-effect found", __func__, offload->isOffload ? "" : "non-");
+        mActiveSubIdx = 0;
         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER,
                                                                 "noActiveEffctFound");
     }
 
-    mActiveSub = itor->first;
-    ALOGI("%s: active %soffload sub-effect: %s, flags %s", __func__,
-          offload->isOffload ? "" : "non-", mActiveSub.uuid.toString().c_str(),
-          std::get<SubEffectTupleIndex::DESCRIPTOR>(itor->second).common.flags.toString().c_str());
+    mActiveSubIdx = std::distance(mSubEffects.begin(), itor);
+    ALOGV("%s: active %soffload sub-effect %zu descriptor: %s", __func__,
+          offload->isOffload ? "" : "non-", mActiveSubIdx,
+          ::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid)
+                  .c_str());
     return ndk::ScopedAStatus::ok();
 }
 
@@ -152,20 +102,24 @@
 ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common,
                                      const std::optional<Parameter::Specific>& specific,
                                      IEffect::OpenEffectReturn* ret __unused) {
-    ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
     ndk::ScopedAStatus status = ndk::ScopedAStatus::fromExceptionCodeWithMessage(
             EX_ILLEGAL_ARGUMENT, "nullEffectHandle");
     for (auto& sub : mSubEffects) {
-        auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
-        auto& openRet = std::get<SubEffectTupleIndex::RETURN>(sub.second);
-        if (!effect || !(status = effect->open(common, specific, &openRet)).isOk()) {
-            ALOGE("%s: failed to open UUID %s", __func__, sub.first.uuid.toString().c_str());
+        IEffect::OpenEffectReturn openReturn;
+        if (!sub.handle || !(status = sub.handle->open(common, specific, &openReturn)).isOk()) {
+            ALOGE("%s: failed to open %p UUID %s", __func__, sub.handle.get(),
+                  ::android::audio::utils::toString(sub.descriptor.common.id.uuid).c_str());
             break;
         }
+        sub.effectMq.statusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
+        sub.effectMq.inputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
+        sub.effectMq.outputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ);
     }
 
     // close all opened effects if failure
     if (!status.isOk()) {
+        ALOGE("%s: closing all sub-effects with error %s", __func__,
+              status.getDescription().c_str());
         close();
     }
 
@@ -173,38 +127,68 @@
 }
 
 ndk::ScopedAStatus EffectProxy::close() {
-    ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
     return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
         return effect->close();
     });
 }
 
 ndk::ScopedAStatus EffectProxy::getDescriptor(Descriptor* desc) {
+    desc->common = mDescriptorCommon;
+    desc->capability = mSubEffects[mActiveSubIdx].descriptor.capability;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectProxy::buildDescriptor(const AudioUuid& uuid,
+                                                const std::vector<Descriptor>& subEffectDescs,
+                                                Descriptor* desc) {
     if (!desc) {
-        ALOGE("%s: nuull descriptor pointer", __func__);
+        ALOGE("%s: null descriptor pointer", __func__);
         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "nullptr");
     }
 
-    auto& activeSubEffect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]);
-    // return initial descriptor if no active sub-effect exist
-    if (!activeSubEffect) {
-        desc->common.id = mIdentity;
-        desc->common.flags = mSubFlags;
-        desc->common.name = "Proxy";
-        desc->common.implementor = "AOSP";
-    } else {
-        *desc = std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[mActiveSub]);
-        desc->common.id = mIdentity;
+    if (subEffectDescs.size() < 2) {
+        ALOGE("%s: proxy need at least 2 sub-effects, got %zu", __func__, subEffectDescs.size());
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "needMoreSubEffects");
     }
 
-    ALOGI("%s with %s", __func__, desc->toString().c_str());
+    desc->common = buildDescriptorCommon(uuid, subEffectDescs);
     return ndk::ScopedAStatus::ok();
 }
 
+Descriptor::Common EffectProxy::buildDescriptorCommon(
+        const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs) {
+    Descriptor::Common common;
+    for (const auto& desc : subEffectDescs) {
+        if (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) {
+            common.flags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL;
+        }
+
+        // initial flag values before we know which sub-effect to active (with setOffloadParam)
+        // same as HIDL EffectProxy flags
+        common.flags.type = Flags::Type::INSERT;
+        common.flags.insert = Flags::Insert::LAST;
+        common.flags.volume = Flags::Volume::CTRL;
+
+        // set indication if any sub-effect indication was set
+        common.flags.offloadIndication |= desc.common.flags.offloadIndication;
+        common.flags.deviceIndication |= desc.common.flags.deviceIndication;
+        common.flags.audioModeIndication |= desc.common.flags.audioModeIndication;
+        common.flags.audioSourceIndication |= desc.common.flags.audioSourceIndication;
+    }
+
+    // copy type UUID from any of sub-effects, all sub-effects should have same type
+    common.id.type = subEffectDescs[0].common.id.type;
+    // replace implementation UUID with proxy UUID.
+    common.id.uuid = uuid;
+    common.id.proxy = std::nullopt;
+    common.name = "Proxy";
+    common.implementor = "AOSP";
+    return common;
+}
+
 // Handle with active sub-effect first, only send to other sub-effects when success
 ndk::ScopedAStatus EffectProxy::command(CommandId id) {
-    ALOGV("%s: %s, command %s", __func__, mIdentity.type.toString().c_str(),
-          android::internal::ToString(id).c_str());
     return runWithActiveSubEffectThenOthers(
             [&](const std::shared_ptr<IEffect>& effect) -> ndk::ScopedAStatus {
                 return effect->command(id);
@@ -239,34 +223,30 @@
         std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) {
     ndk::ScopedAStatus status = runWithActiveSubEffect(func);
     if (!status.isOk()) {
-        return status;
+        ALOGE("%s active sub-effect return error %s", __func__, status.getDescription().c_str());
     }
 
-    // proceed with others if active sub-effect success
-    for (const auto& sub : mSubEffects) {
-        auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
-        if (sub.first != mActiveSub) {
-            if (!effect) {
-                ALOGE("%s null sub-effect interface for %s", __func__,
-                      sub.first.toString().c_str());
-                continue;
-            }
-            func(effect);
+    // proceed with others
+    for (size_t i = 0; i < mSubEffects.size() && i != mActiveSubIdx; i++) {
+        if (!mSubEffects[i].handle) {
+            ALOGE("%s null sub-effect interface for %s", __func__,
+                  mSubEffects[i].descriptor.common.id.uuid.toString().c_str());
+            continue;
         }
+        func(mSubEffects[i].handle);
     }
     return status;
 }
 
 ndk::ScopedAStatus EffectProxy::runWithActiveSubEffect(
         std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) {
-    auto& effect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]);
-    if (!effect) {
+    if (!mSubEffects[mActiveSubIdx].handle) {
         ALOGE("%s null active sub-effect interface, active %s", __func__,
-              mActiveSub.toString().c_str());
+              mSubEffects[mActiveSubIdx].descriptor.toString().c_str());
         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER,
                                                                 "activeSubEffectNull");
     }
-    return func(effect);
+    return func(mSubEffects[mActiveSubIdx].handle);
 }
 
 ndk::ScopedAStatus EffectProxy::runWithAllSubEffects(
@@ -274,12 +254,11 @@
     ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
     // proceed with others if active sub-effect success
     for (auto& sub : mSubEffects) {
-        auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
-        if (!effect) {
-            ALOGW("%s null sub-effect interface for %s", __func__, sub.first.toString().c_str());
+        if (!sub.handle) {
+            ALOGW("%s null sub-effect interface %s", __func__, sub.descriptor.toString().c_str());
             continue;
         }
-        ndk::ScopedAStatus temp = func(effect);
+        ndk::ScopedAStatus temp = func(sub.handle);
         if (!temp.isOk()) {
             status = ndk::ScopedAStatus::fromStatus(temp.getStatus());
         }
@@ -287,5 +266,34 @@
     return status;
 }
 
-} // namespace effect
-} // namespace android
+bool EffectProxy::isBypassing() const {
+    return mSubEffects[mActiveSubIdx].descriptor.common.flags.bypass;
+}
+
+binder_status_t EffectProxy::dump(int fd, const char** args, uint32_t numArgs) {
+    const std::string dumpString = toString();
+    write(fd, dumpString.c_str(), dumpString.size());
+
+    return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
+               return ndk::ScopedAStatus::fromStatus(effect->dump(fd, args, numArgs));
+           })
+            .getStatus();
+}
+
+std::string EffectProxy::toString(size_t level) const {
+    std::string prefixSpace(level, ' ');
+    std::string ss = prefixSpace + "EffectProxy:\n";
+    prefixSpace += " ";
+    base::StringAppendF(&ss, "%sDescriptorCommon: %s\n", prefixSpace.c_str(),
+                        mDescriptorCommon.toString().c_str());
+    base::StringAppendF(&ss, "%sActiveSubIdx: %zu\n", prefixSpace.c_str(), mActiveSubIdx);
+    base::StringAppendF(&ss, "%sAllSubEffects:\n", prefixSpace.c_str());
+    for (size_t i = 0; i < mSubEffects.size(); i++) {
+        base::StringAppendF(&ss, "%s[%zu] - Handle: %p, %s\n", prefixSpace.c_str(), i,
+                            mSubEffects[i].handle ? mSubEffects[i].handle.get() : nullptr,
+                            mSubEffects[i].descriptor.toString().c_str());
+    }
+    return ss;
+}
+
+} // namespace android::effect
diff --git a/media/libaudiohal/impl/EffectProxy.h b/media/libaudiohal/impl/EffectProxy.h
index ffb8a19..18e1567 100644
--- a/media/libaudiohal/impl/EffectProxy.h
+++ b/media/libaudiohal/impl/EffectProxy.h
@@ -40,27 +40,10 @@
  */
 class EffectProxy final : public ::aidl::android::hardware::audio::effect::BnEffect {
   public:
-    EffectProxy(const ::aidl::android::hardware::audio::effect::Descriptor::Identity& id,
-                const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory);
-
-    /**
-     * Add a sub effect into the proxy, the descriptor of candidate sub-effect need to have same
-     * proxy UUID as mUuid.
-     */
-    ndk::ScopedAStatus addSubEffect(
-            const ::aidl::android::hardware::audio::effect::Descriptor& sub);
-
-    /**
-     * Create all sub-effects via AIDL IFactory, always call create() after all sub-effects added
-     * successfully with addSubEffect.
-     */
-    ndk::ScopedAStatus create();
-
-    /**
-     * Destroy all sub-effects via AIDL IFactory, always call create() after all sub-effects added
-     * successfully with addSubEffect.
-     */
-    ndk::ScopedAStatus destroy();
+    EffectProxy(
+            const ::aidl::android::media::audio::common::AudioUuid& uuid,
+            const std::vector<::aidl::android::hardware::audio::effect::Descriptor>& descriptors,
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory);
 
     /**
      * Handle offload parameter setting from framework.
@@ -68,11 +51,9 @@
     ndk::ScopedAStatus setOffloadParam(const effect_offload_param_t* offload);
 
     /**
-     * Get the const reference of the active sub-effect return parameters.
-     * Always use this interface to get the effect open return parameters (FMQs) after a success
-     * setOffloadParam() call.
+     * Destroy all sub-effects via AIDL IFactory.
      */
-    const IEffect::OpenEffectReturn* getEffectReturnParam();
+    ndk::ScopedAStatus destroy();
 
     // IEffect interfaces override
     ndk::ScopedAStatus open(
@@ -91,25 +72,59 @@
             const ::aidl::android::hardware::audio::effect::Parameter::Id& id,
             ::aidl::android::hardware::audio::effect::Parameter* param) override;
 
+    static ndk::ScopedAStatus buildDescriptor(
+            const ::aidl::android::media::audio::common::AudioUuid& uuid,
+            const std::vector<::aidl::android::hardware::audio::effect::Descriptor>& subEffectDescs,
+            ::aidl::android::hardware::audio::effect::Descriptor* desc);
+
+    /**
+     * Get the const reference of the active sub-effect return parameters.
+     * Always use this interface to get the effect open return parameters (FMQs) after a success
+     * setOffloadParam() call.
+     */
+    using StatusMQ = ::android::AidlMessageQueue<
+            ::aidl::android::hardware::audio::effect::IEffect::Status,
+            ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>;
+    using DataMQ = ::android::AidlMessageQueue<
+            float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>;
+    const std::shared_ptr<StatusMQ>& getStatusMQ() const {
+        return mSubEffects[mActiveSubIdx].effectMq.statusQ;
+    }
+    const std::shared_ptr<DataMQ>& getInputMQ() const {
+        return mSubEffects[mActiveSubIdx].effectMq.inputQ;
+    }
+    const std::shared_ptr<DataMQ>& getOutputMQ() const {
+        return mSubEffects[mActiveSubIdx].effectMq.outputQ;
+    }
+
+    bool isBypassing() const;
+
+    // call dump for all sub-effects
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+    std::string toString(size_t indent = 0) const;
+
   private:
-    // Proxy identity, copy from one sub-effect, and update the implementation UUID to proxy UUID
-    const ::aidl::android::hardware::audio::effect::Descriptor::Identity mIdentity;
+    // Proxy descriptor common part, copy from one sub-effect, and update the implementation UUID to
+    // proxy UUID, proxy descriptor capability part comes from the active sub-effect capability
+    const ::aidl::android::hardware::audio::effect::Descriptor::Common mDescriptorCommon;
+
+    struct EffectMQ {
+        std::shared_ptr<StatusMQ> statusQ;
+        std::shared_ptr<DataMQ> inputQ, outputQ;
+    };
+    struct SubEffect {
+        const ::aidl::android::hardware::audio::effect::Descriptor descriptor;
+        std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> handle;
+        EffectMQ effectMq;
+    };
+    std::vector<SubEffect> mSubEffects;
+
     const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory> mFactory;
 
-    // A map of sub effects descriptor to the IEffect handle and return FMQ
-    enum SubEffectTupleIndex { HANDLE, DESCRIPTOR, RETURN };
-    using EffectProxySub =
-            std::tuple<std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>,
-                       ::aidl::android::hardware::audio::effect::Descriptor,
-                       ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn>;
-    std::map<const ::aidl::android::hardware::audio::effect::Descriptor::Identity, EffectProxySub>
-            mSubEffects;
-
-    // Descriptor of the only active effect in the mSubEffects map
-    ::aidl::android::hardware::audio::effect::Descriptor::Identity mActiveSub;
-
-    // keep the flag of sub-effects
-    ::aidl::android::hardware::audio::effect::Flags mSubFlags;
+    // index of the active sub-effects, by default use the first one (index 0)
+    // It's safe to assume there will always at least two SubEffects in mSubEffects
+    size_t mActiveSubIdx = 0;
 
     ndk::ScopedAStatus runWithActiveSubEffectThenOthers(
             std::function<ndk::ScopedAStatus(
@@ -122,6 +137,12 @@
     ndk::ScopedAStatus runWithAllSubEffects(
             std::function<ndk::ScopedAStatus(std::shared_ptr<IEffect>&)> const& func);
 
+    // build Descriptor.Common with all sub-effect descriptors
+    static ::aidl::android::hardware::audio::effect::Descriptor::Common buildDescriptorCommon(
+            const ::aidl::android::media::audio::common::AudioUuid& uuid,
+            const std::vector<::aidl::android::hardware::audio::effect::Descriptor>&
+                    subEffectDescs);
+
     // close and release all sub-effects
     ~EffectProxy();
 };
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index 7b9088e..1c5e474 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -28,6 +28,7 @@
 #include <media/AidlConversionCppNdk.h>
 #include <media/AidlConversionEffect.h>
 #include <system/audio.h>
+#include <system/audio_aidl_utils.h>
 #include <utils/Log.h>
 
 #include "EffectBufferHalAidl.h"
@@ -43,6 +44,7 @@
 using ::aidl::android::media::audio::common::AudioSource;
 using ::aidl::android::media::audio::common::AudioStreamType;
 using ::aidl::android::media::audio::common::AudioUuid;
+using ::android::audio::utils::toString;
 using ::android::base::unexpected;
 using ::android::detail::AudioHalVersionInfo;
 
@@ -66,26 +68,28 @@
           }
           return list;
       }()),
-      mUuidProxyMap([this]() {
-          std::map<AudioUuid, std::shared_ptr<EffectProxy>> proxyMap;
-          for (const auto& desc : mHalDescList) {
-              // create EffectProxy
+      mProxyUuidDescriptorMap([this]() {
+          std::map<AudioUuid, std::vector<Descriptor>> proxyUuidMap;
+          for (auto& desc : mHalDescList) {
               if (desc.common.id.proxy.has_value()) {
-                  const auto& uuid = desc.common.id.proxy.value();
-                  if (0 == proxyMap.count(uuid)) {
-                      proxyMap.insert({uuid, ndk::SharedRefBase::make<EffectProxy>(desc.common.id,
-                                                                                   mFactory)});
+                  auto& uuid = desc.common.id.proxy.value();
+                  if (proxyUuidMap.count(uuid) == 0) {
+                      proxyUuidMap.insert({uuid, {desc}});
+                  } else {
+                      proxyUuidMap[uuid].emplace_back(desc);
                   }
-                  proxyMap[uuid]->addSubEffect(desc);
-                  ALOGI("%s addSubEffect %s", __func__, desc.common.toString().c_str());
               }
           }
-          return proxyMap;
+          return proxyUuidMap;
       }()),
       mProxyDescList([this]() {
           std::vector<Descriptor> list;
-          for (const auto& proxy : mUuidProxyMap) {
-              if (Descriptor desc; proxy.second && proxy.second->getDescriptor(&desc).isOk()) {
+          for (const auto& proxy : mProxyUuidDescriptorMap) {
+              if (Descriptor desc;
+                  EffectProxy::buildDescriptor(proxy.first /* uuid */,
+                                               proxy.second /* sub-effect descriptor list */,
+                                               &desc /* proxy descriptor */)
+                          .isOk()) {
                   list.emplace_back(std::move(desc));
               }
           }
@@ -116,7 +120,8 @@
     }
 
     *pNumEffects = mEffectCount;
-    ALOGI("%s %d", __func__, *pNumEffects);
+    ALOGD("%s %d non %zu proxyMap %zu proxyDesc %zu", __func__, *pNumEffects,
+          mNonProxyDescList.size(), mProxyUuidDescriptorMap.size(), mProxyDescList.size());
     return OK;
 }
 
@@ -181,38 +186,31 @@
     // Use EffectProxy interface instead of IFactory to create
     const bool isProxy = isProxyEffect(aidlUuid);
     if (isProxy) {
-        aidlEffect = mUuidProxyMap.at(aidlUuid);
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mUuidProxyMap.at(aidlUuid)->create()));
+        aidlEffect = ndk::SharedRefBase::make<EffectProxy>(
+                aidlUuid, mProxyUuidDescriptorMap.at(aidlUuid) /* sub-effect descriptor list */,
+                mFactory);
+        mProxyList.emplace_back(std::static_pointer_cast<EffectProxy>(aidlEffect));
     } else {
         RETURN_STATUS_IF_ERROR(
                 statusTFromBinderStatus(mFactory->createEffect(aidlUuid, &aidlEffect)));
     }
     if (aidlEffect == nullptr) {
-        ALOGE("%s failed to create effect with UUID: %s", __func__, aidlUuid.toString().c_str());
+        ALOGE("%s failed to create effect with UUID: %s", __func__, toString(aidlUuid).c_str());
         return NAME_NOT_FOUND;
     }
     Descriptor desc;
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(aidlEffect->getDescriptor(&desc)));
 
-    uint64_t effectId;
-    {
-        std::lock_guard lg(mLock);
-        effectId = ++mEffectIdCounter;
-    }
-
-    *effect =
-            sp<EffectHalAidl>::make(mFactory, aidlEffect, effectId, sessionId, ioId, desc, isProxy);
+    *effect = sp<EffectHalAidl>::make(mFactory, aidlEffect, sessionId, ioId, desc, isProxy);
     return OK;
 }
 
 status_t EffectsFactoryHalAidl::dumpEffects(int fd) {
     status_t ret = OK;
     // record the error ret and continue dump as many effects as possible
-    for (const auto& proxy : mUuidProxyMap) {
-        if (proxy.second) {
-            if (status_t temp = proxy.second->dump(fd, nullptr, 0); temp != OK) {
-                ret = temp;
-            }
+    for (const auto& proxy : mProxyList) {
+        if (status_t temp = BAD_VALUE; proxy && (temp = proxy->dump(fd, nullptr, 0)) != OK) {
+            ret = temp;
         }
     }
     RETURN_STATUS_IF_ERROR(mFactory->dump(fd, nullptr, 0));
@@ -244,10 +242,10 @@
     auto matchIt = std::find_if(list.begin(), list.end(),
                                 [&](const auto& desc) { return desc.common.id.uuid == uuid; });
     if (matchIt == list.end()) {
-        ALOGE("%s UUID not found in HAL and proxy list %s", __func__, uuid.toString().c_str());
+        ALOGE("%s UUID not found in HAL and proxy list %s", __func__, toString(uuid).c_str());
         return BAD_VALUE;
     }
-    ALOGI("%s UUID impl found %s", __func__, uuid.toString().c_str());
+    ALOGI("%s UUID impl found %s", __func__, toString(uuid).c_str());
 
     *pDescriptor = VALUE_OR_RETURN_STATUS(
             ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(*matchIt));
@@ -266,10 +264,10 @@
     std::copy_if(mProxyDescList.begin(), mProxyDescList.end(), std::back_inserter(result),
                  [&](auto& desc) { return desc.common.id.type == type; });
     if (result.empty()) {
-        ALOGW("%s UUID type not found in HAL and proxy list %s", __func__, type.toString().c_str());
+        ALOGW("%s UUID type not found in HAL and proxy list %s", __func__, toString(type).c_str());
         return BAD_VALUE;
     }
-    ALOGI("%s UUID type found %zu \n %s", __func__, result.size(), type.toString().c_str());
+    ALOGI("%s UUID type found %zu \n %s", __func__, result.size(), toString(type).c_str());
 
     *descriptors = VALUE_OR_RETURN_STATUS(
             aidl::android::convertContainer<std::vector<effect_descriptor_t>>(
@@ -278,7 +276,7 @@
 }
 
 bool EffectsFactoryHalAidl::isProxyEffect(const AudioUuid& uuid) const {
-    return 0 != mUuidProxyMap.count(uuid);
+    return 0 != mProxyUuidDescriptorMap.count(uuid);
 }
 
 std::shared_ptr<const effectsConfig::Processings> EffectsFactoryHalAidl::getProcessings() const {
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.h b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
index 39beea2..73089b0 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
@@ -17,8 +17,8 @@
 #pragma once
 
 #include <cstddef>
+#include <list>
 #include <memory>
-#include <mutex>
 
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <aidl/android/hardware/audio/effect/Processing.h>
@@ -72,10 +72,9 @@
     const detail::AudioHalVersionInfo mHalVersion;
     // Full list of HAL effect descriptors
     const std::vector<Descriptor> mHalDescList;
-    // Map of proxy UUID (key) to the proxy object
-    const std::map<::aidl::android::media::audio::common::AudioUuid /* proxy impl UUID */,
-                   std::shared_ptr<EffectProxy>>
-            mUuidProxyMap;
+    // Map of proxy UUID (key) to the Descriptor of sub-effects
+    const std::map<::aidl::android::media::audio::common::AudioUuid, std::vector<Descriptor>>
+            mProxyUuidDescriptorMap;
     // List of effect proxy, initialize after mUuidProxyMap because it need to have all sub-effects
     const std::vector<Descriptor> mProxyDescList;
     // List of non-proxy effects
@@ -85,16 +84,16 @@
     // Query result of pre and post processing from effect factory
     const std::vector<Processing> mAidlProcessings;
 
-    std::mutex mLock;
-    uint64_t mEffectIdCounter GUARDED_BY(mLock) = 0;  // Align with HIDL (0 is INVALID_ID)
+    // list of the EffectProxy instances
+    std::list<std::shared_ptr<EffectProxy>> mProxyList;
 
     virtual ~EffectsFactoryHalAidl() = default;
     status_t getHalDescriptorWithImplUuid(
-            const aidl::android::media::audio::common::AudioUuid& uuid,
+            const ::aidl::android::media::audio::common::AudioUuid& uuid,
             effect_descriptor_t* pDescriptor);
 
     status_t getHalDescriptorWithTypeUuid(
-            const aidl::android::media::audio::common::AudioUuid& type,
+            const ::aidl::android::media::audio::common::AudioUuid& type,
             std::vector<effect_descriptor_t>* descriptors);
 
     bool isProxyEffect(const aidl::android::media::audio::common::AudioUuid& uuid) const;
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index c84f80f..80e19a0 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -32,6 +32,7 @@
 #include <utils/Log.h>
 
 #include "DeviceHalAidl.h"
+#include "EffectHalAidl.h"
 #include "StreamHalAidl.h"
 
 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
@@ -162,20 +163,26 @@
     return OK;
 }
 
-status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect __unused) {
+status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    ALOGE("%s not implemented yet", __func__);
-    return OK;
+    if (effect == nullptr) {
+        return BAD_VALUE;
+    }
+    auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
+    return statusTFromBinderStatus(mStream->addEffect(aidlEffect->getIEffect()));
 }
 
-status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect __unused) {
+status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    ALOGE("%s not implemented yet", __func__);
-    return OK;
+    if (effect == nullptr) {
+        return BAD_VALUE;
+    }
+    auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
+    return statusTFromBinderStatus(mStream->removeEffect(aidlEffect->getIEffect()));
 }
 
 status_t StreamHalAidl::standby() {
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index 82062cc..72eadc6 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -33,6 +33,7 @@
 #include <util/CoreUtils.h>
 
 #include "DeviceHalHidl.h"
+#include "EffectHalHidl.h"
 #include "ParameterUtils.h"
 #include "StreamHalHidl.h"
 
@@ -144,13 +145,15 @@
 status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    return processReturn("addEffect", mStream->addEffect(effect->effectId()));
+    auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
+    return processReturn("addEffect", mStream->addEffect(hidlEffect->effectId()));
 }
 
 status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    return processReturn("removeEffect", mStream->removeEffect(effect->effectId()));
+    auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
+    return processReturn("removeEffect", mStream->removeEffect(hidlEffect->effectId()));
 }
 
 status_t StreamHalHidl::standby() {
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.h
index 3ee419a..61dd36a 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.h
@@ -26,8 +26,9 @@
   public:
     AidlConversionAec(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
                       int32_t sessionId, int32_t ioId,
-                      const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+                      const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+                      bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionAec() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc1.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc1.h
index b0509fd..364b473 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc1.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc1.h
@@ -26,8 +26,9 @@
   public:
     AidlConversionAgc1(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
                        int32_t sessionId, int32_t ioId,
-                       const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+                       const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+                       bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionAgc1() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.h
index 8f7eac7..df9a9ec 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.h
@@ -26,8 +26,9 @@
   public:
     AidlConversionAgc2(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
                        int32_t sessionId, int32_t ioId,
-                       const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+                       const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+                       bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionAgc2() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.h
index 9664aa1..424b837 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.h
@@ -27,8 +27,8 @@
     AidlConversionBassBoost(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionBassBoost() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.h
index 8b28ca3..f963f66 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.h
@@ -26,8 +26,9 @@
   public:
     AidlConversionDownmix(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
                           int32_t sessionId, int32_t ioId,
-                          const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+                          const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+                          bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionDownmix() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.h
index c5d5a54..62714c3 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.h
@@ -26,8 +26,9 @@
   public:
     AidlConversionDp(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
                      int32_t sessionId, int32_t ioId,
-                     const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+                     const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+                     bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionDp() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.h
index 8b92374..95042eb 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.h
@@ -27,8 +27,8 @@
     AidlConversionEnvReverb(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionEnvReverb() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
index 45b98a1..fc867c7 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
@@ -161,6 +161,9 @@
             return param.writeToValue(&bands);
         }
         case EQ_PARAM_LEVEL_RANGE: {
+            if (mDesc.capability.range.getTag() != Range::equalizer) {
+                return OK;
+            }
             const auto& ranges = mDesc.capability.range.get<Range::equalizer>();
             for (const auto& r : ranges) {
                 if (r.min.getTag() == Equalizer::bandLevels &&
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.h
index f94556c..53566e2 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.h
@@ -25,9 +25,10 @@
 class AidlConversionEq : public EffectConversionHelperAidl {
   public:
     AidlConversionEq(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
-                      int32_t sessionId, int32_t ioId,
-                      const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+                     int32_t sessionId, int32_t ioId,
+                     const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+                     bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionEq() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.h
index 03114a5..9890bfb 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.h
@@ -27,8 +27,8 @@
     AidlConversionHapticGenerator(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionHapticGenerator() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.h
index c0402f9..2ce14a6 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.h
@@ -27,8 +27,8 @@
     AidlConversionLoudnessEnhancer(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionLoudnessEnhancer() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.h
index f51e13a..fac121d 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.h
@@ -27,8 +27,8 @@
     AidlConversionNoiseSuppression(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionNoiseSuppression() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.h
index 397d6e6..b975d72 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.h
@@ -27,8 +27,8 @@
     AidlConversionPresetReverb(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionPresetReverb() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
index c44567c..7c60b14 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
@@ -27,8 +27,8 @@
     AidlConversionSpatializer(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionSpatializer() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.h
index fd22e5c..16bfeba 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.h
@@ -27,8 +27,8 @@
     AidlConversionVendorExtension(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionVendorExtension() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.h
index 91c0fcd..359d884 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.h
@@ -27,8 +27,8 @@
     AidlConversionVirtualizer(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionVirtualizer() {}
 
   private:
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.h
index e380bc6..bc9320f 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.h
@@ -27,8 +27,8 @@
     AidlConversionVisualizer(
             std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
             int32_t sessionId, int32_t ioId,
-            const ::aidl::android::hardware::audio::effect::Descriptor& desc)
-        : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+            const ::aidl::android::hardware::audio::effect::Descriptor& desc, bool isProxyEffect)
+        : EffectConversionHelperAidl(effect, sessionId, ioId, desc, isProxyEffect) {}
     ~AidlConversionVisualizer() {}
 
   private:
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 71e5e7a..a965709 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -132,9 +132,9 @@
             std::vector<audio_microphone_characteristic_t>* microphones) = 0;
 
     virtual status_t addDeviceEffect(
-            audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
+            const struct audio_port_config *device, sp<EffectHalInterface> effect) = 0;
     virtual status_t removeDeviceEffect(
-            audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
+            const struct audio_port_config *device, sp<EffectHalInterface> effect) = 0;
 
     virtual status_t getMmapPolicyInfos(
             media::audio::common::AudioMMapPolicyType policyType,
diff --git a/media/libaudiohal/include/media/audiohal/EffectHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
index 2969c92..cf8d7f0 100644
--- a/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
@@ -52,20 +52,14 @@
     // Free resources on the remote side.
     virtual status_t close() = 0;
 
-    // Whether it's a local implementation.
-    virtual bool isLocal() const = 0;
-
     virtual status_t dump(int fd) = 0;
 
-    // Unique effect ID to use with the core HAL.
-    virtual uint64_t effectId() const = 0;
-
   protected:
     // Subclasses can not be constructed directly by clients.
-    EffectHalInterface() {}
+    EffectHalInterface() = default;
 
     // The destructor automatically releases the effect.
-    virtual ~EffectHalInterface() {}
+    virtual ~EffectHalInterface() = default;
 };
 
 } // namespace android
diff --git a/media/libaudiohal/tests/EffectProxy_test.cpp b/media/libaudiohal/tests/EffectProxy_test.cpp
index 92e3dce..8668e85 100644
--- a/media/libaudiohal/tests/EffectProxy_test.cpp
+++ b/media/libaudiohal/tests/EffectProxy_test.cpp
@@ -60,7 +60,7 @@
         mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &mDescs);
         for (const auto& desc : mDescs) {
             if (desc.common.id.proxy.has_value()) {
-                mProxyDescs.insert({desc.common.id, desc});
+                mProxyDescs[desc.common.id.proxy.value()].emplace_back(desc);
             }
         }
     }
@@ -96,44 +96,24 @@
         return common;
     }
 
-    static bool isFlagSet(const ::aidl::android::hardware::audio::effect::Descriptor& desc,
-                          Flags::HardwareAccelerator flag) {
-        return desc.common.flags.hwAcceleratorMode == flag;
-    }
-
     enum TupleIndex { HANDLE, DESCRIPTOR };
     using EffectProxyTuple = std::tuple<std::shared_ptr<EffectProxy>, std::vector<Descriptor>>;
 
     std::map<AudioUuid, EffectProxyTuple> createAllProxies() {
         std::map<AudioUuid, EffectProxyTuple> proxyMap;
         for (const auto& itor : mProxyDescs) {
-            const auto& uuid = itor.first.proxy.value();
+            const auto& uuid = itor.first;
             if (proxyMap.end() == proxyMap.find(uuid)) {
                 std::get<TupleIndex::HANDLE>(proxyMap[uuid]) =
-                        ndk::SharedRefBase::make<EffectProxy>(itor.first, mFactory);
+                        ndk::SharedRefBase::make<EffectProxy>(itor.first, itor.second, mFactory);
             }
         }
         return proxyMap;
     }
 
-    bool addAllSubEffects(std::map<AudioUuid, EffectProxyTuple> proxyMap) {
-        for (auto& itor : mProxyDescs) {
-            const auto& uuid = itor.first.proxy.value();
-            if (proxyMap.end() == proxyMap.find(uuid)) {
-                return false;
-            }
-            auto& proxy = std::get<TupleIndex::HANDLE>(proxyMap[uuid]);
-            if (!proxy->addSubEffect(itor.second).isOk()) {
-                return false;
-            }
-            std::get<TupleIndex::DESCRIPTOR>(proxyMap[uuid]).emplace_back(itor.second);
-        }
-        return true;
-    }
-
     std::shared_ptr<IFactory> mFactory;
     std::vector<Descriptor> mDescs;
-    std::map<Descriptor::Identity, Descriptor> mProxyDescs;
+    std::map<const AudioUuid, std::vector<Descriptor>> mProxyDescs;
 };
 
 TEST_F(EffectProxyTest, createProxy) {
@@ -144,24 +124,20 @@
 
 TEST_F(EffectProxyTest, addSubEffectsCreateAndDestroy) {
     auto proxyMap = createAllProxies();
-    ASSERT_TRUE(addAllSubEffects(proxyMap));
 
     for (const auto& itor : proxyMap) {
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
-        EXPECT_TRUE(proxy->create().isOk());
         EXPECT_TRUE(proxy->destroy().isOk());
     }
 }
 
 TEST_F(EffectProxyTest, addSubEffectsCreateOpenCloseDestroy) {
     auto proxyMap = createAllProxies();
-    EXPECT_TRUE(addAllSubEffects(proxyMap));
 
     Parameter::Common common = createParamCommon();
     IEffect::OpenEffectReturn ret;
     for (const auto& itor : proxyMap) {
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
-        EXPECT_TRUE(proxy->create().isOk());
         EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
         EXPECT_TRUE(proxy->close().isOk());
         EXPECT_TRUE(proxy->destroy().isOk());
@@ -171,33 +147,23 @@
 // Add sub-effects, set active sub-effect with different checkers
 TEST_F(EffectProxyTest, setOffloadParam) {
     auto proxyMap = createAllProxies();
-    EXPECT_TRUE(addAllSubEffects(proxyMap));
 
     // Any flag exist should be able to set successfully
-    bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
-    for (const auto& itor : mProxyDescs) {
-        isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
-        isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
-        isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
-    }
-
     Parameter::Common common = createParamCommon();
     IEffect::OpenEffectReturn ret;
     for (const auto& itor : proxyMap) {
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
-        EXPECT_TRUE(proxy->create().isOk());
         EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
         effect_offload_param_t offloadParam{false, 0};
-        EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
+        EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
         offloadParam.isOffload = true;
-        EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+        EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
         EXPECT_TRUE(proxy->close().isOk());
         EXPECT_TRUE(proxy->destroy().isOk());
     }
 }
 TEST_F(EffectProxyTest, destroyWithoutCreate) {
     auto proxyMap = createAllProxies();
-    ASSERT_TRUE(addAllSubEffects(proxyMap));
 
     for (const auto& itor : proxyMap) {
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
@@ -207,11 +173,9 @@
 
 TEST_F(EffectProxyTest, closeWithoutOpen) {
     auto proxyMap = createAllProxies();
-    ASSERT_TRUE(addAllSubEffects(proxyMap));
 
     for (const auto& itor : proxyMap) {
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
-        EXPECT_TRUE(proxy->create().isOk());
 
         EXPECT_TRUE(proxy->close().isOk());
         EXPECT_TRUE(proxy->destroy().isOk());
@@ -221,16 +185,6 @@
 // Add sub-effects, set active sub-effect, create, open, and send command, expect success handling
 TEST_F(EffectProxyTest, normalSequency) {
     auto proxyMap = createAllProxies();
-    ASSERT_TRUE(addAllSubEffects(proxyMap));
-
-    bool isTunnelExist = [&]() {
-        for (const auto& itor : mProxyDescs) {
-            if (isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL)) {
-                return true;
-            }
-        }
-        return false;
-    }();
 
     Parameter::Common common = createParamCommon();
     IEffect::OpenEffectReturn ret;
@@ -242,14 +196,14 @@
         Parameter expect;
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
         effect_offload_param_t offloadParam{true, 0};
-        EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+        EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
 
-        EXPECT_TRUE(proxy->create().isOk());
         EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
 
         EXPECT_TRUE(proxy->setParameter(param).isOk());
         EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
-        EXPECT_EQ(expect, param);
+        EXPECT_EQ(expect, param) << " EXPECTED: " << expect.toString()
+                                 << "\nACTUAL: " << param.toString();
 
         EXPECT_TRUE(proxy->command(CommandId::START).isOk());
         EXPECT_TRUE(proxy->getState(&state).isOk());
@@ -267,14 +221,6 @@
 // setParameter, change active sub-effect, verify with getParameter
 TEST_F(EffectProxyTest, changeActiveSubAndVerifyParameter) {
     auto proxyMap = createAllProxies();
-    EXPECT_TRUE(addAllSubEffects(proxyMap));
-
-    bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
-    for (const auto& itor : mProxyDescs) {
-        isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
-        isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
-        isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
-    }
 
     Parameter::Common common = createParamCommon();
     IEffect::OpenEffectReturn ret;
@@ -284,19 +230,18 @@
     for (const auto& itor : proxyMap) {
         Parameter expect;
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
-        EXPECT_TRUE(proxy->create().isOk());
         EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
         EXPECT_TRUE(proxy->setParameter(param).isOk());
         EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
         EXPECT_EQ(expect, param);
 
         effect_offload_param_t offloadParam{false, 0};
-        EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
+        EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
         EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
         EXPECT_EQ(expect, param);
 
         offloadParam.isOffload = true;
-        EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+        EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
         EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
         EXPECT_EQ(expect, param);
 
@@ -308,14 +253,6 @@
 // send command, change active sub-effect, then verify the state with getState
 TEST_F(EffectProxyTest, changeActiveSubAndVerifyState) {
     auto proxyMap = createAllProxies();
-    ASSERT_TRUE(addAllSubEffects(proxyMap));
-
-    bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
-    for (const auto& itor : mProxyDescs) {
-        isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
-        isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
-        isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
-    }
 
     Parameter::Common common = createParamCommon();
     IEffect::OpenEffectReturn ret;
@@ -323,7 +260,6 @@
     for (const auto& itor : proxyMap) {
         Parameter expect;
         auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
-        EXPECT_TRUE(proxy->create().isOk());
         EXPECT_TRUE(proxy->getState(&state).isOk());
         EXPECT_EQ(State::INIT, state);
         EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
@@ -334,12 +270,12 @@
         EXPECT_EQ(State::PROCESSING, state);
 
         effect_offload_param_t offloadParam{false, 0};
-        EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
+        EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
         EXPECT_TRUE(proxy->getState(&state).isOk());
         EXPECT_EQ(State::PROCESSING, state);
 
         offloadParam.isOffload = true;
-        EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+        EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
         EXPECT_TRUE(proxy->getState(&state).isOk());
         EXPECT_EQ(State::PROCESSING, state);
 
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
index 4eea04f..bfc5059 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
@@ -166,9 +166,9 @@
              * Bypass mode or everything off, so copy the input to the output
              */
             if (pToProcess != pProcessed) {
-                Copy_Float(pToProcess,                          /* Source */
-                           pProcessed,                          /* Destination */
-                           (LVM_INT16)(NrChannels * NrFrames)); /* Copy all samples */
+                Copy_Float(pToProcess,   /* Source */
+                           pProcessed,   /* Destination */
+                           SampleCount); /* Copy all samples */
             }
 
             /*
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index d026e2b..0db7a73 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -15,9 +15,11 @@
  */
 
 #include <cstddef>
+#include <cstdio>
 
 #define LOG_TAG "BundleContext"
 #include <android-base/logging.h>
+#include <audio_utils/power.h>
 #include <Utils.h>
 
 #include "BundleContext.h"
@@ -34,7 +36,7 @@
     std::lock_guard lg(mMutex);
     // init with pre-defined preset NORMAL
     for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-        mBandGaindB[i] = lvm::kSoftPresets[0 /* normal */][i];
+        mBandGainMdB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100;
     }
 
     // allocate lvm instance
@@ -212,7 +214,7 @@
 
         if (eqEnabled) {
             for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-                float bandFactor = mBandGaindB[i] / 15.0;
+                float bandFactor = mBandGainMdB[i] / 1500.0;
                 float bandCoefficient = lvm::kBandEnergyCoefficient[i];
                 float bandEnergy = bandFactor * bandCoefficient * bandCoefficient;
                 if (bandEnergy > 0) energyContribution += bandEnergy;
@@ -221,8 +223,8 @@
             // cross EQ coefficients
             float bandFactorSum = 0;
             for (int i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) {
-                float bandFactor1 = mBandGaindB[i] / 15.0;
-                float bandFactor2 = mBandGaindB[i + 1] / 15.0;
+                float bandFactor1 = mBandGainMdB[i] / 1500.0;
+                float bandFactor2 = mBandGainMdB[i + 1] / 1500.0;
 
                 if (bandFactor1 > 0 && bandFactor2 > 0) {
                     float crossEnergy =
@@ -244,7 +246,7 @@
 
             if (eqEnabled) {
                 for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-                    float bandFactor = mBandGaindB[i] / 15.0;
+                    float bandFactor = mBandGainMdB[i] / 1500.0;
                     float bandCrossCoefficient = lvm::kBassBoostEnergyCrossCoefficient[i];
                     float bandEnergy = boostFactor * bandFactor * bandCrossCoefficient;
                     if (bandEnergy > 0) energyBassBoost += bandEnergy;
@@ -397,15 +399,10 @@
     return db_fix;
 }
 
-// TODO: replace with more generic approach, like: audio_utils_power_from_amplitude
-int16_t BundleContext::VolToDb(uint32_t vol) const {
-    int16_t dB;
-
-    dB = LVC_ToDB_s32Tos16(vol << 7);
-    dB = (dB + 8) >> 4;
-    dB = (dB < -96) ? -96 : dB;
-
-    return dB;
+/* static */
+float BundleContext::VolToDb(float vol) {
+    float dB = audio_utils_power_from_amplitude(vol);
+    return std::max(dB, -96.f);
 }
 
 RetCode BundleContext::setVolumeStereo(const Parameter::VolumeStereo& volume) {
@@ -413,11 +410,12 @@
     LVM_ReturnStatus_en status = LVM_SUCCESS;
 
     // Convert volume to dB
-    int leftdB = VolToDb(volume.left);
-    int rightdB = VolToDb(volume.right);
-    int maxdB = std::max(leftdB, rightdB);
-    int pandB = rightdB - leftdB;
-    setVolumeLevel(maxdB * 100);
+    float leftdB = VolToDb(volume.left);
+    float rightdB = VolToDb(volume.right);
+
+    float maxdB = std::max(leftdB, rightdB);
+    float pandB = rightdB - leftdB;
+    setVolumeLevel(maxdB);
     LOG(DEBUG) << __func__ << " pandB: " << pandB << " maxdB " << maxdB;
 
     {
@@ -441,8 +439,8 @@
     std::vector<Equalizer::BandLevel> bandLevels;
     bandLevels.reserve(lvm::MAX_NUM_BANDS);
     for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-        bandLevels.emplace_back(
-                Equalizer::BandLevel{static_cast<int32_t>(i), lvm::kSoftPresets[presetIdx][i]});
+        bandLevels.emplace_back(Equalizer::BandLevel{static_cast<int32_t>(i),
+                                                     lvm::kSoftPresets[presetIdx][i] * 100});
     }
 
     RetCode ret = updateControlParameter(bandLevels);
@@ -472,7 +470,8 @@
     std::vector<Equalizer::BandLevel> bandLevels;
     bandLevels.reserve(lvm::MAX_NUM_BANDS);
     for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-        bandLevels.emplace_back(Equalizer::BandLevel{static_cast<int32_t>(i), mBandGaindB[i]});
+        bandLevels.emplace_back(
+                Equalizer::BandLevel{static_cast<int32_t>(i), mBandGainMdB[i]});
     }
     return bandLevels;
 }
@@ -506,7 +505,7 @@
     RETURN_VALUE_IF(!isBandLevelIndexInRange(bandLevels), RetCode::ERROR_ILLEGAL_PARAMETER,
                     "indexOutOfRange");
 
-    std::array<int, lvm::MAX_NUM_BANDS> tempLevel;
+    std::array<int, lvm::MAX_NUM_BANDS> tempLevel(mBandGainMdB);
     for (const auto& it : bandLevels) {
         tempLevel[it.index] = it.levelMb;
     }
@@ -520,14 +519,16 @@
         for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
             params.pEQNB_BandDefinition[i].Frequency = lvm::kPresetsFrequencies[i];
             params.pEQNB_BandDefinition[i].QFactor = lvm::kPresetsQFactors[i];
-            params.pEQNB_BandDefinition[i].Gain = tempLevel[i];
+            params.pEQNB_BandDefinition[i].Gain =
+                    tempLevel[i] > 0 ? (tempLevel[i] + 50) / 100 : (tempLevel[i] - 50) / 100;
         }
 
         RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
                         RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
     }
-    mBandGaindB = tempLevel;
-    LOG(INFO) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGaindB);
+    mBandGainMdB = tempLevel;
+    LOG(DEBUG) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGainMdB)
+               << "mdB";
 
     return RetCode::SUCCESS;
 }
@@ -551,18 +552,18 @@
     return limitLevel();
 }
 
-RetCode BundleContext::setVolumeLevel(int level) {
+RetCode BundleContext::setVolumeLevel(float level) {
     if (mMuteEnabled) {
-        mLevelSaved = level / 100;
+        mLevelSaved = level;
     } else {
-        mVolume = level / 100;
+        mVolume = level;
     }
     LOG(INFO) << __func__ << " success with level " << level;
     return limitLevel();
 }
 
-int BundleContext::getVolumeLevel() const {
-    return (mMuteEnabled ? mLevelSaved * 100 : mVolume * 100);
+float BundleContext::getVolumeLevel() const {
+    return (mMuteEnabled ? mLevelSaved : mVolume);
 }
 
 RetCode BundleContext::setVolumeMute(bool mute) {
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index 47d5e5a..62bb6e4 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -80,8 +80,8 @@
     RetCode setBassBoostStrength(int strength);
     int getBassBoostStrength() const { return mBassStrengthSaved; }
 
-    RetCode setVolumeLevel(int level);
-    int getVolumeLevel() const;
+    RetCode setVolumeLevel(float level);
+    float getVolumeLevel() const;
 
     RetCode setVolumeMute(bool mute);
     int getVolumeMute() const { return mMuteEnabled; }
@@ -135,20 +135,20 @@
     int mBassStrengthSaved = 0;
     // Equalizer
     int mCurPresetIdx = lvm::PRESET_CUSTOM; /* Current preset being used */
-    std::array<int, lvm::MAX_NUM_BANDS> mBandGaindB;
+    std::array<int, lvm::MAX_NUM_BANDS> mBandGainMdB; /* band gain in millibels */
     // Virtualizer
     int mVirtStrengthSaved = 0; /* Conversion between Get/Set */
     bool mVirtualizerTempDisabled = false;
     ::aidl::android::media::audio::common::AudioDeviceDescription mForceDevice;
     // Volume
-    int mLevelSaved = 0; /* for when mute is set, level must be saved */
-    int mVolume = 0;
+    float mLevelSaved = 0; /* for when mute is set, level must be saved */
+    float mVolume = 0;
     bool mMuteEnabled = false; /* Must store as mute = -96dB level */
 
     void initControlParameter(LVM_ControlParams_t& params) const;
     void initHeadroomParameter(LVM_HeadroomParams_t& params) const;
     RetCode limitLevel();
-    int16_t VolToDb(uint32_t vol) const;
+    static float VolToDb(float vol);
     LVM_INT16 LVC_ToDB_s32Tos16(LVM_INT32 Lin_fix) const;
     RetCode updateControlParameter(const std::vector<Equalizer::BandLevel>& bandLevels);
     bool isBandLevelIndexInRange(const std::vector<Equalizer::BandLevel>& bandLevels) const;
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index 3bc889c..143329d 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -73,9 +73,9 @@
         MAKE_RANGE(Equalizer, preset, 0, MAX_NUM_PRESETS - 1),
         MAKE_RANGE(Equalizer, bandLevels,
                    std::vector<Equalizer::BandLevel>{
-                           Equalizer::BandLevel({.index = 0, .levelMb = -15})},
+                           Equalizer::BandLevel({.index = 0, .levelMb = -1500})},
                    std::vector<Equalizer::BandLevel>{
-                           Equalizer::BandLevel({.index = MAX_NUM_BANDS - 1, .levelMb = 15})}),
+                           Equalizer::BandLevel({.index = MAX_NUM_BANDS - 1, .levelMb = 1500})}),
         /* capability definition */
         MAKE_RANGE(Equalizer, bandFrequencies, kEqBandFrequency, kEqBandFrequency),
         MAKE_RANGE(Equalizer, presets, kEqPresets, kEqPresets),
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index cd9fb60..eb7ab1a 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -355,7 +355,7 @@
     auto tag = id.get<Volume::Id::commonTag>();
     switch (tag) {
         case Volume::levelDb: {
-            volParam.set<Volume::levelDb>(mContext->getVolumeLevel());
+            volParam.set<Volume::levelDb>(static_cast<int>(mContext->getVolumeLevel()));
             break;
         }
         case Volume::mute: {
@@ -384,6 +384,7 @@
 
     if (id.getTag() == Virtualizer::Id::speakerAnglesPayload) {
         auto angles = mContext->getSpeakerAngles(id.get<Virtualizer::Id::speakerAnglesPayload>());
+        RETURN_IF(angles.size() == 0, EX_ILLEGAL_ARGUMENT, "getSpeakerAnglesFailed");
         Virtualizer param = Virtualizer::make<Virtualizer::speakerAngles>(angles);
         specific->set<Parameter::Specific::virtualizer>(param);
         return ndk::ScopedAStatus::ok();
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 3ebd13e..86ad997 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -102,111 +102,6 @@
     return OK;
 }
 
-static int32_t convertToIntNoSign(const AString &str) {
-    char *end;
-    unsigned long u = strtoul(str.c_str(), &end, 10);
-    if (end == str.c_str() || *end != '\0') {
-        // malformed integer
-        return -1;
-    }
-    if (u > INT32_MAX) {
-        // The number is too big
-        return -1;
-    }
-    return static_cast<int32_t>(u);
-}
-
-static void parseSize(const AString &str, int32_t *width, int32_t *height) {
-    ssize_t ix = str.find("x");
-    if (ix == -1) {
-        ix = str.find("*");
-        if (ix == -1) {
-            return;
-        }
-    }
-    AString wStr(str, 0, ix);
-    AString hStr(str, ix + 1, str.size() - ix - 1);
-    *width = convertToIntNoSign(wStr);
-    *height = convertToIntNoSign(hStr);
-}
-
-static void parseRange(const AString &str, int32_t *min, int32_t *max) {
-    ssize_t ix = str.find("-");
-    if (ix == -1) {
-        return;
-    }
-    AString minStr(str, 0, ix);
-    AString maxStr(str, ix + 1, str.size() - ix - 1);
-    *min = convertToIntNoSign(minStr);
-    *max = convertToIntNoSign(maxStr);
-}
-
-static void parseSizeRange(const AString &str, int32_t *minWidth, int32_t *minHeight,
-                           int32_t *maxWidth, int32_t *maxHeight) {
-    ssize_t ix = str.find("-");
-    if (ix == -1) {
-        return;
-    }
-    AString minSize(str, 0, ix);
-    AString maxSize(str, ix + 1, str.size() - ix - 1);
-    parseSize(minSize, minWidth, minHeight);
-    parseSize(maxSize, maxWidth, maxHeight);
-}
-
-
-bool MediaCodecInfo::Capabilities::isResolutionSupported(int32_t width, int32_t height) {
-    AString blockSizeStr;
-    AString blockCountStr;
-    int32_t blockWidth = -1;
-    int32_t blockHeight = -1;
-    int32_t maxBlocks = -1;
-    int32_t minBlocks = -1;
-
-    if (mDetails->findString("block-size", &blockSizeStr)) {
-        parseSize(blockSizeStr, &blockWidth, &blockHeight);
-    }
-    if (mDetails->findString("block-count-range", &blockCountStr)) {
-        parseRange(blockCountStr, &minBlocks, &maxBlocks);
-    }
-    if (maxBlocks != -1 && blockWidth != -1 && blockHeight != -1) {
-        if (maxBlocks < ((width + blockWidth - 1) / blockWidth) *
-                         ((height + blockHeight - 1) / blockHeight)) {
-            return false;
-        }
-    }
-
-    AString sizeRangeStr;
-    int32_t maxWidth = -1;
-    int32_t maxHeight = -1;
-    int32_t minWidth = -1;
-    int32_t minHeight = -1;
-
-    if (mDetails->findString("size-range", &sizeRangeStr)) {
-        parseSizeRange(sizeRangeStr, &minWidth, &minHeight, &maxWidth, &maxHeight);
-    }
-
-    if (maxWidth != -1 && maxHeight != -1) {
-        // The logic is that the format is not supported if width or height is outside
-        // of min-max limits, UNLESS codec allows to swap it and in this case format is
-        // not supported if width is outside of min-max height or height is outside of
-        // min-max width
-        if (width < minWidth || height < minHeight ||
-            width > maxWidth || height > maxHeight) {
-            int32_t swappable = 0;
-            if (!mDetails->findInt32("feature-can-swap-width-height", &swappable) ||
-                swappable == 0) {
-                return false;
-            }
-            if (width < minHeight || height < minWidth ||
-                width > maxHeight || height > maxWidth) {
-                return false;
-            }
-        }
-    }
-    return true;
-}
-
-
 void MediaCodecInfo::CapabilitiesWriter::addDetail(
         const char* key, const char* value) {
     mCap->mDetails->setString(key, value);
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index 855bc28..54f565a 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -59,7 +59,6 @@
         kFlagIsVendor = 1 << 1,
         kFlagIsSoftwareOnly = 1 << 2,
         kFlagIsHardwareAccelerated = 1 << 3,
-        kFlagIsEnforceXmlCapabilities = 1 << 4,
     };
 
     struct Capabilities : public RefBase {
@@ -97,8 +96,6 @@
          */
         const sp<AMessage> getDetails() const;
 
-        bool isResolutionSupported(int32_t width, int32_t height);
-
     protected:
         Vector<ProfileLevel> mProfileLevels;
         SortedVector<ProfileLevel> mProfileLevelsSorted;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 54ca1ea..e0ebc11 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2048,40 +2048,6 @@
     return configure(format, nativeWindow, crypto, NULL, flags);
 }
 
-bool MediaCodec::isResolutionSupported(const sp<AMessage>& format) {
-    int32_t width = -1;
-    int32_t height = -1;
-    int32_t maxWidth = -1;
-    int32_t maxHeight = -1;
-    format->findInt32("width", &width);
-    format->findInt32("height", &height);
-    format->findInt32("max-width", &maxWidth);
-    format->findInt32("max-height", &maxHeight);
-    AString mediaType;
-    if (!format->findString("mime", &mediaType)) {
-        ALOGI("Can not check mediaFormat: No MIME set.");
-        return true;
-    }
-    sp<MediaCodecInfo::Capabilities> caps = mCodecInfo->getCapabilitiesFor(mediaType.c_str());
-    if (caps == NULL) {
-        ALOGI("Can not get Capabilities for MIME %s.", mediaType.c_str());
-        return true;
-    }
-    if (width != -1 && height != -1) {
-        if (!caps->isResolutionSupported(width, height)) {
-            ALOGD("Frame resolution (%dx%d) is beyond codec capabilities", width, height);
-            return false;
-        }
-    }
-    if (maxWidth != -1 && maxHeight != -1) {
-        if (!caps->isResolutionSupported(maxWidth, maxHeight)) {
-            ALOGD("Max frame resolution (%dx%d) is beyond codec capabilities", maxWidth, maxHeight);
-            return false;
-        }
-    }
-    return true;
-}
-
 status_t MediaCodec::configure(
         const sp<AMessage> &format,
         const sp<Surface> &surface,
@@ -2169,24 +2135,7 @@
             mediametrics_delete(nextMetricsHandle);
             return BAD_VALUE;
         }
-        // For applications built with targetSdkVersion of Android U or later (or if MediaCodec's
-        // caller is not an app) we enforce codec resolution capabilities if such enforcement is
-        // required by 'enforce-xml-capabilities' attribute
-        if (android_get_application_target_sdk_version() >= __ANDROID_API_U__) {
-            if (mCodecInfo != nullptr &&
-                (mCodecInfo->getAttributes() &
-                 MediaCodecInfo::kFlagIsEnforceXmlCapabilities)) {
-                if (!isResolutionSupported(format)) {
-                    mErrorLog.log(LOG_TAG,
-                                  base::StringPrintf("The input resolution of %dx%d is not "
-                                  "supported for this codec; please query MediaCodecList "
-                                  "for the supported formats including the resolution. See "
-                                  "CodecCapabilities#isFormatSupported() and "
-                                  "VideoCapabilities#isSizeSupported()", mWidth, mHeight));
-                    return BAD_VALUE;
-                }
-            }
-        }
+
     } else {
         if (nextMetricsHandle != 0) {
             int32_t channelCount;
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index baa2ca1..574fc1a 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -16,9 +16,16 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "RemoteMediaExtractor"
+
+#include <list>
+#include <pthread.h>
+#include <condition_variable>
+#include <mutex>
+
 #include <utils/Log.h>
 
 #include <binder/IPCThreadState.h>
+#include <cutils/properties.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/MediaMetricsItem.h>
 #include <media/stagefright/MediaSource.h>
@@ -90,10 +97,65 @@
     }
 }
 
+static pthread_t myThread;
+static std::list<sp<DataSource>> pending;
+static std::mutex pending_mutex;
+static std::condition_variable pending_added;
+
+static void* closing_thread_func(void *arg) {
+    while (true) {
+        sp<DataSource> ds = nullptr;
+        std::unique_lock _lk(pending_mutex);
+        pending_added.wait(_lk, []{return !pending.empty();});
+        ALOGV("worker thread wake up with %zu entries", pending.size());
+        if (!pending.empty()) {
+            ds = pending.front();
+            (void) pending.pop_front();
+        }
+        _lk.unlock();       // unique_lock is not scoped
+        if (ds != nullptr) {
+            ds->close();
+        }
+    }
+
+    ALOGE("[unexpected] worker thread quit");
+    return arg;
+}
+
+// this can be '&ds' as long as the pending.push_back() bumps the
+// reference counts to ensure the object lives long enough
+static void start_close_thread(sp<DataSource> &ds) {
+
+    // make sure we have our (single) worker thread
+    static std::once_flag sCheckOnce;
+    std::call_once(sCheckOnce, [&](){
+        pthread_attr_t attr;
+        pthread_attr_init(&attr);
+        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+        pthread_create(&myThread, &attr, closing_thread_func, nullptr);
+        pthread_attr_destroy(&attr);
+    });
+
+    {
+        std::lock_guard _lm(pending_mutex);     // scoped, no explicit unlock
+        pending.push_back(ds);
+    }
+    pending_added.notify_one();     // get the worker thread going
+}
+
 RemoteMediaExtractor::~RemoteMediaExtractor() {
     delete mExtractor;
-    mSource->close();
-    mSource.clear();
+    // TODO(287851984) hook for changing behavior this dynamically, drop after testing
+    int8_t new_scheme = property_get_bool("debug.mediaextractor.delayedclose", 1);
+    if (new_scheme != 0) {
+        ALOGV("deferred close()");
+        start_close_thread(mSource);
+        mSource.clear();
+    } else {
+        ALOGV("immediate close()");
+        mSource->close();
+        mSource.clear();
+    }
     mExtractorPlugin = nullptr;
     // log the current record, provided it has some information worth recording
     if (MEDIA_LOG) {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 144ea53..52d7d3d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -462,7 +462,6 @@
     constexpr const char *asString(TunnelPeekState state, const char *default_string="?");
     void updateTunnelPeek(const sp<AMessage> &msg);
     void processRenderedFrames(const sp<AMessage> &msg);
-    bool isResolutionSupported(const sp<AMessage> &format);
 
     inline void initClientConfigParcel(ClientConfigParcel& clientConfig);
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 817d3a4..02531bd 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -731,24 +731,24 @@
     }
 }
 
-status_t AudioFlinger::addEffectToHal(audio_port_handle_t deviceId,
-        audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
+status_t AudioFlinger::addEffectToHal(
+        const struct audio_port_config *device, const sp<EffectHalInterface>& effect) {
     AutoMutex lock(mHardwareLock);
-    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
+    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(device->ext.device.hw_module);
     if (audioHwDevice == nullptr) {
         return NO_INIT;
     }
-    return audioHwDevice->hwDevice()->addDeviceEffect(deviceId, effect);
+    return audioHwDevice->hwDevice()->addDeviceEffect(device, effect);
 }
 
-status_t AudioFlinger::removeEffectFromHal(audio_port_handle_t deviceId,
-        audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
+status_t AudioFlinger::removeEffectFromHal(
+        const struct audio_port_config *device, const sp<EffectHalInterface>& effect) {
     AutoMutex lock(mHardwareLock);
-    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
+    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(device->ext.device.hw_module);
     if (audioHwDevice == nullptr) {
         return NO_INIT;
     }
-    return audioHwDevice->hwDevice()->removeDeviceEffect(deviceId, effect);
+    return audioHwDevice->hwDevice()->removeDeviceEffect(device, effect);
 }
 
 static const char * const audio_interfaces[] = {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 10bfdb9..c3ca1b0 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -344,10 +344,10 @@
         const sp<os::ExternalVibration>& externalVibration);
     static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
 
-    status_t addEffectToHal(audio_port_handle_t deviceId,
-            audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect);
-    status_t removeEffectFromHal(audio_port_handle_t deviceId,
-            audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect);
+    status_t addEffectToHal(
+            const struct audio_port_config *device, const sp<EffectHalInterface>& effect);
+    status_t removeEffectFromHal(
+            const struct audio_port_config *device, const sp<EffectHalInterface>& effect);
 
     void updateDownStreamPatches_l(const struct audio_patch *patch,
                                    const std::set<audio_io_handle_t>& streams);
diff --git a/services/audioflinger/DeviceEffectManager.h b/services/audioflinger/DeviceEffectManager.h
index 395781d..b87f830 100644
--- a/services/audioflinger/DeviceEffectManager.h
+++ b/services/audioflinger/DeviceEffectManager.h
@@ -44,13 +44,13 @@
     status_t createEffectHal(const effect_uuid_t *pEffectUuid,
            int32_t sessionId, int32_t deviceId,
            sp<EffectHalInterface> *effect);
-    status_t addEffectToHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
+    status_t addEffectToHal(const struct audio_port_config *device,
             const sp<EffectHalInterface>& effect) {
-        return mAudioFlinger.addEffectToHal(deviceId, hwModuleId, effect);
+        return mAudioFlinger.addEffectToHal(device, effect);
     };
-    status_t removeEffectFromHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
+    status_t removeEffectFromHal(const struct audio_port_config *device,
             const sp<EffectHalInterface>& effect) {
-        return mAudioFlinger.removeEffectFromHal(deviceId, hwModuleId, effect);
+        return mAudioFlinger.removeEffectFromHal(device, effect);
     };
 
     AudioFlinger& audioFlinger() const { return mAudioFlinger; }
@@ -132,13 +132,13 @@
 
     int newEffectId() { return mManager.audioFlinger().nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT); }
 
-    status_t addEffectToHal(audio_port_handle_t deviceId,
-            audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
-        return mManager.addEffectToHal(deviceId, hwModuleId, effect);
+    status_t addEffectToHal(const struct audio_port_config *device,
+            const sp<EffectHalInterface>& effect) {
+        return mManager.addEffectToHal(device, effect);
     }
-    status_t removeEffectFromHal(audio_port_handle_t deviceId,
-            audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
-        return mManager.removeEffectFromHal(deviceId, hwModuleId, effect);
+    status_t removeEffectFromHal(const struct audio_port_config *device,
+            const sp<EffectHalInterface>& effect) {
+        return mManager.removeEffectFromHal(device, effect);
     }
 private:
     DeviceEffectManager& mManager;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 77aa804..7c7548a 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -3486,8 +3486,7 @@
     if (mHalEffect == nullptr) {
         return NO_INIT;
     }
-    return mManagerCallback->addEffectToHal(
-            mDevicePort.id, mDevicePort.ext.device.hw_module, effect);
+    return mManagerCallback->addEffectToHal(&mDevicePort, effect);
 }
 
 status_t AudioFlinger::DeviceEffectProxy::removeEffectFromHal(
@@ -3495,8 +3494,7 @@
     if (mHalEffect == nullptr) {
         return NO_INIT;
     }
-    return mManagerCallback->removeEffectFromHal(
-            mDevicePort.id, mDevicePort.ext.device.hw_module, effect);
+    return mManagerCallback->removeEffectFromHal(&mDevicePort, effect);
 }
 
 bool AudioFlinger::DeviceEffectProxy::isOutput() const {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 631fff8..bc2ba31 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -183,7 +183,8 @@
     for (size_t i = 0; i < size(); i++) {
         const sp<AudioPolicyMix>& registeredMix = itemAt(i);
         if (mix.mDeviceType == registeredMix->mDeviceType
-                && mix.mDeviceAddress.compare(registeredMix->mDeviceAddress) == 0) {
+                && mix.mDeviceAddress.compare(registeredMix->mDeviceAddress) == 0
+                && is_mix_loopback(mix.mRouteFlags)) {
             ALOGE("registerMix(): mix already registered for dev=0x%x addr=%s",
                     mix.mDeviceType, mix.mDeviceAddress.string());
             return BAD_VALUE;
@@ -288,9 +289,10 @@
             continue; // skip the mix
         }
 
-        if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
-            // AAudio MMAP_NOIRQ streams cannot be routed using dynamic audio policy.
-            ALOGD("%s: Rejecting MMAP_NOIRQ request matched to dynamic audio policy mix.",
+        if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) && is_mix_loopback(policyMix->mRouteFlags)) {
+            // AAudio MMAP_NOIRQ streams cannot be routed to loopback/loopback+render
+            // using dynamic audio policy.
+            ALOGD("%s: Rejecting MMAP_NOIRQ request matched to loopback dynamic audio policy mix.",
                 __func__);
             return INVALID_OPERATION;
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
index 8ccb8b9..82f51ad 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
@@ -115,12 +115,22 @@
         profile->setDynamicFormat(true);
         profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
         profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
-        addAudioProfileAndSort(audioProfileVector, profile);
+        size_t profileIndex = 0;
+        for (; profileIndex < audioProfileVector.size(); profileIndex++) {
+            if (profile->equals(audioProfileVector.at(profileIndex))) {
+                // The dynamic profile is already there
+                break;
+            }
+        }
+        if (profileIndex >= audioProfileVector.size()) {
+            // Only add when the dynamic profile is not there
+            addAudioProfileAndSort(audioProfileVector, profile);
+        }
     }
 }
 
 void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
-                                      const sp<AudioProfile> &profileToAdd)
+                                   const sp<AudioProfile> &profileToAdd)
 {
     // Check valid profile to add:
     if (!profileToAdd->hasValidFormat()) {
@@ -143,11 +153,15 @@
                 audioProfileVector, profileToAdd->getChannels(), profileToAdd->getFormat());
         return;
     }
+    const bool originalIsDynamicFormat = profileToAdd->isDynamicFormat();
+    profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
     // Go through the list of profile to avoid duplicates
     for (size_t profileIndex = 0; profileIndex < audioProfileVector.size(); profileIndex++) {
         const sp<AudioProfile> &profile = audioProfileVector.at(profileIndex);
-        if (profile->isValid() && profile == profileToAdd) {
-            // Nothing to do
+        if (profile->isValid() && profile->equals(profileToAdd)) {
+            // The same profile is already there, no need to add.
+            // Reset `isDynamicProfile` as original value.
+            profileToAdd->setDynamicFormat(originalIsDynamicFormat);
             return;
         }
     }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 4e758cc..3f2b196 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2148,6 +2148,26 @@
                 return DEAD_OBJECT;
             }
             info->increaseActiveClient();
+            if (info->getActiveClientCount() == 1 &&
+                (info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE) {
+                // If it is first bit-perfect client, reroute all clients that will be routed to
+                // the bit-perfect sink so that it is guaranteed only bit-perfect stream is active.
+                PortHandleVector clientsToInvalidate;
+                for (size_t i = 0; i < mOutputs.size(); i++) {
+                    if (mOutputs[i] == outputDesc ||
+                        !mOutputs[i]->devices().filter(outputDesc->devices()).isEmpty()) {
+                        continue;
+                    }
+                    for (const auto& c : mOutputs[i]->getClientIterable()) {
+                        clientsToInvalidate.push_back(c->portId());
+                    }
+                }
+                if (!clientsToInvalidate.empty()) {
+                    ALOGD("%s Invalidate clients due to first bit-perfect client started",
+                          __func__);
+                    mpClientInterface->invalidateTracks(clientsToInvalidate);
+                }
+            }
         }
     }
 
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index ee2e0eb..1245b1e 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -236,18 +236,15 @@
     sp<EffectHalInterface> effect;
     status = effectsFactoryHal->createEffect(&descriptors[0].uuid, AUDIO_SESSION_OUTPUT_STAGE,
             AUDIO_IO_HANDLE_NONE, AUDIO_PORT_HANDLE_NONE, &effect);
-    ALOGI("%s FX create status %d effect ID %" PRId64, __func__, status,
-          effect ? effect->effectId() : 0);
+    ALOGI("%s FX create status %d effect %p", __func__, status, effect.get());
 
     if (status == NO_ERROR && effect != nullptr) {
         spatializer = new Spatializer(descriptors[0], callback);
         if (spatializer->loadEngineConfiguration(effect) != NO_ERROR) {
             spatializer.clear();
-            ALOGW("%s loadEngine error: %d  effect Id %" PRId64,
-                    __func__, status, effect ? effect->effectId() : 0);
+            ALOGW("%s loadEngine error: %d  effect %p", __func__, status, effect.get());
         } else {
-            spatializer->mLocalLog.log("%s with effect Id %" PRId64, __func__,
-                                       effect ? effect->effectId() : 0);
+            spatializer->mLocalLog.log("%s with effect Id %p", __func__, effect.get());
         }
     }
 
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 7a21aa8..15eae14 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -1350,13 +1350,14 @@
             AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig);
     ASSERT_EQ(INVALID_OPERATION, ret);
 
-    // The first time to register valid policy mixes should succeed.
+    // The first time to register valid loopback policy mix should succeed.
     clearPolicyMix();
-    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
-            AUDIO_DEVICE_OUT_SPEAKER, "", audioConfig);
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "addr", audioConfig);
     ASSERT_EQ(NO_ERROR, ret);
-    // Registering the same policy mixes should fail.
-    ret = mManager->registerPolicyMixes(mAudioMixes);
+    // Registering the render policy for the loopback address should succeed.
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "addr", audioConfig);
     ASSERT_EQ(INVALID_OPERATION, ret);
 }
 
@@ -1911,7 +1912,7 @@
     bool mIsBitPerfect;
 };
 
-TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting, MmapPlaybackStreamMatchingDapMixFails) {
+TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting, MmapPlaybackStreamMatchingLoopbackDapMixFails) {
     // Add mix matching the test uid.
     const int testUid = 12345;
     const auto param = GetParam();
@@ -1928,7 +1929,8 @@
                                          &mOutputType, &mIsSpatialized, &mIsBitPerfect));
 }
 
-TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting, NonMmapPlaybackStreamMatchingDapMixSucceeds) {
+TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting,
+        NonMmapPlaybackStreamMatchingLoopbackDapMixSucceeds) {
     // Add mix matching the test uid.
     const int testUid = 12345;
     const auto param = GetParam();
@@ -1945,15 +1947,30 @@
                                          &mOutputType, &mIsSpatialized, &mIsBitPerfect));
 }
 
+TEST_F(AudioPolicyManagerTestMMapPlaybackRerouting,
+        MmapPlaybackStreamMatchingRenderDapMixSucceeds) {
+      // Add render-only mix matching the test uid.
+    const int testUid = 12345;
+    status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER, AUDIO_DEVICE_OUT_SPEAKER,
+                                /*mixAddress=*/"", audioConfig, {createUidCriterion(testUid)});
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // Geting output for matching uid should succeed for mmaped stream.
+    audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+    ASSERT_EQ(NO_ERROR,
+              mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
+                                         createAttributionSourceState(testUid), &audioConfig,
+                                         &outputFlags, &mSelectedDeviceId, &mPortId, {},
+                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect));
+}
+
 INSTANTIATE_TEST_SUITE_P(
         MmapPlaybackRerouting, AudioPolicyManagerTestMMapPlaybackRerouting,
         testing::Values(DPMmapTestParam(MIX_ROUTE_FLAG_LOOP_BACK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                                         /*deviceAddress=*/"remote_submix_media"),
                         DPMmapTestParam(MIX_ROUTE_FLAG_LOOP_BACK_AND_RENDER,
                                         AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                        /*deviceAddress=*/"remote_submix_media"),
-                        DPMmapTestParam(MIX_ROUTE_FLAG_RENDER, AUDIO_DEVICE_OUT_SPEAKER,
-                                        /*deviceAddress=*/"")));
+                                        /*deviceAddress=*/"remote_submix_media")));
 
 class AudioPolicyManagerTestDPMixRecordInjection : public AudioPolicyManagerTestDynamicPolicy,
         public testing::WithParamInterface<DPTestParam> {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 06ef88a..8348cd9 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -80,9 +80,7 @@
 
     SharedParameters::Lock l(mParameters);
     l.mParameters.state = Parameters::DISCONNECTED;
-    if (forceSlowJpegMode) {
-        l.mParameters.isSlowJpegModeForced = true;
-    }
+    l.mParameters.isSlowJpegModeForced = forceSlowJpegMode;
 }
 
 status_t Camera2Client::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 23570c2..13dcbaa 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -43,6 +43,7 @@
         int cameraFacing) :
         cameraId(cameraId),
         cameraFacing(cameraFacing),
+        isSlowJpegModeForced(false),
         info(NULL),
         mDefaultSceneMode(ANDROID_CONTROL_SCENE_MODE_DISABLED) {
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index cfe51c7..61c3298 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1645,6 +1645,10 @@
     bool stateSeen = false;
     nsecs_t startTime = systemTime();
     do {
+        if (mStatus == STATUS_ERROR) {
+            // Device in error state. Return right away.
+            break;
+        }
         if (active == (mStatus == STATUS_ACTIVE) &&
             (requestThreadInvocation || !mStatusIsInternal)) {
             // Desired state is current
@@ -1674,6 +1678,11 @@
         // they are not paused. This avoids intermediate pause signals from reconfigureCamera as it
         // changes the status to active right after.
         for (size_t i = startIndex; i < mRecentStatusUpdates.size(); i++) {
+            if (mRecentStatusUpdates[i].status == STATUS_ERROR) {
+                // Device in error state. Return right away.
+                stateSeen = true;
+                break;
+            }
             if (active == (mRecentStatusUpdates[i].status == STATUS_ACTIVE) &&
                 (requestThreadInvocation || !mRecentStatusUpdates[i].isInternal)) {
                 stateSeen = true;
@@ -2365,6 +2374,9 @@
             //present streams end up with outstanding buffers that will
             //not get drained.
             internalUpdateStatusLocked(STATUS_ACTIVE);
+
+            mCameraServiceProxyWrapper->logStreamConfigured(mId, mOperatingMode,
+                    true /*internalReconfig*/, ns2ms(systemTime() - startTime));
         } else if (rc == DEAD_OBJECT) {
             // DEAD_OBJECT can be returned if either the consumer surface is
             // abandoned, or the HAL has died.
@@ -2380,9 +2392,6 @@
         ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc);
     }
 
-    mCameraServiceProxyWrapper->logStreamConfigured(mId, mOperatingMode, true /*internalReconfig*/,
-        ns2ms(systemTime() - startTime));
-
     if (markClientActive) {
         mStatusTracker->markComponentActive(clientStatusId);
     }
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index 3aff2ac..b58975f 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -243,12 +243,12 @@
     std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
     {
         Mutex::Autolock l(mLock);
-        sessionStats = mSessionStatsMap[id];
-        if (sessionStats == nullptr) {
+        if (mSessionStatsMap.count(id) == 0) {
             ALOGE("%s: SessionStatsMap should contain camera %s",
                     __FUNCTION__, id.c_str());
             return;
         }
+        sessionStats = mSessionStatsMap[id];
     }
 
     ALOGV("%s: id %s, operatingMode %d, internalConfig %d, latencyMs %d",
@@ -260,12 +260,12 @@
     std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
     {
         Mutex::Autolock l(mLock);
-        sessionStats = mSessionStatsMap[id];
-        if (sessionStats == nullptr) {
+        if (mSessionStatsMap.count(id) == 0) {
             ALOGE("%s: SessionStatsMap should contain camera %s when logActive is called",
                     __FUNCTION__, id.c_str());
             return;
         }
+        sessionStats = mSessionStatsMap[id];
     }
 
     ALOGV("%s: id %s", __FUNCTION__, id.c_str());
@@ -280,13 +280,12 @@
     std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
     {
         Mutex::Autolock l(mLock);
-        sessionStats = mSessionStatsMap[id];
-    }
-
-    if (sessionStats == nullptr) {
-        ALOGE("%s: SessionStatsMap should contain camera %s when logIdle is called",
+        if (mSessionStatsMap.count(id) == 0) {
+            ALOGE("%s: SessionStatsMap should contain camera %s when logIdle is called",
                 __FUNCTION__, id.c_str());
-        return;
+            return;
+        }
+        sessionStats = mSessionStatsMap[id];
     }
 
     ALOGV("%s: id %s, requestCount %" PRId64 ", resultErrorCount %" PRId64 ", deviceError %d"
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index ffd9f01..89e75b3 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -73,11 +73,11 @@
 
     int32_t dynamicDepthKey =
             SessionConfigurationUtils::getAppropriateModeTag(
-                    ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+                    ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, maxRes);
 
     int32_t heicKey =
             SessionConfigurationUtils::getAppropriateModeTag(
-                    ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
+                    ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, maxRes);
 
     getStreamConfigurations(staticInfo, scalerKey, scm);
     getStreamConfigurations(staticInfo, depthKey, scm);