Merge "audio policy: fix capture policy for assistant when running as top" into main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index e9b757b..34ff367 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -30,8 +30,10 @@
 
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               camera/
                media/libaudioclient/tests/
                media/libaudiohal/tests/
                media/libmediatranscoding/
                services/camera/virtualcamera/
                services/mediatranscoding/
+               services/camera/libcameraservice/
diff --git a/camera/Android.bp b/camera/Android.bp
index d91fcb2..25b5e2c 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -54,7 +54,13 @@
 cc_aconfig_library {
     name: "camera_platform_flags_c_lib",
     aconfig_declarations: "camera_platform_flags",
+}
+
+cc_aconfig_library {
+    name: "camera_platform_flags_c_lib_for_test",
+    aconfig_declarations: "camera_platform_flags",
     host_supported: true,
+    mode: "test",
 }
 
 java_aconfig_library {
diff --git a/camera/camera2/SessionConfiguration.cpp b/camera/camera2/SessionConfiguration.cpp
index 2f1f22d..065d283 100644
--- a/camera/camera2/SessionConfiguration.cpp
+++ b/camera/camera2/SessionConfiguration.cpp
@@ -72,17 +72,15 @@
 
     bool hasSessionParameters = false;
     CameraMetadata settings;
-    if (flags::feature_combination_query()) {
-        if ((err = parcel->readBool(&hasSessionParameters)) != OK) {
-            ALOGE("%s: Failed to read hasSessionParameters flag from parcel", __FUNCTION__);
-            return err;
-        }
+    if ((err = parcel->readBool(&hasSessionParameters)) != OK) {
+        ALOGE("%s: Failed to read hasSessionParameters flag from parcel", __FUNCTION__);
+        return err;
+    }
 
-        if (hasSessionParameters) {
-            if ((err = settings.readFromParcel(parcel)) != OK) {
-                ALOGE("%s: Failed to read metadata flag from parcel", __FUNCTION__);
-                return err;
-            }
+    if (hasSessionParameters) {
+        if ((err = settings.readFromParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to read metadata flag from parcel", __FUNCTION__);
+            return err;
         }
     }
 
@@ -94,10 +92,8 @@
     for (auto& stream : outputStreams) {
         mOutputStreams.push_back(stream);
     }
-    if (flags::feature_combination_query()) {
-        mHasSessionParameters = hasSessionParameters;
-        mSessionParameters = std::move(settings);
-    }
+    mHasSessionParameters = hasSessionParameters;
+    mSessionParameters = std::move(settings);
 
     return err;
 }
@@ -125,14 +121,12 @@
     err = parcel->writeParcelableVector(mOutputStreams);
     if (err != OK) return err;
 
-    if (flags::feature_combination_query()) {
-        err = parcel->writeBool(mHasSessionParameters);
-        if (err != OK) return err;
+    err = parcel->writeBool(mHasSessionParameters);
+    if (err != OK) return err;
 
-        if (mHasSessionParameters) {
-            err = mSessionParameters.writeToParcel(parcel);
-            if (err != OK) return err;
-        }
+    if (mHasSessionParameters) {
+        err = mSessionParameters.writeToParcel(parcel);
+        if (err != OK) return err;
     }
 
     return OK;
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index e916985..db33dd7 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -27,20 +27,6 @@
 
 flag {
     namespace: "camera_platform"
-    name: "watch_foreground_changes"
-    description: "Request AppOps to notify changes in the foreground status of the client"
-    bug: "290086710"
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "log_ultrawide_usage"
-    description: "Enable measuring how much usage there is for ultrawide-angle cameras"
-    bug: "300515796"
-}
-
-flag {
-    namespace: "camera_platform"
     name: "camera_manual_flash_strength_control"
     is_exported: true
     description: "Flash brightness level control in manual flash mode"
@@ -49,27 +35,6 @@
 
 flag {
     namespace: "camera_platform"
-    name: "lazy_aidl_wait_for_service"
-    description: "Use waitForService instead of getService with lazy AIDL HALs"
-    bug: "285546208"
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "log_zoom_override_usage"
-    description: "Enable measuring how much usage there is for zoom settings overrde"
-    bug: "307409002"
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "session_hal_buf_manager"
-    description: "Enable or disable HAL buffer manager as requested by the camera HAL"
-    bug: "311263114"
-}
-
-flag {
-    namespace: "camera_platform"
     name: "inject_session_params"
     description: "Enable session parameter injection via reconfiguration"
     bug: "308984721"
@@ -92,13 +57,6 @@
 
 flag {
     namespace: "camera_platform"
-    name: "use_ro_board_api_level_for_vndk_version"
-    description: "Enable using ro.board.api_level instead of ro.vndk.version to get VNDK version"
-    bug: "312315580"
-}
-
-flag {
-    namespace: "camera_platform"
     name: "camera_extensions_characteristics_get"
     is_exported: true
     description: "Enable get extension specific camera characteristics API"
@@ -107,13 +65,6 @@
 
 flag {
     namespace: "camera_platform"
-    name: "delay_lazy_hal_instantiation"
-    description: "Only trigger lazy HAL instantiation when the HAL is needed for an operation."
-    bug: "319735068"
-}
-
-flag {
-    namespace: "camera_platform"
     name: "return_buffers_outside_locks"
     description: "Enable returning graphics buffers to buffer queues without holding the in-flight mutex"
     bug: "315526878"
@@ -137,16 +88,6 @@
 
 flag {
     namespace: "camera_platform"
-    name: "surface_ipc"
-    description: "Optimize Surface binder IPC"
-    bug: "323292530"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "camera_platform"
     name: "extension_10_bit"
     is_exported: true
     description: "Enables 10-bit support in the camera extensions."
@@ -155,57 +96,9 @@
 
 flag {
     namespace: "camera_platform"
-    name: "single_thread_executor"
-    description: "Ensure device logic is run within one thread."
-    bug: "305857746"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "surface_leak_fix"
-    description: "Address Surface release leaks in CaptureRequest"
-    bug: "324071855"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "concert_mode_api"
-    description: "Covers the eyes free videography public facing API"
-    bug: "297083874"
-}
-
-
-flag {
-    namespace: "camera_platform"
-    name: "cache_permission_services"
-    description: "Cache IPermissionController and IPermissionChecker in CameraService to reduce query latency."
-    bug: "326139956"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "check_session_support_before_session_char"
-    description: "Validate that a SessionConfiguration is supported before fetching SessionCharacteristics."
-    bug: "327008530"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "calculate_perf_override_during_session_support"
-    description: "Dynamically calulate whether perf class override should be set in isSessionConfigurationWithParametersSupported."
-    bug: "332975108"
+    name: "single_thread_executor_naming"
+    description: "Set the device executor thread name."
+    bug: "359709863"
     metadata {
         purpose: PURPOSE_BUGFIX
     }
@@ -220,26 +113,6 @@
 
 flag {
     namespace: "camera_platform"
-    name: "realtime_priority_bump"
-    description: "Bump the scheduling priority of performance critical code paths"
-    bug: "336628522"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "camera_platform"
-    name: "use_system_api_for_vndk_version"
-    description: "ro.board.api_level isn't reliable. Use system api to replace ro.vndk.version"
-    bug: "312315580"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "camera_platform"
     name: "multi_res_raw_reprocessing"
     description: "Allow multi-resolution raw reprocessing without reprocessing capability"
     bug: "336922859"
@@ -276,4 +149,25 @@
     metadata {
         purpose: PURPOSE_BUGFIX
     }
-}
\ No newline at end of file
+}
+
+flag {
+    namespace: "camera_platform"
+    name: "enable_hal_abort_from_cameraservicewatchdog"
+    description: "Enable CameraServiceWatchdog to abort camera HAL to generate HAL tombstones"
+    bug: "349652177"
+}
+
+flag {
+    namespace: "camera_platform"
+    name: "enable_stream_reconfiguration_for_unchanged_streams"
+    description: "Enable stream reconfiguration for unchanged streams"
+    bug: "341740105"
+}
+
+flag {
+    namespace: "camera_platform"
+    name: "use_context_attribution_source"
+    description: "Use the context-provided AttributionSource when checking for client permissions"
+    bug: "190657833"
+}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 6862cb1..d0df90b 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -22,6 +22,11 @@
     default_applicable_licenses: ["frameworks_av_camera_license"],
 }
 
+vintf_fragment {
+    name: "manifest_android.frameworks.cameraservice.service.xml",
+    src: "manifest_android.frameworks.cameraservice.service.xml",
+}
+
 cc_binary {
     name: "cameraserver",
 
@@ -61,7 +66,7 @@
 
     init_rc: ["cameraserver.rc"],
 
-    vintf_fragments: [
+    vintf_fragment_modules: [
         "manifest_android.frameworks.cameraservice.service.xml",
     ],
 }
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 6d29ef5..53c4489 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -170,97 +170,78 @@
 }
 
 sp<hardware::ICameraService> CameraManagerGlobal::getCameraServiceLocked() {
-    if (mCameraService.get() == nullptr) {
-        if (CameraUtils::isCameraServiceDisabled()) {
-            return mCameraService;
-        }
+    if (mCameraService.get() != nullptr) {
+        return mCameraService;
+    }
+    if (CameraUtils::isCameraServiceDisabled()) {
+        return mCameraService;
+    }
 
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder;
-        binder = sm->checkService(String16(kCameraServiceName));
-        if (binder == nullptr) {
-            ALOGE("%s: Could not get CameraService instance.", __FUNCTION__);
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder;
+    binder = sm->checkService(String16(kCameraServiceName));
+    if (binder == nullptr) {
+        ALOGE("%s: Could not get CameraService instance.", __FUNCTION__);
+        return nullptr;
+    }
+    sp<hardware::ICameraService> cameraService = interface_cast<hardware::ICameraService>(binder);
+    if (mDeathNotifier == nullptr) {
+        mDeathNotifier = new DeathNotifier(this);
+        binder->linkToDeath(mDeathNotifier);
+    }
+
+    // Setup looper thread to perform availability callbacks
+    if (mCbLooper == nullptr) {
+        mCbLooper = new ALooper;
+        mCbLooper->setName("C2N-mgr-looper");
+        status_t err = mCbLooper->start(
+                /*runOnCallingThread*/false,
+                /*canCallJava*/       true,
+                PRIORITY_DEFAULT);
+        if (err != OK) {
+            ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
+                    __FUNCTION__, strerror(-err), err);
+            mCbLooper.clear();
             return nullptr;
         }
-        if (mDeathNotifier == nullptr) {
-            mDeathNotifier = new DeathNotifier(this);
+        if (mHandler == nullptr) {
+            mHandler = new CallbackHandler(this);
         }
-        binder->linkToDeath(mDeathNotifier);
-        mCameraService = interface_cast<hardware::ICameraService>(binder);
+        mCbLooper->registerHandler(mHandler);
+    }
 
-        // Setup looper thread to perfrom availiability callbacks
-        if (mCbLooper == nullptr) {
-            mCbLooper = new ALooper;
-            mCbLooper->setName("C2N-mgr-looper");
-            status_t err = mCbLooper->start(
-                    /*runOnCallingThread*/false,
-                    /*canCallJava*/       true,
-                    PRIORITY_DEFAULT);
-            if (err != OK) {
-                ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
-                        __FUNCTION__, strerror(-err), err);
-                mCbLooper.clear();
-                return nullptr;
-            }
-            if (mHandler == nullptr) {
-                mHandler = new CallbackHandler(this);
-            }
-            mCbLooper->registerHandler(mHandler);
+    // register ICameraServiceListener
+    std::vector<hardware::CameraStatus> cameraStatuses{};
+    if (mCameraServiceListener == nullptr) {
+        mCameraServiceListener = new CameraServiceListener(this);
+        cameraService->addListener(mCameraServiceListener, &cameraStatuses);
+    }
+
+    for (auto& c : cameraStatuses) {
+        onStatusChangedLocked(c.status, c.deviceId, c.cameraId);
+
+        for (auto& unavailablePhysicalId : c.unavailablePhysicalIds) {
+            onStatusChangedLocked(hardware::ICameraServiceListener::STATUS_NOT_PRESENT,
+                                    c.deviceId, c.cameraId, unavailablePhysicalId);
         }
+    }
+    // setup vendor tags
+    if (!setupVendorTags(cameraService)) {
+        ALOGE("%s: Vendor tag descriptor cache couldn't be set up", __FUNCTION__);
+        return nullptr;
+    }
 
-        // register ICameraServiceListener
-        if (mCameraServiceListener == nullptr) {
-            mCameraServiceListener = new CameraServiceListener(this);
-        }
-        std::vector<hardware::CameraStatus> cameraStatuses{};
-        mCameraService->addListener(mCameraServiceListener, &cameraStatuses);
-        for (auto& c : cameraStatuses) {
-            onStatusChangedLocked(c.status, c.deviceId, c.cameraId);
+    mCameraService = cameraService;
+    ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
+    return mCameraService;
+}
 
-            for (auto& unavailablePhysicalId : c.unavailablePhysicalIds) {
-                onStatusChangedLocked(hardware::ICameraServiceListener::STATUS_NOT_PRESENT,
-                                      c.deviceId, c.cameraId, unavailablePhysicalId);
-            }
-        }
-
-        // setup vendor tags
-        sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
-        binder::Status ret = mCameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
-
-        if (ret.isOk()) {
-            if (0 < desc->getTagCount()) {
-                status_t err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
-                if (err != OK) {
-                    ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
-                            __FUNCTION__, strerror(-err), err);
-                }
-            } else {
-                sp<VendorTagDescriptorCache> cache =
-                        new VendorTagDescriptorCache();
-                binder::Status res =
-                        mCameraService->getCameraVendorTagCache(
-                                /*out*/cache.get());
-                if (res.serviceSpecificErrorCode() ==
-                        hardware::ICameraService::ERROR_DISCONNECTED) {
-                    // No camera module available, not an error on devices with no cameras
-                    VendorTagDescriptorCache::clearGlobalVendorTagCache();
-                } else if (res.isOk()) {
-                    status_t err =
-                            VendorTagDescriptorCache::setAsGlobalVendorTagCache(
-                                    cache);
-                    if (err != OK) {
-                        ALOGE("%s: Failed to set vendor tag cache,"
-                                "received error %s (%d)", __FUNCTION__,
-                                strerror(-err), err);
-                    }
-                } else {
-                    VendorTagDescriptorCache::clearGlobalVendorTagCache();
-                    ALOGE("%s: Failed to setup vendor tag cache: %s",
-                            __FUNCTION__, res.toString8().c_str());
-                }
-            }
-        } else if (ret.serviceSpecificErrorCode() ==
-                hardware::ICameraService::ERROR_DEPRECATED_HAL) {
+bool CameraManagerGlobal::setupVendorTags(sp<hardware::ICameraService> &cameraService) {
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    binder::Status ret = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
+    if (!ret.isOk()) {
+        if (ret.serviceSpecificErrorCode() ==
+            hardware::ICameraService::ERROR_DEPRECATED_HAL) {
             ALOGW("%s: Camera HAL too old; does not support vendor tags",
                     __FUNCTION__);
             VendorTagDescriptor::clearGlobalVendorTagDescriptor();
@@ -268,9 +249,45 @@
             ALOGE("%s: Failed to get vendor tag descriptors: %s",
                     __FUNCTION__, ret.toString8().c_str());
         }
+        return false;
     }
-    ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
-    return mCameraService;
+
+    if (0 < desc->getTagCount()) {
+        status_t err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+        if (err != OK) {
+            ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
+                    __FUNCTION__, strerror(-err), err);
+            return false;
+        }
+    } else {
+        sp<VendorTagDescriptorCache> cache =
+                new VendorTagDescriptorCache();
+        binder::Status res =
+                cameraService->getCameraVendorTagCache(
+                        /*out*/cache.get());
+        if (res.serviceSpecificErrorCode() ==
+                hardware::ICameraService::ERROR_DISCONNECTED) {
+            // No camera module available, not an error on devices with no cameras
+            VendorTagDescriptorCache::clearGlobalVendorTagCache();
+        } else if (res.isOk()) {
+            status_t err =
+                    VendorTagDescriptorCache::setAsGlobalVendorTagCache(
+                            cache);
+            if (err != OK) {
+                ALOGE("%s: Failed to set vendor tag cache,"
+                        "received error %s (%d)", __FUNCTION__,
+                        strerror(-err), err);
+                return false;
+            }
+        } else {
+            VendorTagDescriptorCache::clearGlobalVendorTagCache();
+            ALOGE("%s: Failed to setup vendor tag cache: %s",
+                    __FUNCTION__, res.toString8().c_str());
+            return false;
+        }
+    }
+
+    return true;
 }
 
 void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
@@ -290,6 +307,8 @@
                                       key.cameraId);
         }
         cm->mCameraService.clear();
+        cm->mCameraServiceListener.clear();
+        cm->mDeathNotifier.clear();
         // TODO: consider adding re-connect call here?
     }
 }
@@ -398,6 +417,9 @@
 bool CameraManagerGlobal::supportsCamera2ApiLocked(const std::string &cameraId) {
     bool camera2Support = false;
     auto cs = getCameraServiceLocked();
+    if (cs == nullptr) {
+        return false;
+    }
     binder::Status serviceRet =
         cs->supportsCameraApi(cameraId,
                 hardware::ICameraService::API_VERSION_2, &camera2Support);
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index f4124ef..cb7a4ff 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -105,6 +105,8 @@
     template <class T>
     void registerAvailCallback(const DeviceContext& deviceContext, const T* callback);
 
+    bool setupVendorTags(sp<hardware::ICameraService> &cameraService);
+
     class DeathNotifier : public IBinder::DeathRecipient {
       public:
         explicit DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 7d234bb..7fb2d05 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -91,7 +91,6 @@
     ACAMERA_AUTOMOTIVE_LENS,
     ACAMERA_EXTENSION,
     ACAMERA_JPEGR,
-    ACAMERA_EFV,
     ACAMERA_SECTION_COUNT,
 
     ACAMERA_VENDOR = 0x8000
@@ -139,7 +138,6 @@
     ACAMERA_AUTOMOTIVE_LENS_START  = ACAMERA_AUTOMOTIVE_LENS   << 16,
     ACAMERA_EXTENSION_START        = ACAMERA_EXTENSION         << 16,
     ACAMERA_JPEGR_START            = ACAMERA_JPEGR             << 16,
-    ACAMERA_EFV_START              = ACAMERA_EFV               << 16,
     ACAMERA_VENDOR_START           = ACAMERA_VENDOR            << 16
 } acamera_metadata_section_start_t;
 
@@ -482,10 +480,21 @@
      * camera device auto-exposure routine for the overridden
      * fields for a given capture will be available in its
      * CaptureResult.</p>
+     * <p>When ACAMERA_CONTROL_AE_MODE is AE_MODE_ON and if the device
+     * supports manual flash strength control, i.e.,
+     * if ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
+     * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1, then
+     * the auto-exposure (AE) precapture metering sequence should be
+     * triggered to avoid the image being incorrectly exposed at
+     * different ACAMERA_FLASH_STRENGTH_LEVEL.</p>
      *
+     * @see ACAMERA_CONTROL_AE_MODE
      * @see ACAMERA_CONTROL_MODE
      * @see ACAMERA_FLASH_INFO_AVAILABLE
      * @see ACAMERA_FLASH_MODE
+     * @see ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
+     * @see ACAMERA_FLASH_STRENGTH_LEVEL
+     * @see ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL
      * @see ACAMERA_SENSOR_EXPOSURE_TIME
      * @see ACAMERA_SENSOR_FRAME_DURATION
      * @see ACAMERA_SENSOR_SENSITIVITY
@@ -646,9 +655,14 @@
      * be made, and for firing pre-capture flash pulses to estimate
      * scene brightness and required final capture flash power, when
      * the flash is enabled.</p>
-     * <p>Normally, this entry should be set to START for only a
-     * single request, and the application should wait until the
-     * sequence completes before starting a new one.</p>
+     * <p>Flash is enabled during precapture sequence when:</p>
+     * <ul>
+     * <li>AE mode is ON_ALWAYS_FLASH</li>
+     * <li>AE mode is ON_AUTO_FLASH and the scene is deemed too dark without flash, or</li>
+     * <li>AE mode is ON and flash mode is TORCH or SINGLE</li>
+     * </ul>
+     * <p>Normally, this entry should be set to START for only single request, and the
+     * application should wait until the sequence completes before starting a new one.</p>
      * <p>When a precapture metering sequence is finished, the camera device
      * may lock the auto-exposure routine internally to be able to accurately expose the
      * subsequent still capture image (<code>ACAMERA_CONTROL_CAPTURE_INTENT == STILL_CAPTURE</code>).
@@ -2289,8 +2303,6 @@
      * boost when the light level threshold is exceeded.</p>
      * <p>This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
      * indicate when it is not being applied by returning 'INACTIVE'.</p>
-     * <p>This key will be absent from the CaptureResult if AE mode is not set to
-     * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
      * <p>The default value will always be 'INACTIVE'.</p>
      */
     ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE =                     // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
@@ -2448,6 +2460,13 @@
      * in ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL.
      * If ACAMERA_CONTROL_AE_MODE is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>,
      * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p>
+     * <p>When AE mode is ON and flash mode is TORCH or SINGLE, the application should make sure
+     * the AE mode, flash mode, and flash strength level remain the same between precapture
+     * trigger request and final capture request. The flash strength level being set during
+     * precapture sequence is used by the camera device as a reference. The actual strength
+     * may be less, and the auto-exposure routine makes sure proper conversions of sensor
+     * exposure time and sensitivities between precapture and final capture for the specified
+     * strength level.</p>
      *
      * @see ACAMERA_CONTROL_AE_MODE
      * @see ACAMERA_FLASH_MODE
@@ -8225,7 +8244,17 @@
      * ACAMERA_SENSOR_FRAME_DURATION are ignored. The
      * application has control over the various
      * ACAMERA_FLASH_* fields.</p>
+     * <p>If the device supports manual flash strength control, i.e.,
+     * if ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
+     * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1, then
+     * the auto-exposure (AE) precapture metering sequence should be
+     * triggered for the configured flash mode and strength to avoid
+     * the image being incorrectly exposed at different
+     * ACAMERA_FLASH_STRENGTH_LEVEL.</p>
      *
+     * @see ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
+     * @see ACAMERA_FLASH_STRENGTH_LEVEL
+     * @see ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL
      * @see ACAMERA_SENSOR_EXPOSURE_TIME
      * @see ACAMERA_SENSOR_FRAME_DURATION
      * @see ACAMERA_SENSOR_SENSITIVITY
@@ -11563,7 +11592,6 @@
 
 
 
-
 __END_DECLS
 
 #endif /* _NDK_CAMERA_METADATA_TAGS_H */
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index cdba8ff..5b69f5c 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -194,11 +194,11 @@
     return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0);
 }
 
-bool CameraManagerGlobal::setupVendorTags() {
+bool CameraManagerGlobal::setupVendorTags(std::shared_ptr<ICameraService> &cameraService) {
     sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
     Status status = Status::NO_ERROR;
     std::vector<ProviderIdAndVendorTagSections> providerIdsAndVts;
-    ScopedAStatus remoteRet = mCameraService->getCameraVendorTagSections(&providerIdsAndVts);
+    ScopedAStatus remoteRet = cameraService->getCameraVendorTagSections(&providerIdsAndVts);
 
     if (!remoteRet.isOk()) {
         if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
@@ -261,15 +261,12 @@
         ALOGE("%s: Could not get ICameraService instance.", __FUNCTION__);
         return nullptr;
     }
-
     if (mDeathRecipient.get() == nullptr) {
         mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
                 AIBinder_DeathRecipient_new(CameraManagerGlobal::binderDeathCallback));
+        AIBinder_linkToDeath(cameraService->asBinder().get(),
+                             mDeathRecipient.get(), /*cookie=*/ this);
     }
-    AIBinder_linkToDeath(cameraService->asBinder().get(),
-                         mDeathRecipient.get(), /*cookie=*/ this);
-
-    mCameraService = cameraService;
 
     // Setup looper thread to perform availability callbacks
     if (mCbLooper == nullptr) {
@@ -291,33 +288,25 @@
         mCbLooper->registerHandler(mHandler);
     }
 
+    std::vector<CameraStatusAndId> cameraStatuses;
     // register ICameraServiceListener
     if (mCameraServiceListener == nullptr) {
         mCameraServiceListener = ndk::SharedRefBase::make<CameraServiceListener>(weak_from_this());
-    }
-
-    std::vector<CameraStatusAndId> cameraStatuses;
-    Status status = Status::NO_ERROR;
-    ScopedAStatus remoteRet = mCameraService->addListener(mCameraServiceListener,
-                                                          &cameraStatuses);
-
-    if (!remoteRet.isOk()) {
-        if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
-            Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
-            ALOGE("%s: Failed to add listener to camera service: %s", __FUNCTION__,
-                toString(errStatus).c_str());
-        } else {
-            ALOGE("%s: Transaction failed when adding listener to camera service: %d",
-                __FUNCTION__, remoteRet.getExceptionCode());
+        ScopedAStatus remoteRet = cameraService->addListener(mCameraServiceListener,
+                                                            &cameraStatuses);
+        if (!remoteRet.isOk()) {
+            if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+                Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+                ALOGE("%s: Failed to add listener to camera service: %s", __FUNCTION__,
+                    toString(errStatus).c_str());
+            } else {
+                ALOGE("%s: Transaction failed when adding listener to camera service: %d",
+                    __FUNCTION__, remoteRet.getExceptionCode());
+            }
+            return nullptr;
         }
     }
 
-    // Setup vendor tags
-    if (!setupVendorTags()) {
-        ALOGE("Unable to set up vendor tags");
-        return nullptr;
-    }
-
     for (auto& csi: cameraStatuses){
         onStatusChangedLocked(csi.deviceStatus, csi.cameraId);
 
@@ -326,6 +315,13 @@
                                   csi.cameraId, unavailablePhysicalId);
         }
     }
+
+   // Setup vendor tags
+    if (!setupVendorTags(cameraService)) {
+        ALOGE("Unable to set up vendor tags");
+        return nullptr;
+    }
+    mCameraService = cameraService;
     return mCameraService;
 }
 
@@ -346,6 +342,8 @@
         instance->onStatusChangedLocked(deviceStatus, cameraId);
     }
     instance->mCameraService.reset();
+    instance->mDeathRecipient.release();
+    instance->mCameraServiceListener.reset();
     // TODO: consider adding re-connect call here?
 }
 
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 2d8eefa..5688e76 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -188,7 +188,7 @@
                          const std::string &physicalCameraId);
     void onStatusChangedLocked(const CameraDeviceStatus &status, const std::string &cameraId,
                                const std::string &physicalCameraId);
-    bool setupVendorTags();
+    bool setupVendorTags(std::shared_ptr<ICameraService> &cameraService);
 
     // Utils for status
     static bool validStatus(CameraDeviceStatus status);
diff --git a/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
index f046785..97a8cc4 100644
--- a/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
+++ b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
@@ -35,7 +35,8 @@
 class DrmRemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
   public:
     DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm, std::string drmVendor,
-                                    std::string drmDesc, std::vector<uint8_t> bcc);
+                                    std::string drmDesc, std::vector<uint8_t> bcc,
+                                    std::vector<uint8_t> bcc_signature);
     ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
 
     ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
@@ -60,6 +61,7 @@
     std::string mDrmVendor;
     std::string mDrmDesc;
     std::vector<uint8_t> mBcc;
+    std::vector<uint8_t> mBccSignature;
 };
 }  // namespace android::mediadrm
 
diff --git a/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
index 440be79..65054b0 100644
--- a/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
+++ b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
@@ -28,11 +28,13 @@
 DrmRemotelyProvisionedComponent::DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm,
                                                                  std::string drmVendor,
                                                                  std::string drmDesc,
-                                                                 std::vector<uint8_t> bcc)
+                                                                 std::vector<uint8_t> bcc,
+                                                                 std::vector<uint8_t> bcc_signature)
     : mDrm(std::move(drm)),
       mDrmVendor(std::move(drmVendor)),
       mDrmDesc(std::move(drmDesc)),
-      mBcc(std::move(bcc)) {}
+      mBcc(std::move(bcc)),
+      mBccSignature(std::move(bcc_signature)) {}
 
 ScopedAStatus DrmRemotelyProvisionedComponent::getHardwareInfo(RpcHardwareInfo* info) {
     info->versionNumber = 3;
@@ -107,7 +109,7 @@
     for (auto i : keyToProp) {
         auto key = i.first;
         auto prop = i.second;
-        const auto& val= deviceInfoMap.get(key);
+        const auto& val = deviceInfoMap.get(key);
         if (val == nullptr || val->asTstr()->value().empty()) {
             std::string propValue = android::base::GetProperty(prop, "");
             if (propValue.empty()) {
@@ -161,12 +163,16 @@
     }
 
     // assemble AuthenticatedRequest (definition in IRemotelyProvisionedComponent.aidl)
-    *out = cppbor::Array()
-                   .add(1 /* version */)
-                   .add(cppbor::Map() /* UdsCerts */)
-                   .add(cppbor::EncodedItem(mBcc))
-                   .add(cppbor::EncodedItem(std::move(deviceSignedCsrPayload)))
-                   .encode();
+    cppbor::Array request_array = cppbor::Array().add(1 /* version */);
+    if (!mBccSignature.empty()) {
+        request_array.add(cppbor::EncodedItem(mBccSignature) /* UdsCerts */);
+    } else {
+        request_array.add(cppbor::Map() /* empty UdsCerts */);
+    }
+    request_array.add(cppbor::EncodedItem(mBcc))
+            .add(cppbor::EncodedItem(std::move(deviceSignedCsrPayload)));
+    *out = request_array.encode();
+
     return ScopedAStatus::ok();
 }
 }  // namespace android::mediadrm
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
index 515d157..750b51e 100644
--- a/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
+++ b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
@@ -87,13 +87,21 @@
                           status.getDescription().c_str());
                     return;
                 }
-
+                std::vector<uint8_t> bcc_signature;
+                status =
+                        mDrm->getPropertyByteArray("bootCertificateChainSignature", &bcc_signature);
+                if (!status.isOk()) {
+                    ALOGW("mDrm->getPropertyByteArray(\"bootCertificateChainSignature\") failed."
+                          "Detail: [%s].",
+                          status.getDescription().c_str());
+                    // bcc signature is optional, no need to return when it is unavailable.
+                }
                 std::string compName(instance);
                 auto comps = static_cast<
                         std::map<std::string, std::shared_ptr<IRemotelyProvisionedComponent>>*>(
                         context);
                 (*comps)[compName] = ::ndk::SharedRefBase::make<DrmRemotelyProvisionedComponent>(
-                        mDrm, drmVendor, drmDesc, bcc);
+                        mDrm, drmVendor, drmDesc, bcc, bcc_signature);
             });
     return comps;
 }
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
index 1bb3da6..079e075 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -86,7 +86,7 @@
     ],
     srcs: ["Service.cpp"],
     init_rc: ["android.hardware.drm-service.clearkey.rc"],
-    vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+    vintf_fragment_modules: ["android.hardware.drm-service.clearkey.xml_vintf"],
 }
 
 cc_binary {
@@ -98,7 +98,13 @@
     overrides: ["android.hardware.drm-service.clearkey"],
     srcs: ["ServiceLazy.cpp"],
     init_rc: ["android.hardware.drm-service-lazy.clearkey.rc"],
-    vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+    vintf_fragment_modules: ["android.hardware.drm-service.clearkey.xml_vintf"],
+}
+
+vintf_fragment {
+    name: "android.hardware.drm-service.clearkey.xml_vintf",
+    src: "android.hardware.drm-service.clearkey.xml",
+    vendor: true,
 }
 
 cc_binary {
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 1a637ac..695cad6 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -45,6 +45,32 @@
             "file_patterns": ["(?i)drm|crypto"]
         }
     ],
+    "postsubmit": [
+        {
+            "name": "MctsMediaCodecTestCases",
+            "options": [
+                {
+                    "include-filter": "android.media.codec.cts.EncodeDecodeTest"
+                }
+            ]
+        },
+        {
+            "name": "MctsMediaCodecTestCases",
+            "options": [
+                {
+                    "include-filter": "android.media.codec.cts.DecodeEditEncodeTest"
+                }
+            ]
+        },
+        {
+            "name": "MctsMediaCodecTestCases",
+            "options": [
+                {
+                    "include-filter": "android.media.codec.cts.ExtractDecodeEditEncodeMuxTest"
+                }
+            ]
+        }
+    ],
     // Postsubmit tests for TV devices
     "tv-postsubmit": [
         {
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index 362e98e..ed1522b 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -13,6 +13,26 @@
 }
 
 flag {
+  name: "codec_buffer_state_cleanup"
+  namespace: "codec_fwk"
+  description: "Bugfix flag for more buffer state cleanup in MediaCodec"
+  bug: "343502509"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
+  name: "dataspace_v0_partial"
+  namespace: "codec_fwk"
+  description: "Bugfix flag for using V0 dataspace in some cases"
+  bug: "313827126"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "dynamic_color_aspects"
   is_exported: true
   namespace: "codec_fwk"
@@ -98,6 +118,16 @@
 }
 
 flag {
+  name: "secure_codecs_require_crypto"
+  namespace: "codec_fwk"
+  description: "Bugfix flag for requiring setting crypto for secure codecs"
+  bug: "365162324"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "set_callback_stall"
   namespace: "codec_fwk"
   description: "Bugfix flag for setCallback stall"
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index de8aca7..a5aeff2 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -50,6 +50,23 @@
 }
 
 cc_aconfig_library {
+    name: "com.android.media.audioserver-aconfig-cc-ro",
+    aconfig_declarations: "com.android.media.audioserver-aconfig",
+    defaults: ["audio-aconfig-cc-defaults"],
+    double_loadable: true,
+    host_supported: true,
+    product_available: true,
+    vendor_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
+    mode: "force-read-only",
+}
+
+cc_aconfig_library {
     name: "com.android.media.audio-aconfig-cc",
     aconfig_declarations: "com.android.media.audio-aconfig",
     defaults: ["audio-aconfig-cc-defaults"],
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index 9221c04..c732708 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -60,6 +60,15 @@
 }
 
 flag {
+    name: "equal_sco_lea_vc_index_range"
+    namespace: "media_audio"
+    description:
+        "Introduce the same index range for voice calls over SCO and "
+        "LE audio"
+    bug: "364364777"
+}
+
+flag {
     name: "music_fx_edge_to_edge"
     namespace: "media_audio"
     description: "Enable Edge-to-edge feature for MusicFx and handle insets"
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 0209e28..411996e 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -22,6 +22,13 @@
     bug: "302323921"
 }
 
+flag{
+    name: "enable_ringtone_haptics_customization"
+    namespace: "media_audio"
+    description: "Enables haptic customization for playing ringtone."
+    bug: "351974934"
+}
+
 flag {
     name: "feature_spatial_audio_headtracking_low_latency"
     is_exported: true
@@ -40,6 +47,14 @@
     bug: "316414750"
 }
 
+flag {
+    name: "dolby_ac4_level4_encoding_api"
+    namespace: "media_audio"
+    description: "Feature flag for Dolby AC-4 level 4 AudioFormat encoding."
+    is_fixed_read_only: true
+    bug: "266537650"
+}
+
 # TODO remove
 flag {
     name: "foreground_audio_control"
@@ -86,6 +101,13 @@
 }
 
 flag {
+    name: "muted_by_port_volume_api"
+    namespace: "media_audio"
+    description: "Playback monitoring flag used when player muted by port volume"
+    bug: "319515324"
+}
+
+flag {
     name: "sco_managed_by_audio"
     is_exported: true
     namespace: "media_audio"
diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig
index d1c6239..1ce4d00 100644
--- a/media/audio/aconfig/audioserver.aconfig
+++ b/media/audio/aconfig/audioserver.aconfig
@@ -22,6 +22,13 @@
 }
 
 flag {
+    name: "enable_audio_input_device_routing"
+    namespace: "media_audio"
+    description: "Allow audio input devices routing control."
+    bug: "364923030"
+}
+
+flag {
     name: "fdtostring_timeout_fix"
     namespace: "media_audio"
     description: "Improve fdtostring implementation to properly handle timing out."
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 9eaddce..cdcce08 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -76,6 +76,8 @@
 using media::audio::common::AudioOffloadInfo;
 using media::audio::common::AudioOutputFlags;
 using media::audio::common::AudioPlaybackRate;
+using media::audio::common::AudioPolicyForcedConfig;
+using media::audio::common::AudioPolicyForceUse;
 using media::audio::common::AudioPort;
 using media::audio::common::AudioPortConfig;
 using media::audio::common::AudioPortDeviceExt;
@@ -739,6 +741,8 @@
             {// Note: not in the IANA registry.
              AUDIO_FORMAT_APTX_HD, make_AudioFormatDescription("audio/vnd.qcom.aptx.hd")},
             {AUDIO_FORMAT_AC4, make_AudioFormatDescription(::android::MEDIA_MIMETYPE_AUDIO_AC4)},
+            {AUDIO_FORMAT_AC4_L4, make_AudioFormatDescription(
+                    std::string(::android::MEDIA_MIMETYPE_AUDIO_AC4) + ";version=02.01.04")},
             {// Note: not in the IANA registry.
              AUDIO_FORMAT_LDAC, make_AudioFormatDescription("audio/vnd.sony.ldac")},
             {AUDIO_FORMAT_MAT,
@@ -1053,6 +1057,14 @@
     return OK;
 }
 
+namespace {
+    // Use '01' for LSB bits 0 and 1 as Bluetooth MAC addresses are never multicast
+    // and universaly administered
+    constexpr std::array<uint8_t, 4> BTANON_PREFIX {0xFD, 0xFF, 0xFF, 0xFF};
+    // Keep sync with ServiceUtilities.cpp mustAnonymizeBluetoothAddress
+    constexpr const char * BTANON_PREFIX_STR = "XX:XX:XX:XX:";
+}
+
 ::android::status_t aidl2legacy_AudioDevice_audio_device(
         const AudioDevice& aidl,
         audio_devices_t* legacyType, std::string* legacyAddress) {
@@ -1067,8 +1079,16 @@
         case Tag::mac: {
             const std::vector<uint8_t>& mac = aidl.address.get<AudioDeviceAddress::mac>();
             if (mac.size() != 6) return BAD_VALUE;
-            snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
-                    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+            if (std::equal(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin())) {
+                // special case for anonymized mac address:
+                // change anonymized bytes back from FD:FF:FF:FF: to XX:XX:XX:XX:
+                snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN,
+                        "%s%02X:%02X", BTANON_PREFIX_STR, mac[4], mac[5]);
+            } else {
+                snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN,
+                        "%02X:%02X:%02X:%02X:%02X:%02X",
+                        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+            }
         } break;
         case Tag::ipv4: {
             const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>();
@@ -1130,8 +1150,20 @@
         switch (suggestDeviceAddressTag(aidl.type)) {
             case Tag::mac: {
                 std::vector<uint8_t> mac(6);
-                int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
-                        &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+                int status;
+                // special case for anonymized mac address:
+                // change anonymized bytes so that they can be scanned as HEX bytes
+                if (legacyAddress.starts_with(BTANON_PREFIX_STR)) {
+                    std::copy(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin());
+                    LOG_ALWAYS_FATAL_IF(legacyAddress.length() <= strlen(BTANON_PREFIX_STR));
+                    status = sscanf(legacyAddress.c_str() + strlen(BTANON_PREFIX_STR),
+                                        "%hhX:%hhX",
+                                        &mac[4], &mac[5]);
+                    status += 4;
+                } else {
+                    status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
+                            &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+                }
                 if (status != mac.size()) {
                     ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str());
                     return unexpected(BAD_VALUE);
@@ -3301,6 +3333,138 @@
     return OK;
 }
 
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(AudioPolicyForceUse aidl) {
+    switch (aidl) {
+        case AudioPolicyForceUse::COMMUNICATION:
+            return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
+        case AudioPolicyForceUse::MEDIA:
+            return AUDIO_POLICY_FORCE_FOR_MEDIA;
+        case AudioPolicyForceUse::RECORD:
+            return AUDIO_POLICY_FORCE_FOR_RECORD;
+        case AudioPolicyForceUse::DOCK:
+            return AUDIO_POLICY_FORCE_FOR_DOCK;
+        case AudioPolicyForceUse::SYSTEM:
+            return AUDIO_POLICY_FORCE_FOR_SYSTEM;
+        case AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
+            return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
+        case AudioPolicyForceUse::ENCODED_SURROUND:
+            return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
+        case AudioPolicyForceUse::VIBRATE_RINGING:
+            return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
+    switch (legacy) {
+        case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
+            return AudioPolicyForceUse::COMMUNICATION;
+        case AUDIO_POLICY_FORCE_FOR_MEDIA:
+            return AudioPolicyForceUse::MEDIA;
+        case AUDIO_POLICY_FORCE_FOR_RECORD:
+            return AudioPolicyForceUse::RECORD;
+        case AUDIO_POLICY_FORCE_FOR_DOCK:
+            return AudioPolicyForceUse::DOCK;
+        case AUDIO_POLICY_FORCE_FOR_SYSTEM:
+            return AudioPolicyForceUse::SYSTEM;
+        case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
+            return AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
+        case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
+            return AudioPolicyForceUse::ENCODED_SURROUND;
+        case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
+            return AudioPolicyForceUse::VIBRATE_RINGING;
+        case AUDIO_POLICY_FORCE_USE_CNT:
+            break;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(AudioPolicyForcedConfig aidl) {
+    switch (aidl) {
+        case AudioPolicyForcedConfig::NONE:
+            return AUDIO_POLICY_FORCE_NONE;
+        case AudioPolicyForcedConfig::SPEAKER:
+            return AUDIO_POLICY_FORCE_SPEAKER;
+        case AudioPolicyForcedConfig::HEADPHONES:
+            return AUDIO_POLICY_FORCE_HEADPHONES;
+        case AudioPolicyForcedConfig::BT_SCO:
+            return AUDIO_POLICY_FORCE_BT_SCO;
+        case AudioPolicyForcedConfig::BT_A2DP:
+            return AUDIO_POLICY_FORCE_BT_A2DP;
+        case AudioPolicyForcedConfig::WIRED_ACCESSORY:
+            return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+        case AudioPolicyForcedConfig::BT_CAR_DOCK:
+            return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
+        case AudioPolicyForcedConfig::BT_DESK_DOCK:
+            return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
+        case AudioPolicyForcedConfig::ANALOG_DOCK:
+            return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+        case AudioPolicyForcedConfig::DIGITAL_DOCK:
+            return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+        case AudioPolicyForcedConfig::NO_BT_A2DP:
+            return AUDIO_POLICY_FORCE_NO_BT_A2DP;
+        case AudioPolicyForcedConfig::SYSTEM_ENFORCED:
+            return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
+        case AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
+            return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
+        case AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
+        case AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
+        case AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
+        case AudioPolicyForcedConfig::BT_BLE:
+            return AUDIO_POLICY_FORCE_BT_BLE;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
+    switch (legacy) {
+        case AUDIO_POLICY_FORCE_NONE:
+            return AudioPolicyForcedConfig::NONE;
+        case AUDIO_POLICY_FORCE_SPEAKER:
+            return AudioPolicyForcedConfig::SPEAKER;
+        case AUDIO_POLICY_FORCE_HEADPHONES:
+            return AudioPolicyForcedConfig::HEADPHONES;
+        case AUDIO_POLICY_FORCE_BT_SCO:
+            return AudioPolicyForcedConfig::BT_SCO;
+        case AUDIO_POLICY_FORCE_BT_A2DP:
+            return AudioPolicyForcedConfig::BT_A2DP;
+        case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
+            return AudioPolicyForcedConfig::WIRED_ACCESSORY;
+        case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
+            return AudioPolicyForcedConfig::BT_CAR_DOCK;
+        case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
+            return AudioPolicyForcedConfig::BT_DESK_DOCK;
+        case AUDIO_POLICY_FORCE_ANALOG_DOCK:
+            return AudioPolicyForcedConfig::ANALOG_DOCK;
+        case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
+            return AudioPolicyForcedConfig::DIGITAL_DOCK;
+        case AUDIO_POLICY_FORCE_NO_BT_A2DP:
+            return AudioPolicyForcedConfig::NO_BT_A2DP;
+        case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
+            return AudioPolicyForcedConfig::SYSTEM_ENFORCED;
+        case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
+            return AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
+        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
+            return AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
+        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
+            return AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
+        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
+            return AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
+        case AUDIO_POLICY_FORCE_BT_BLE:
+            return AudioPolicyForcedConfig::BT_BLE;
+        case AUDIO_POLICY_FORCE_CFG_CNT:
+            break;
+    }
+    return unexpected(BAD_VALUE);
+}
+
 }  // namespace android
 
 #undef GET_DEVICE_DESC_CONNECTION
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
index 7268464..9dfb7e7 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
@@ -58,6 +58,8 @@
 #include PREFIX(android/media/audio/common/AudioMode.h)
 #include PREFIX(android/media/audio/common/AudioOffloadInfo.h)
 #include PREFIX(android/media/audio/common/AudioOutputFlags.h)
+#include PREFIX(android/media/audio/common/AudioPolicyForceUse.h)
+#include PREFIX(android/media/audio/common/AudioPolicyForcedConfig.h)
 #include PREFIX(android/media/audio/common/AudioPort.h)
 #include PREFIX(android/media/audio/common/AudioPortConfig.h)
 #include PREFIX(android/media/audio/common/AudioPortExt.h)
@@ -76,6 +78,7 @@
 
 #include <system/audio.h>
 #include <system/audio_effect.h>
+#include <system/audio_policy.h>
 
 #if defined(BACKEND_NDK_IMPL)
 namespace aidl {
@@ -454,6 +457,18 @@
         media::audio::common::MicrophoneInfo* aidlInfo,
         media::audio::common::MicrophoneDynamicInfo* aidlDynamic);
 
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(
+        media::audio::common::AudioPolicyForcedConfig aidl);
+ConversionResult<media::audio::common::AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
+
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
+        media::audio::common::AudioPolicyForceUse aidl);
+ConversionResult<media::audio::common::AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
+
 }  // namespace android
 
 #if defined(BACKEND_NDK_IMPL)
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index 5d7daa4..d55932d 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -205,6 +205,7 @@
                   __func__, status, policyInfos.size());
         }
         const auto endTime = std::chrono::steady_clock::now();
+        af->startupFinished();
         using FloatMillis = std::chrono::duration<float, std::milli>;
         const float timeTaken = std::chrono::duration_cast<FloatMillis>(
                 endTime - startTime).count();
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
index 149c6ee..aed5e68 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
@@ -114,7 +114,9 @@
 c2_status_t C2SoftMP3::onStop() {
     // Make sure that the next buffer output does not still
     // depend on fragments from the last one decoded.
-    pvmp3_InitDecoder(mConfig, mDecoderBuf);
+    if (mDecoderBuf) {
+        pvmp3_InitDecoder(mConfig, mDecoderBuf);
+    }
     mSignalledError = false;
     mIsFirst = true;
     mSignalledOutputEos = false;
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index ea4d045..de9332b 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -153,6 +153,13 @@
         mParamReflectors.push_back(paramReflector);
     }
 #endif
+    // MultiAccessUnit reflector helper is allocated once per store.
+    // All components in this store can reuse this reflector helper.
+    if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+        std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+        mParamReflectors.push_back(helper);
+        mMultiAccessUnitReflector = helper;
+    }
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -212,12 +219,20 @@
     if (c2interface == nullptr) {
         return nullptr;
     }
+    // Framework support for Large audio frame feature depends on:
+    // 1. All feature flags enabled on platform
+    // 2. The capability of the implementation to use the same input buffer
+    //    for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+    // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
     if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
         c2_status_t err = C2_OK;
         C2ComponentDomainSetting domain;
         std::vector<std::unique_ptr<C2Param>> heapParams;
-        err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
-        if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+        C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+        err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+        if (err == C2_OK
+                && (domain.value == C2Component::DOMAIN_AUDIO)
+                && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
             std::vector<std::shared_ptr<C2ParamDescriptor>> params;
             bool isComponentSupportsLargeAudioFrame = false;
             c2interface->querySupportedParams_nb(&params);
@@ -234,7 +249,7 @@
                 // thus we pass the component's param reflector, which is mParamReflectors[0].
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
                         c2interface,
-                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+                        mMultiAccessUnitReflector);
             }
         }
     }
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index b2158a6..bb4c596 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -52,6 +52,13 @@
 using ::aidl::android::hardware::media::bufferpool2::IClientManager;
 
 struct ComponentStore : public BnComponentStore {
+    /**
+     * Constructor for ComponentStore.
+     *
+     * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+     * Be careful about the order of SetPreferredCodec2ComponentStore() and
+     * ComponentStore() in the code.
+     */
     ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
     virtual ~ComponentStore();
 
@@ -120,6 +127,9 @@
     std::shared_ptr<C2ComponentStore> mStore;
     std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
+    // Reflector helper for MultiAccessUnitHelper
+    std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
     std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index 1ba1889..108ba06 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
     }
 #endif
 
+    // MultiAccessUnit reflector helper is allocated once per store.
+    // All components in this store can reuse this reflector helper.
+    if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+        std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+        mParamReflectors.push_back(helper);
+        mMultiAccessUnitReflector = helper;
+    }
+
     // Retrieve supported parameters from store
     using namespace std::placeholders;
     mInit = mConfigurable->init(mParameterCache);
@@ -207,12 +215,20 @@
     if (c2interface == nullptr) {
         return nullptr;
     }
+    // Framework support for Large audio frame feature depends on:
+    // 1. All feature flags enabled on platform
+    // 2. The capability of the implementation to use the same input buffer
+    //    for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+    // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
     if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
         c2_status_t err = C2_OK;
         C2ComponentDomainSetting domain;
         std::vector<std::unique_ptr<C2Param>> heapParams;
-        err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
-        if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+        C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+        err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+        if (err == C2_OK
+                && (domain.value == C2Component::DOMAIN_AUDIO)
+                && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
             std::vector<std::shared_ptr<C2ParamDescriptor>> params;
             bool isComponentSupportsLargeAudioFrame = false;
             c2interface->querySupportedParams_nb(&params);
@@ -225,7 +241,7 @@
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
                         c2interface,
-                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+                        mMultiAccessUnitReflector);
             }
         }
     }
diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index 44b8ec1..028238b 100644
--- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -55,6 +55,13 @@
 using ::android::sp;
 
 struct ComponentStore : public IComponentStore {
+    /**
+     * Constructor for ComponentStore.
+     *
+     * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+     * Be careful about the order of SetPreferredCodec2ComponentStore() and
+     * ComponentStore() in the code.
+     */
     ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
     virtual ~ComponentStore();
 
@@ -124,6 +131,9 @@
     std::shared_ptr<C2ComponentStore> mStore;
     std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
+    // Reflector helper for MultiAccessUnitHelper
+    std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
     std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index 1b86958..84f5d26 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
     }
 #endif
 
+    // MultiAccessUnit reflector helper is allocated once per store.
+    // All components in this store can reuse this reflector helper.
+    if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+        std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+        mParamReflectors.push_back(helper);
+        mMultiAccessUnitReflector = helper;
+    }
+
     // Retrieve supported parameters from store
     using namespace std::placeholders;
     mInit = mConfigurable->init(mParameterCache);
@@ -207,12 +215,20 @@
     if (c2interface == nullptr) {
         return nullptr;
     }
+    // Framework support for Large audio frame feature depends on:
+    // 1. All feature flags enabled on platform
+    // 2. The capability of the implementation to use the same input buffer
+    //    for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+    // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
     if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
         c2_status_t err = C2_OK;
         C2ComponentDomainSetting domain;
         std::vector<std::unique_ptr<C2Param>> heapParams;
-        err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
-        if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+        C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+        err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+        if (err == C2_OK
+                && (domain.value == C2Component::DOMAIN_AUDIO)
+                && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
             std::vector<std::shared_ptr<C2ParamDescriptor>> params;
             bool isComponentSupportsLargeAudioFrame = false;
             c2interface->querySupportedParams_nb(&params);
@@ -222,11 +238,10 @@
                     break;
                 }
             }
-
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
                         c2interface,
-                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+                        mMultiAccessUnitReflector);
             }
         }
     }
diff --git a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
index 52d2945..b023115 100644
--- a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
@@ -56,6 +56,13 @@
 using ::android::sp;
 
 struct ComponentStore : public IComponentStore {
+    /**
+     * Constructor for ComponentStore.
+     *
+     * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+     * Be careful about the order of SetPreferredCodec2ComponentStore() and
+     * ComponentStore() in the code.
+     */
     ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
     virtual ~ComponentStore();
 
@@ -132,6 +139,9 @@
     std::shared_ptr<C2ComponentStore> mStore;
     std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
+    // Reflector helper for MultiAccessUnitHelper
+    std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
     std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index 2e0386f..5585be8 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
     }
 #endif
 
+    // MultiAccessUnit reflector helper is allocated once per store.
+    // All components in this store can reuse this reflector helper.
+    if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+        std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+        mParamReflectors.push_back(helper);
+        mMultiAccessUnitReflector = helper;
+    }
+
     // Retrieve supported parameters from store
     using namespace std::placeholders;
     mInit = mConfigurable->init(mParameterCache);
@@ -207,12 +215,20 @@
     if (c2interface == nullptr) {
         return nullptr;
     }
+    // Framework support for Large audio frame feature depends on:
+    // 1. All feature flags enabled on platform
+    // 2. The capability of the implementation to use the same input buffer
+    //    for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+    // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
     if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
         c2_status_t err = C2_OK;
         C2ComponentDomainSetting domain;
         std::vector<std::unique_ptr<C2Param>> heapParams;
-        err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
-        if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+        C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+        err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+        if (err == C2_OK
+                && (domain.value == C2Component::DOMAIN_AUDIO)
+                && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
             std::vector<std::shared_ptr<C2ParamDescriptor>> params;
             bool isComponentSupportsLargeAudioFrame = false;
             c2interface->querySupportedParams_nb(&params);
@@ -225,7 +241,7 @@
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
                         c2interface,
-                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+                        mMultiAccessUnitReflector);
             }
         }
     }
diff --git a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
index 1b209e2..a7e043b 100644
--- a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
@@ -56,6 +56,13 @@
 using ::android::sp;
 
 struct ComponentStore : public IComponentStore {
+    /**
+     * Constructor for ComponentStore.
+     *
+     * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+     * Be careful about the order of SetPreferredCodec2ComponentStore() and
+     * ComponentStore() in the code.
+     */
     ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
     virtual ~ComponentStore();
 
@@ -139,6 +146,9 @@
     std::shared_ptr<C2ComponentStore> mStore;
     std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
+    // Reflector helper for MultiAccessUnitHelper
+    std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
     std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
index 47412b7..34872f0 100644
--- a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
@@ -856,21 +856,31 @@
     C2String getName() const override { return "android.sample.filter-plugin-store"; }
     c2_status_t createComponent(
             C2String name, std::shared_ptr<C2Component>* const component) override {
-        if (mFactories.count(name) == 0) {
+        auto it = std::find_if(
+                mFactories.begin(), mFactories.end(),
+                [&name](const std::unique_ptr<ComponentFactory> &factory) {
+                    return name == factory->getTraits()->name;
+                });
+        if (it == mFactories.end()) {
             return C2_BAD_VALUE;
         }
-        return mFactories.at(name)->createComponent(++mNodeId, component);
+        return (*it)->createComponent(++mNodeId, component);
     }
     c2_status_t createInterface(
             C2String name, std::shared_ptr<C2ComponentInterface>* const interface) override {
-        if (mFactories.count(name) == 0) {
+        auto it = std::find_if(
+                mFactories.begin(), mFactories.end(),
+                [&name](const std::unique_ptr<ComponentFactory> &factory) {
+                    return name == factory->getTraits()->name;
+                });
+        if (it == mFactories.end()) {
             return C2_BAD_VALUE;
         }
-        return mFactories.at(name)->createInterface(++mNodeId, interface);
+        return (*it)->createInterface(++mNodeId, interface);
     }
     std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override {
         std::vector<std::shared_ptr<const C2Component::Traits>> ret;
-        for (const auto &[name, factory] : mFactories) {
+        for (const auto &factory : mFactories) {
             ret.push_back(factory->getTraits());
         }
         return ret;
@@ -951,20 +961,18 @@
 
     template <class T>
     static void AddFactory(
-            std::map<C2String, std::unique_ptr<ComponentFactory>> *factories,
+            std::vector<std::unique_ptr<ComponentFactory>> *factories,
             const std::shared_ptr<C2ReflectorHelper> &reflector) {
         std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0, reflector)};
         std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
         CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
                 << "Failed to fill traits from interface";
-        factories->emplace(
-                traits->name,
-                new ComponentFactoryImpl<T>(traits, reflector));
+        factories->emplace_back(new ComponentFactoryImpl<T>(traits, reflector));
     }
 
-    static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories(
+    static std::vector<std::unique_ptr<ComponentFactory>> CreateFactories(
             const std::shared_ptr<C2ReflectorHelper> &reflector) {
-        std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
+        std::vector<std::unique_ptr<ComponentFactory>> factories;
         AddFactory<SampleToneMappingFilter>(&factories, reflector);
         return factories;
     }
@@ -977,7 +985,7 @@
         }
     } mIntf;
 
-    const std::map<C2String, std::unique_ptr<ComponentFactory>> mFactories;
+    const std::vector<std::unique_ptr<ComponentFactory>> mFactories;
 
     std::atomic_int32_t mNodeId{0};
 };
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 68f1dda..632eaed 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -512,9 +512,14 @@
         uint64_t usage = mConfig.mUsage;
         (void)(*node)->setConsumerUsage((int64_t)usage);
 
+        // AIDL does not define legacy dataspace.
+        android_dataspace_t dataspace = mDataSpace;
+        if (android::media::codec::provider_->dataspace_v0_partial()) {
+            ColorUtils::convertDataSpaceToV0(dataspace);
+        }
         return fromAidlStatus(mSource->configure(
                 (*node), static_cast<::aidl::android::hardware::graphics::common::Dataspace>(
-                        mDataSpace)));
+                        dataspace)));
     }
 
     void disconnect() override {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index d829523..3ef2f84 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -228,17 +228,23 @@
 status_t CCodecBufferChannel::setInputSurface(
         const std::shared_ptr<InputSurfaceWrapper> &surface) {
     ALOGV("[%s] setInputSurface", mName);
-    Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
-    *inputSurface = surface;
-    return (*inputSurface)->connect(mComponent);
+    if (!surface) {
+        ALOGE("[%s] setInputSurface: surface must not be null", mName);
+        return BAD_VALUE;
+    }
+    Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+    inputSurface->numProcessingBuffersBalance = 0;
+    inputSurface->surface = surface;
+    mHasInputSurface = true;
+    return inputSurface->surface->connect(mComponent);
 }
 
 status_t CCodecBufferChannel::signalEndOfInputStream() {
-    Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
-    if ((*inputSurface) == nullptr) {
+    Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+    if (inputSurface->surface == nullptr) {
         return INVALID_OPERATION;
     }
-    return (*inputSurface)->signalEndOfInputStream();
+    return inputSurface->surface->signalEndOfInputStream();
 }
 
 status_t CCodecBufferChannel::queueInputBufferInternal(
@@ -1063,19 +1069,36 @@
     if (mInputMetEos) {
         return;
     }
-    {
+    int64_t numOutputSlots = 0;
+    bool outputFull = [this, &numOutputSlots]() {
         Mutexed<Output>::Locked output(mOutput);
-        if (!output->buffers ||
-                output->buffers->hasPending() ||
+        if (!output->buffers) {
+            ALOGV("[%s] feedInputBufferIfAvailableInternal: "
+                  "return because output buffers are null", mName);
+            return true;
+        }
+        numOutputSlots = int64_t(output->numSlots);
+        if (output->buffers->hasPending() ||
                 (!output->bounded && output->buffers->numActiveSlots() >= output->numSlots)) {
-            return;
+            ALOGV("[%s] feedInputBufferIfAvailableInternal: "
+                  "return because there are no room for more output buffers", mName);
+            return true;
+        }
+        return false;
+    }();
+    if (android::media::codec::provider_->input_surface_throttle()) {
+        Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+        if (inputSurface->surface) {
+            if (inputSurface->numProcessingBuffersBalance <= numOutputSlots) {
+                ++inputSurface->numProcessingBuffersBalance;
+                ALOGV("[%s] feedInputBufferIfAvailableInternal: numProcessingBuffersBalance = %lld",
+                      mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
+                inputSurface->surface->onInputBufferEmptied();
+            }
         }
     }
-    if (android::media::codec::provider_->input_surface_throttle()) {
-        Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
-        if ((*inputSurface) != nullptr) {
-            (*inputSurface)->onInputBufferEmptied();
-        }
+    if (outputFull) {
+        return;
     }
     size_t numActiveSlots = 0;
     while (!mPipelineWatcher.lock()->pipelineFull()) {
@@ -1704,7 +1727,7 @@
                 && (hasCryptoOrDescrambler() || conforming)) {
             input->buffers.reset(new SlotInputBuffers(mName));
         } else if (graphic) {
-            if (mInputSurface.lock()->get()) {
+            if (mHasInputSurface) {
                 input->buffers.reset(new DummyInputBuffers(mName));
             } else if (mMetaMode == MODE_ANW) {
                 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
@@ -1987,7 +2010,7 @@
 
 status_t CCodecBufferChannel::prepareInitialInputBuffers(
         std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
-    if (mInputSurface.lock()->get()) {
+    if (mHasInputSurface) {
         return OK;
     }
 
@@ -2113,9 +2136,13 @@
 
 void CCodecBufferChannel::reset() {
     stop();
-    mInputSurface.lock()->reset();
     mPipelineWatcher.lock()->flush();
     {
+        mHasInputSurface = false;
+        Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+        inputSurface->surface.reset();
+    }
+    {
         Mutexed<Input>::Locked input(mInput);
         input->buffers.reset(new DummyInputBuffers(""));
         input->extraBuffers.flush();
@@ -2208,9 +2235,6 @@
 
 void CCodecBufferChannel::onInputBufferDone(
         uint64_t frameIndex, size_t arrayIndex) {
-    if (mInputSurface.lock()->get()) {
-        return;
-    }
     std::shared_ptr<C2Buffer> buffer =
             mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
     bool newInputSlotAvailable = false;
@@ -2265,8 +2289,7 @@
         notifyClient = false;
     }
 
-    bool hasInputSurface = (mInputSurface.lock()->get() != nullptr);
-    if (!hasInputSurface && (work->worklets.size() != 1u
+    if (!mHasInputSurface && (work->worklets.size() != 1u
             || !work->worklets.front()
             || !(work->worklets.front()->output.flags &
                  C2FrameData::FLAG_INCOMPLETE))) {
@@ -2475,7 +2498,7 @@
     c2_cntr64_t timestamp =
         worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
                 - work->input.ordinal.timestamp;
-    if (hasInputSurface) {
+    if (mHasInputSurface) {
         // When using input surface we need to restore the original input timestamp.
         timestamp = work->input.ordinal.customOrdinal;
     }
@@ -2605,8 +2628,6 @@
         switch (action) {
         case OutputBuffers::SKIP:
             return;
-        case OutputBuffers::DISCARD:
-            break;
         case OutputBuffers::NOTIFY_CLIENT:
         {
             // TRICKY: we want popped buffers reported in order, so sending
@@ -2625,8 +2646,8 @@
                                 bufferMetadata->m.values[nMeta];
                         flag = convertFlags(bufferMetadataStruct.flags, false);
                         accessUnitInfos.emplace_back(flag,
-                                static_cast<size_t>(bufferMetadataStruct.size),
-                                static_cast<size_t>(bufferMetadataStruct.timestamp));
+                                bufferMetadataStruct.size,
+                                bufferMetadataStruct.timestamp);
                     }
                     sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
                         new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
@@ -2634,6 +2655,15 @@
                 }
             }
             mCallback->onOutputBufferAvailable(index, outBuffer);
+            [[fallthrough]];
+        }
+        case OutputBuffers::DISCARD: {
+            if (mHasInputSurface && android::media::codec::provider_->input_surface_throttle()) {
+                Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+                --inputSurface->numProcessingBuffersBalance;
+                ALOGV("[%s] onWorkDone: numProcessingBuffersBalance = %lld",
+                        mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
+            }
             break;
         }
         case OutputBuffers::REALLOCATE:
@@ -2802,7 +2832,7 @@
 }
 
 void CCodecBufferChannel::setInfoBuffer(const std::shared_ptr<C2InfoBuffer> &buffer) {
-    if (mInputSurface.lock()->get() == nullptr) {
+    if (!mHasInputSurface) {
         mInfoBuffers.push_back(buffer);
     } else {
         std::list<std::unique_ptr<C2Work>> items;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index f5e268a..4d296fd 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -391,7 +391,21 @@
     };
     Mutexed<BlockPools> mBlockPools;
 
-    Mutexed<std::shared_ptr<InputSurfaceWrapper>> mInputSurface;
+    std::atomic_bool mHasInputSurface;
+    struct InputSurface {
+        std::shared_ptr<InputSurfaceWrapper> surface;
+        // This variable tracks the number of buffers processing
+        // in the input surface and codec by counting the # of buffers to
+        // be filled in and queued from the input surface and the # of
+        // buffers generated from the codec.
+        //
+        // Note that this variable can go below 0, because it does not take
+        // account the number of buffers initially in the buffer queue at
+        // start. This is okay, as we only track how many more we allow
+        // from the initial state.
+        int64_t numProcessingBuffersBalance;
+    };
+    Mutexed<InputSurface> mInputSurface;
 
     MetaMode mMetaMode;
 
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 164a1e0..7d4e8ab 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -20,6 +20,8 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
+#include <android_media_codec.h>
+
 #include <aidl/android/hardware/graphics/common/Cta861_3.h>
 #include <aidl/android/hardware/graphics/common/Smpte2086.h>
 #include <android-base/no_destructor.h>
@@ -33,6 +35,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ColorUtils.h>
 #include <mediadrm/ICrypto.h>
 #include <nativebase/nativebase.h>
 #include <ui/GraphicBufferMapper.h>
@@ -735,6 +738,10 @@
         // Gralloc4 not supported; nothing to do
         return err;
     }
+    // Use V0 dataspaces for Gralloc4+
+    if (android::media::codec::provider_->dataspace_v0_partial()) {
+        ColorUtils::convertDataSpaceToV0(dataSpace);
+    }
     status_t status = mapper.setDataspace(buffer.get(), static_cast<ui::Dataspace>(dataSpace));
     if (status != OK) {
        err = C2_CORRUPTED;
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 4b417a7..add28e0 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -36,9 +36,6 @@
     symbol_file: "src/libaaudio.map.txt",
     first_version: "26",
     unversioned_until: "current",
-    export_header_libs: [
-        "libAAudio_headers",
-    ],
 }
 
 cc_library_headers {
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 1e27a81..1e8ac8d 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -602,6 +602,7 @@
 }
 
 AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy) {
+    ALOGD("%s(%d)", __func__, policy);
     return AudioGlobal_setMMapPolicy(policy);
 }
 
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index c9d8b35..01f0038 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -109,10 +109,12 @@
 
     std::vector<AudioMMapPolicyInfo> policyInfos;
     aaudio_policy_t mmapPolicy = AudioGlobal_getMMapPolicy();
-    if (android::AudioSystem::getMmapPolicyInfo(
-            AudioMMapPolicyType::DEFAULT, &policyInfos) == NO_ERROR) {
+    ALOGD("%s, global mmap policy is %d", __func__, mmapPolicy);
+    if (status_t status = android::AudioSystem::getMmapPolicyInfo(
+            AudioMMapPolicyType::DEFAULT, &policyInfos); status == NO_ERROR) {
         aaudio_policy_t systemMmapPolicy = AAudio_getAAudioPolicy(
                 policyInfos, AAUDIO_MMAP_POLICY_DEFAULT_AIDL);
+        ALOGD("%s, system mmap policy is %d", __func__, systemMmapPolicy);
         if (mmapPolicy == AAUDIO_POLICY_ALWAYS && systemMmapPolicy == AAUDIO_POLICY_NEVER) {
             // No need to try as AAudioService is not created and the client only wants MMAP path.
             return AAUDIO_ERROR_NO_SERVICE;
@@ -125,6 +127,7 @@
             mmapPolicy = systemMmapPolicy;
         }
     } else {
+        ALOGD("%s, failed to query system mmap policy, error=%d", __func__, status);
         // If it fails querying mmap policy info, it is highly possible that the AAudioService is
         // not created. In this case, we don't try mmap path.
         if (mmapPolicy == AAUDIO_POLICY_ALWAYS) {
@@ -136,17 +139,22 @@
     if (mmapPolicy == AAUDIO_UNSPECIFIED) {
         mmapPolicy = AAUDIO_MMAP_POLICY_DEFAULT;
     }
+    ALOGD("%s, final mmap policy is %d", __func__, mmapPolicy);
 
     policyInfos.clear();
     aaudio_policy_t mmapExclusivePolicy = AAUDIO_UNSPECIFIED;
-    if (android::AudioSystem::getMmapPolicyInfo(
-            AudioMMapPolicyType::EXCLUSIVE, &policyInfos) == NO_ERROR) {
+    if (status_t status = android::AudioSystem::getMmapPolicyInfo(
+            AudioMMapPolicyType::EXCLUSIVE, &policyInfos); status == NO_ERROR) {
         mmapExclusivePolicy = AAudio_getAAudioPolicy(
                 policyInfos, AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT_AIDL);
+        ALOGD("%s, system mmap exclusive policy is %d", __func__, mmapExclusivePolicy);
+    } else {
+        ALOGD("%s, failed to query mmap exclusive policy, error=%d", __func__, status);
     }
     if (mmapExclusivePolicy == AAUDIO_UNSPECIFIED) {
         mmapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
     }
+    ALOGD("%s, final mmap exclusive policy is %d", __func__, mmapExclusivePolicy);
 
     aaudio_sharing_mode_t sharingMode = getSharingMode();
     if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 5785537..61204ae 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -158,6 +158,7 @@
         "framework-permission-aidl-cpp",
         "libbinder",
         "libmediametrics",
+        "libmediautils",
         "spatializer-aidl-cpp",
     ],
 
@@ -358,8 +359,6 @@
         "aidl/android/media/AudioMixerBehavior.aidl",
         "aidl/android/media/AudioOffloadMode.aidl",
         "aidl/android/media/AudioPolicyDeviceState.aidl",
-        "aidl/android/media/AudioPolicyForceUse.aidl",
-        "aidl/android/media/AudioPolicyForcedConfig.aidl",
         "aidl/android/media/AudioProductStrategy.aidl",
         "aidl/android/media/AudioVolumeGroup.aidl",
         "aidl/android/media/DeviceRole.aidl",
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 7f5a165..5b954f7 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -79,6 +79,17 @@
     return NO_ERROR;
 }
 
+status_t AudioRecord::logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage,
+                                                const std::string& func) {
+    if (status != NO_ERROR) {
+        if (!func.empty()) mMediaMetrics.markError(status, func.c_str());
+        ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
+        reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
+    }
+    mStatus = status;
+    return mStatus;
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
@@ -246,13 +257,28 @@
     if (pid == -1 || (callingPid != myPid)) {
         adjPid = callingPid;
     }
-    mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(adjPid));
-
+    auto clientAttributionSourcePid = legacy2aidl_pid_t_int32_t(adjPid);
+    if (!clientAttributionSourcePid.ok()) {
+        return logIfErrorAndReturnStatus(BAD_VALUE,
+                                         StringPrintf("%s: received invalid client attribution "
+                                                      "source pid, pid: %d, sessionId: %d",
+                                                      __func__, pid, sessionId),
+                                         __func__);
+    }
+    mClientAttributionSource.pid = clientAttributionSourcePid.value();
     uid_t adjUid = uid;
     if (uid == -1 || (callingPid != myPid)) {
         adjUid = IPCThreadState::self()->getCallingUid();
     }
-    mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(adjUid));
+    auto clientAttributionSourceUid = legacy2aidl_uid_t_int32_t(adjUid);
+    if (!clientAttributionSourceUid.ok()) {
+        return logIfErrorAndReturnStatus(BAD_VALUE,
+                                         StringPrintf("%s: received invalid client attribution "
+                                                      "source uid, pid: %d, session id: %d",
+                                                      __func__, pid, sessionId),
+                                         __func__);
+    }
+    mClientAttributionSource.uid = clientAttributionSourceUid.value();
 
     mTracker.reset(new RecordingActivityTracker());
 
@@ -268,7 +294,6 @@
     mSelectedMicFieldDimension = microphoneFieldDimension;
     mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs;
 
-    std::string errorMessage;
     // Copy the state variables early so they are available for error reporting.
     if (pAttributes == nullptr) {
         mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -311,38 +336,48 @@
         break;
     case TRANSFER_CALLBACK:
         if (callback == nullptr) {
-            errorMessage = StringPrintf(
-                    "%s: Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__);
-            status = BAD_VALUE;
-            goto error;
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s: Transfer type TRANSFER_CALLBACK but callback == nullptr, "
+                                 "pid: %d, session id: %d",
+                                 __func__, pid, sessionId),
+                    __func__);
         }
         break;
     case TRANSFER_OBTAIN:
     case TRANSFER_SYNC:
         break;
     default:
-        errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, mTransfer);
-        status = BAD_VALUE;
-        goto error;
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE,
+                StringPrintf("%s: Invalid transfer type %d, pid: %d, session id: %d", __func__,
+                             mTransfer, pid, sessionId),
+                __func__);
     }
 
     // invariant that mAudioRecord != 0 is true only after set() returns successfully
     if (mAudioRecord != 0) {
-        errorMessage = StringPrintf("%s: Track already in use", __func__);
-        status = INVALID_OPERATION;
-        goto error;
+        return logIfErrorAndReturnStatus(
+                INVALID_OPERATION,
+                StringPrintf("%s: Track already in use, pid: %d, session id: %d", __func__, pid,
+                             sessionId),
+                __func__);
     }
 
     if (!audio_is_valid_format(mFormat)) {
-        errorMessage = StringPrintf("%s: Format %#x is not valid", __func__, mFormat);
-        status = BAD_VALUE;
-        goto error;
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE,
+                StringPrintf("%s: Format %#x is not valid, pid: %d, session id: %d", __func__,
+                             mFormat, pid, sessionId),
+                __func__);
     }
 
     if (!audio_is_input_channel(mChannelMask)) {
-        errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, mChannelMask);
-        status = BAD_VALUE;
-        goto error;
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE,
+                StringPrintf("%s: Invalid channel mask %#x, pid: %d, session id: %d", __func__,
+                             mChannelMask, pid, sessionId),
+                __func__);
     }
 
     mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
@@ -376,7 +411,8 @@
             mAudioRecordThread.clear();
         }
         // bypass error message to avoid logging twice (createRecord_l logs the error).
-        goto exit;
+        mStatus = status;
+        return mStatus;
     }
 
     // TODO: add audio hardware input latency here
@@ -392,15 +428,7 @@
     mFramesRead = 0;
     mFramesReadServerOffset = 0;
 
-error:
-    if (status != NO_ERROR) {
-        mMediaMetrics.markError(status, __FUNCTION__);
-        ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
-        reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
-    }
-exit:
-    mStatus = status;
-    return status;
+    return logIfErrorAndReturnStatus(status, "", __func__);
 }
 
 // -------------------------------------------------------------------------
@@ -801,12 +829,10 @@
     status_t status;
     static const int32_t kMaxCreateAttempts = 3;
     int32_t remainingAttempts = kMaxCreateAttempts;
-    std::string errorMessage;
 
     if (audioFlinger == 0) {
-        errorMessage = StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId);
-        status = NO_INIT;
-        goto exit;
+        return logIfErrorAndReturnStatus(
+                NO_INIT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId), "");
     }
 
     // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@@ -864,16 +890,34 @@
 
     do {
         media::CreateRecordResponse response;
-        status = audioFlinger->createRecord(VALUE_OR_FATAL(input.toAidl()), response);
-        output = VALUE_OR_FATAL(IAudioFlinger::CreateRecordOutput::fromAidl(response));
+        auto aidlInput = input.toAidl();
+        if (!aidlInput.ok()) {
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s(%d): Could not create record due to invalid input", __func__,
+                                 mPortId),
+                    "");
+        }
+        status = audioFlinger->createRecord(aidlInput.value(), response);
+
+        auto recordOutput = IAudioFlinger::CreateRecordOutput::fromAidl(response);
+        if (!recordOutput.ok()) {
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s(%d): Could not create record output due to invalid response",
+                                 __func__, mPortId),
+                    "");
+        }
+        output = recordOutput.value();
         if (status == NO_ERROR) {
             break;
         }
         if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
-            errorMessage = StringPrintf(
-                    "%s(%d): AudioFlinger could not create record track, status: %d",
-                    __func__, mPortId, status);
-            goto exit;
+            return logIfErrorAndReturnStatus(
+                    status,
+                    StringPrintf("%s(%d): AudioFlinger could not create record track, status: %d",
+                                 __func__, mPortId, status),
+                    "");
         }
         // FAILED_TRANSACTION happens under very specific conditions causing a state mismatch
         // between audio policy manager and audio flinger during the input stream open sequence
@@ -908,9 +952,9 @@
     mHalFormat = output.halConfig.format;
 
     if (output.cblk == 0) {
-        errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId);
-        status = NO_INIT;
-        goto exit;
+        return logIfErrorAndReturnStatus(
+                NO_INIT, StringPrintf("%s(%d): Could not get control block", __func__, mPortId),
+                "");
     }
     // TODO: Using unsecurePointer() has some associated security pitfalls
     //       (see declaration for details).
@@ -918,10 +962,9 @@
     //       issue (e.g. by copying).
     iMemPointer = output.cblk ->unsecurePointer();
     if (iMemPointer == NULL) {
-        errorMessage = StringPrintf(
-                "%s(%d): Could not get control block pointer", __func__, mPortId);
-        status = NO_INIT;
-        goto exit;
+        return logIfErrorAndReturnStatus(
+                NO_INIT,
+                StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId), "");
     }
     cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
 
@@ -938,10 +981,9 @@
         //       issue (e.g. by copying).
         buffers = output.buffers->unsecurePointer();
         if (buffers == NULL) {
-            errorMessage = StringPrintf(
-                    "%s(%d): Could not get buffer pointer", __func__, mPortId);
-            status = NO_INIT;
-            goto exit;
+            return logIfErrorAndReturnStatus(
+                    NO_INIT,
+                    StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId), "");
         }
     }
 
@@ -1033,15 +1075,8 @@
         .set(AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION, (double)mSelectedMicFieldDimension)
         .record();
 
-exit:
-    if (status != NO_ERROR) {
-        ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
-        reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
-    }
-
-    mStatus = status;
     // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
-    return status;
+    return logIfErrorAndReturnStatus(status, "", "");
 }
 
 // Report error associated with the event and some configuration details.
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 55f74e1..769475c 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -60,6 +60,8 @@
 using media::audio::common::AudioMMapPolicyInfo;
 using media::audio::common::AudioMMapPolicyType;
 using media::audio::common::AudioOffloadInfo;
+using media::audio::common::AudioPolicyForceUse;
+using media::audio::common::AudioPolicyForcedConfig;
 using media::audio::common::AudioSource;
 using media::audio::common::AudioStreamType;
 using media::audio::common::AudioUsage;
@@ -306,11 +308,11 @@
 }
 
 status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
-                                      audio_io_handle_t output) {
+                                      bool muted, audio_io_handle_t output) {
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
     const sp<IAudioFlinger> af = get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-    af->setStreamVolume(stream, value, output);
+    af->setStreamVolume(stream, value, muted, output);
     return NO_ERROR;
 }
 
@@ -323,14 +325,15 @@
 }
 
 status_t AudioSystem::setPortsVolume(
-        const std::vector<audio_port_handle_t>& portIds, float volume, audio_io_handle_t output) {
+        const std::vector<audio_port_handle_t>& portIds, float volume, bool muted,
+        audio_io_handle_t output) {
     const sp<IAudioFlinger> af = get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     std::vector<int32_t> portIdsAidl = VALUE_OR_RETURN_STATUS(
             convertContainer<std::vector<int32_t>>(
                     portIds, legacy2aidl_audio_port_handle_t_int32_t));
     int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
-    af->setPortsVolume(portIdsAidl, volume, outputAidl);
+    af->setPortsVolume(portIdsAidl, volume, muted, outputAidl);
     return NO_ERROR;
 }
 
@@ -1054,9 +1057,9 @@
     if (aps == 0) return AUDIO_POLICY_FORCE_NONE;
 
     auto result = [&]() -> ConversionResult<audio_policy_forced_cfg_t> {
-        media::AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
+        AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
                 legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(usage));
-        media::AudioPolicyForcedConfig configAidl;
+        AudioPolicyForcedConfig configAidl;
         RETURN_IF_ERROR(statusTFromBinderStatus(
                 aps->getForceUse(usageAidl, &configAidl)));
         return aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(configAidl);
@@ -1094,7 +1097,8 @@
                                        std::vector<audio_io_handle_t>* secondaryOutputs,
                                        bool *isSpatialized,
                                        bool *isBitPerfect,
-                                       float *volume) {
+                                       float *volume,
+                                       bool *muted) {
     if (attr == nullptr) {
         ALOGE("%s NULL audio attributes", __func__);
         return BAD_VALUE;
@@ -1161,6 +1165,7 @@
     *attr = VALUE_OR_RETURN_STATUS(
             aidl2legacy_AudioAttributes_audio_attributes_t(responseAidl.attr));
     *volume = responseAidl.volume;
+    *muted = responseAidl.muted;
 
     return OK;
 }
@@ -1324,6 +1329,7 @@
 
 status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
                                            int index,
+                                           bool muted,
                                            audio_devices_t device) {
     const sp<IAudioPolicyService> aps = get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
@@ -1334,7 +1340,7 @@
     AudioDeviceDescription deviceAidl = VALUE_OR_RETURN_STATUS(
             legacy2aidl_audio_devices_t_AudioDeviceDescription(device));
     return statusTFromBinderStatus(
-            aps->setStreamVolumeIndex(streamAidl, deviceAidl, indexAidl));
+            aps->setStreamVolumeIndex(streamAidl, deviceAidl, indexAidl, muted));
 }
 
 status_t AudioSystem::getStreamVolumeIndex(audio_stream_type_t stream,
@@ -1358,6 +1364,7 @@
 
 status_t AudioSystem::setVolumeIndexForAttributes(const audio_attributes_t& attr,
                                                   int index,
+                                                  bool muted,
                                                   audio_devices_t device) {
     const sp<IAudioPolicyService> aps = get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
@@ -1368,7 +1375,7 @@
     AudioDeviceDescription deviceAidl = VALUE_OR_RETURN_STATUS(
             legacy2aidl_audio_devices_t_AudioDeviceDescription(device));
     return statusTFromBinderStatus(
-            aps->setVolumeIndexForAttributes(attrAidl, deviceAidl, indexAidl));
+            aps->setVolumeIndexForAttributes(attrAidl, deviceAidl, indexAidl, muted));
 }
 
 status_t AudioSystem::getVolumeIndexForAttributes(const audio_attributes_t& attr,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 336af36..d7c0b5b 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -188,6 +188,14 @@
     return result.value_or(false);
 }
 
+status_t AudioTrack::logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage) {
+    if (status != NO_ERROR) {
+        ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
+        reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
+    }
+    mStatus = status;
+    return mStatus;
+}
 // ---------------------------------------------------------------------------
 
 void AudioTrack::MediaMetrics::gather(const AudioTrack *track)
@@ -365,6 +373,10 @@
                 mSessionId, IPCThreadState::self()->getCallingPid(), clientPid);
         AudioSystem::releaseAudioSessionId(mSessionId, clientPid);
     }
+
+    if (mOutput != AUDIO_IO_HANDLE_NONE) {
+        AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
+    }
 }
 
 void AudioTrack::stopAndJoinCallbacks() {
@@ -413,9 +425,16 @@
     uint32_t channelCount;
     pid_t callingPid;
     pid_t myPid;
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
-    std::string errorMessage;
+    auto uid = aidl2legacy_int32_t_uid_t(attributionSource.uid);
+    auto pid = aidl2legacy_int32_t_pid_t(attributionSource.pid);
+    if (!uid.ok()) {
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE, StringPrintf("%s: received invalid attribution source uid", __func__));
+    }
+    if (!pid.ok()) {
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE, StringPrintf("%s: received invalid attribution source pid", __func__));
+    }
     // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
     ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "flags %#x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@@ -486,34 +505,33 @@
     case TRANSFER_CALLBACK:
     case TRANSFER_SYNC_NOTIF_CALLBACK:
         if (callback == nullptr || sharedBuffer != 0) {
-            errorMessage = StringPrintf(
-                    "%s: Transfer type %s but callback == nullptr || sharedBuffer != 0",
-                    convertTransferToText(transferType), __func__);
-            status = BAD_VALUE;
-            goto error;
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf(
+                            "%s: Transfer type %s but callback == nullptr || sharedBuffer != 0",
+                            convertTransferToText(transferType), __func__));
         }
         break;
     case TRANSFER_OBTAIN:
     case TRANSFER_SYNC:
         if (sharedBuffer != 0) {
-            errorMessage = StringPrintf(
-                    "%s: Transfer type TRANSFER_OBTAIN but sharedBuffer != 0", __func__);
-            status = BAD_VALUE;
-            goto error;
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s: Transfer type TRANSFER_OBTAIN but sharedBuffer != 0",
+                                 __func__));
         }
         break;
     case TRANSFER_SHARED:
         if (sharedBuffer == 0) {
-            errorMessage = StringPrintf(
-                    "%s: Transfer type TRANSFER_SHARED but sharedBuffer == 0", __func__);
-            status = BAD_VALUE;
-            goto error;
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s: Transfer type TRANSFER_SHARED but sharedBuffer == 0",
+                                 __func__));
         }
         break;
     default:
-        errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, transferType);
-        status = BAD_VALUE;
-        goto error;
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE, StringPrintf("%s: Invalid transfer type %d", __func__, transferType));
     }
     mSharedBuffer = sharedBuffer;
     mTransfer = transferType;
@@ -524,9 +542,8 @@
 
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
-        errorMessage = StringPrintf("%s: Track already in use", __func__);
-        status = INVALID_OPERATION;
-        goto error;
+        return logIfErrorAndReturnStatus(INVALID_OPERATION,
+                                         StringPrintf("%s: Track already in use", __func__));
     }
 
     // handle default values first.
@@ -535,9 +552,8 @@
     }
     if (pAttributes == NULL) {
         if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) {
-            errorMessage = StringPrintf("%s: Invalid stream type %d", __func__, streamType);
-            status = BAD_VALUE;
-            goto error;
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE, StringPrintf("%s: Invalid stream type %d", __func__, streamType));
         }
         mOriginalStreamType = streamType;
     } else {
@@ -546,15 +562,13 @@
 
     // validate parameters
     if (!audio_is_valid_format(format)) {
-        errorMessage = StringPrintf("%s: Invalid format %#x", __func__, format);
-        status = BAD_VALUE;
-        goto error;
+        return logIfErrorAndReturnStatus(BAD_VALUE,
+                                         StringPrintf("%s: Invalid format %#x", __func__, format));
     }
 
     if (!audio_is_output_channel(channelMask)) {
-        errorMessage = StringPrintf("%s: Invalid channel mask %#x",  __func__, channelMask);
-        status = BAD_VALUE;
-        goto error;
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE, StringPrintf("%s: Invalid channel mask %#x", __func__, channelMask));
     }
     channelCount = audio_channel_count_from_out_mask(channelMask);
     mChannelCount = channelCount;
@@ -569,10 +583,9 @@
 
     // sampling rate must be specified for direct outputs
     if (sampleRate == 0 && (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
-        errorMessage = StringPrintf(
-                "%s: sample rate must be specified for direct outputs", __func__);
-        status = BAD_VALUE;
-        goto error;
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE,
+                StringPrintf("%s: sample rate must be specified for direct outputs", __func__));
     }
     // 1.0 <= mMaxRequiredSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX
     mMaxRequiredSpeed = min(max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
@@ -600,17 +613,16 @@
         mNotificationsPerBufferReq = 0;
     } else {
         if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
-            errorMessage = StringPrintf(
-                    "%s: notificationFrames=%d not permitted for non-fast track",
-                    __func__, notificationFrames);
-            status = BAD_VALUE;
-            goto error;
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s: notificationFrames=%d not permitted for non-fast track",
+                                 __func__, notificationFrames));
         }
         if (frameCount > 0) {
-            ALOGE("%s(): notificationFrames=%d not permitted with non-zero frameCount=%zu",
-                    __func__, notificationFrames, frameCount);
-            status = BAD_VALUE;
-            goto error;
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE, StringPrintf("%s(): notificationFrames=%d not permitted "
+                                            "with non-zero frameCount=%zu",
+                                            __func__, notificationFrames, frameCount));
         }
         mNotificationFramesReq = 0;
         const uint32_t minNotificationsPerBuffer = 1;
@@ -627,12 +639,24 @@
     mClientAttributionSource = AttributionSourceState(attributionSource);
     callingPid = IPCThreadState::self()->getCallingPid();
     myPid = getpid();
-    if (uid == -1 || (callingPid != myPid)) {
-        mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
-            IPCThreadState::self()->getCallingUid()));
+    if (uid.value() == -1 || (callingPid != myPid)) {
+        auto clientAttributionSourceUid =
+                legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid());
+        if (!clientAttributionSourceUid.ok()) {
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s: received invalid client attribution source uid", __func__));
+        }
+        mClientAttributionSource.uid = clientAttributionSourceUid.value();
     }
-    if (pid == (pid_t)-1 || (callingPid != myPid)) {
-        mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(callingPid));
+    if (pid.value() == (pid_t)-1 || (callingPid != myPid)) {
+        auto clientAttributionSourcePid = legacy2aidl_uid_t_int32_t(callingPid);
+        if (!clientAttributionSourcePid.ok()) {
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s: received invalid client attribution source pid", __func__));
+        }
+        mClientAttributionSource.pid = clientAttributionSourcePid.value();
     }
     mAuxEffectId = 0;
     mCallback = callback;
@@ -655,7 +679,8 @@
             mAudioTrackThread.clear();
         }
         // We do not goto error to prevent double-logging errors.
-        goto exit;
+        mStatus = status;
+        return mStatus;
     }
 
     mLoopCount = 0;
@@ -670,7 +695,7 @@
     mReleased = 0;
     mStartNs = 0;
     mStartFromZeroUs = 0;
-    AudioSystem::acquireAudioSessionId(mSessionId, pid, uid);
+    AudioSystem::acquireAudioSessionId(mSessionId, pid.value(), uid.value());
     mSequence = 1;
     mObservedSequence = mSequence;
     mInUnderrun = false;
@@ -688,15 +713,7 @@
     mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
     mVolumeHandler = new media::VolumeHandler();
 
-error:
-    if (status != NO_ERROR) {
-        ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
-        reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
-    }
-    // fall through
-exit:
-    mStatus = status;
-    return status;
+    return logIfErrorAndReturnStatus(status, "");
 }
 
 
@@ -723,8 +740,22 @@
         audio_port_handle_t selectedDeviceId)
 {
     AttributionSourceState attributionSource;
-    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
-    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
+    auto attributionSourceUid = legacy2aidl_uid_t_int32_t(uid);
+    if (!attributionSourceUid.ok()) {
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE,
+                StringPrintf("%s: received invalid attribution source uid, uid: %d, session id: %d",
+                             __func__, uid, sessionId));
+    }
+    attributionSource.uid = attributionSourceUid.value();
+    auto attributionSourcePid = legacy2aidl_pid_t_int32_t(pid);
+    if (!attributionSourcePid.ok()) {
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE,
+                StringPrintf("%s: received invalid attribution source pid, pid: %d, sessionId: %d",
+                             __func__, pid, sessionId));
+    }
+    attributionSource.pid = attributionSourcePid.value();
     attributionSource.token = sp<BBinder>::make();
     if (callback) {
         mLegacyCallbackWrapper = sp<LegacyCallbackWrapper>::make(callback, user);
@@ -1804,15 +1835,11 @@
 status_t AudioTrack::createTrack_l()
 {
     status_t status;
-    bool callbackAdded = false;
-    std::string errorMessage;
 
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
     if (audioFlinger == 0) {
-        errorMessage = StringPrintf("%s(%d): Could not get audioflinger",
-                __func__, mPortId);
-        status = DEAD_OBJECT;
-        goto exit;
+        return logIfErrorAndReturnStatus(
+                DEAD_OBJECT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId));
     }
 
     {
@@ -1880,21 +1907,31 @@
     input.audioTrackCallback = mAudioTrackCallback;
 
     media::CreateTrackResponse response;
-    status = audioFlinger->createTrack(VALUE_OR_FATAL(input.toAidl()), response);
+    auto aidlInput = input.toAidl();
+    if (!aidlInput.ok()) {
+        return logIfErrorAndReturnStatus(
+                BAD_VALUE, StringPrintf("%s(%d): Could not create track due to invalid input",
+                                        __func__, mPortId));
+    }
+    status = audioFlinger->createTrack(aidlInput.value(), response);
 
     IAudioFlinger::CreateTrackOutput output{};
     if (status == NO_ERROR) {
-        output = VALUE_OR_FATAL(IAudioFlinger::CreateTrackOutput::fromAidl(response));
+        auto trackOutput = IAudioFlinger::CreateTrackOutput::fromAidl(response);
+        if (!trackOutput.ok()) {
+            return logIfErrorAndReturnStatus(
+                    BAD_VALUE,
+                    StringPrintf("%s(%d): Could not create track output due to invalid response",
+                                 __func__, mPortId));
+        }
+        output = trackOutput.value();
     }
 
     if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
-        errorMessage = StringPrintf(
-                "%s(%d): AudioFlinger could not create track, status: %d output %d",
-                __func__, mPortId, status, output.outputId);
-        if (status == NO_ERROR) {
-            status = INVALID_OPERATION; // device not ready
-        }
-        goto exit;
+        return logIfErrorAndReturnStatus(
+                status == NO_ERROR ? INVALID_OPERATION : status,  // device not ready
+                StringPrintf("%s(%d): AudioFlinger could not create track, status: %d output %d",
+                             __func__, mPortId, status, output.outputId));
     }
     ALOG_ASSERT(output.audioTrack != 0);
 
@@ -1924,22 +1961,22 @@
     // FIXME compare to AudioRecord
     std::optional<media::SharedFileRegion> sfr;
     output.audioTrack->getCblk(&sfr);
-    sp<IMemory> iMem = VALUE_OR_FATAL(aidl2legacy_NullableSharedFileRegion_IMemory(sfr));
-    if (iMem == 0) {
-        errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId);
-        status = FAILED_TRANSACTION;
-        goto exit;
+    auto iMemory = aidl2legacy_NullableSharedFileRegion_IMemory(sfr);
+    if (!iMemory.ok() || iMemory.value() == 0) {
+        return logIfErrorAndReturnStatus(
+                FAILED_TRANSACTION,
+                StringPrintf("%s(%d): Could not get control block", __func__, mPortId));
     }
+    sp<IMemory> iMem = iMemory.value();
     // TODO: Using unsecurePointer() has some associated security pitfalls
     //       (see declaration for details).
     //       Either document why it is safe in this case or address the
     //       issue (e.g. by copying).
     void *iMemPointer = iMem->unsecurePointer();
     if (iMemPointer == NULL) {
-        errorMessage = StringPrintf(
-                "%s(%d): Could not get control block pointer", __func__, mPortId);
-        status = FAILED_TRANSACTION;
-        goto exit;
+        return logIfErrorAndReturnStatus(
+                FAILED_TRANSACTION,
+                StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId));
     }
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
@@ -1974,7 +2011,6 @@
             AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
         }
         AudioSystem::addAudioDeviceCallback(this, output.outputId, output.portId);
-        callbackAdded = true;
     }
 
     mPortId = output.portId;
@@ -1999,11 +2035,9 @@
         //       issue (e.g. by copying).
         buffers = mSharedBuffer->unsecurePointer();
         if (buffers == NULL) {
-            errorMessage = StringPrintf(
-                    "%s(%d): Could not get buffer pointer", __func__, mPortId);
-            ALOGE("%s", errorMessage.c_str());
-            status = FAILED_TRANSACTION;
-            goto exit;
+            return logIfErrorAndReturnStatus(
+                    FAILED_TRANSACTION,
+                    StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId));
         }
     }
 
@@ -2100,19 +2134,8 @@
 
     }
 
-exit:
-    if (status != NO_ERROR) {
-        if (callbackAdded) {
-            // note: mOutput is always valid is callbackAdded is true
-            AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
-        }
-        ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
-        reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
-    }
-    mStatus = status;
-
     // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
-    return status;
+    return logIfErrorAndReturnStatus(status, "");
 }
 
 void AudioTrack::reportError(status_t status, const char *event, const char *message) const
@@ -3203,7 +3226,12 @@
         media::AudioTimestampInternal ts;
         mAudioTrack->getTimestamp(&ts, &status);
         if (status == OK) {
-            timestamp = VALUE_OR_FATAL(aidl2legacy_AudioTimestampInternal_AudioTimestamp(ts));
+            auto legacyTs = aidl2legacy_AudioTimestampInternal_AudioTimestamp(ts);
+            if (!legacyTs.ok()) {
+                return logIfErrorAndReturnStatus(
+                        BAD_VALUE, StringPrintf("%s: received invalid audio timestamp", __func__));
+            }
+            timestamp = legacyTs.value();
         }
     } else {
         // read timestamp from shared memory
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 9241973..168b47e 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -337,11 +337,12 @@
 }
 
 status_t AudioFlingerClientAdapter::setStreamVolume(audio_stream_type_t stream, float value,
-                                                    audio_io_handle_t output) {
+                                                    bool muted, audio_io_handle_t output) {
     AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
             legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
     int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
-    return statusTFromBinderStatus(mDelegate->setStreamVolume(streamAidl, value, outputAidl));
+    return statusTFromBinderStatus(
+            mDelegate->setStreamVolume(streamAidl, value, muted, outputAidl));
 }
 
 status_t AudioFlingerClientAdapter::setStreamMute(audio_stream_type_t stream, bool muted) {
@@ -351,12 +352,14 @@
 }
 
 status_t AudioFlingerClientAdapter::setPortsVolume(
-        const std::vector<audio_port_handle_t>& portIds, float volume, audio_io_handle_t output) {
+        const std::vector<audio_port_handle_t> &portIds, float volume, bool muted,
+        audio_io_handle_t output) {
     std::vector<int32_t> portIdsAidl = VALUE_OR_RETURN_STATUS(
             convertContainer<std::vector<int32_t>>(
                     portIds, legacy2aidl_audio_port_handle_t_int32_t));
     int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
-    return statusTFromBinderStatus(mDelegate->setPortsVolume(portIdsAidl, volume, outputAidl));
+    return statusTFromBinderStatus(
+            mDelegate->setPortsVolume(portIdsAidl, volume, muted, outputAidl));
 }
 
 status_t AudioFlingerClientAdapter::setMode(audio_mode_t mode) {
@@ -1007,12 +1010,13 @@
 }
 
 Status AudioFlingerServerAdapter::setStreamVolume(AudioStreamType stream, float value,
-                                                  int32_t output) {
+                                                  bool muted, int32_t output) {
     audio_stream_type_t streamLegacy = VALUE_OR_RETURN_BINDER(
             aidl2legacy_AudioStreamType_audio_stream_type_t(stream));
     audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
             aidl2legacy_int32_t_audio_io_handle_t(output));
-    return Status::fromStatusT(mDelegate->setStreamVolume(streamLegacy, value, outputLegacy));
+    return Status::fromStatusT(
+            mDelegate->setStreamVolume(streamLegacy, value, muted, outputLegacy));
 }
 
 Status AudioFlingerServerAdapter::setStreamMute(AudioStreamType stream, bool muted) {
@@ -1022,13 +1026,14 @@
 }
 
 Status AudioFlingerServerAdapter::setPortsVolume(
-        const std::vector<int32_t>& portIds, float volume, int32_t output) {
+        const std::vector<int32_t>& portIds, float volume, bool muted, int32_t output) {
     std::vector<audio_port_handle_t> portIdsLegacy = VALUE_OR_RETURN_BINDER(
             convertContainer<std::vector<audio_port_handle_t>>(
                     portIds, aidl2legacy_int32_t_audio_port_handle_t));
     audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
             aidl2legacy_int32_t_audio_io_handle_t(output));
-    return Status::fromStatusT(mDelegate->setPortsVolume(portIdsLegacy, volume, outputLegacy));
+    return Status::fromStatusT(
+            mDelegate->setPortsVolume(portIdsLegacy, volume, muted, outputLegacy));
 }
 
 Status AudioFlingerServerAdapter::setMode(AudioMode mode) {
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index 163a359..a414cb7 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -296,138 +296,6 @@
     return unexpected(BAD_VALUE);
 }
 
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl) {
-    switch (aidl) {
-        case media::AudioPolicyForceUse::COMMUNICATION:
-            return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
-        case media::AudioPolicyForceUse::MEDIA:
-            return AUDIO_POLICY_FORCE_FOR_MEDIA;
-        case media::AudioPolicyForceUse::RECORD:
-            return AUDIO_POLICY_FORCE_FOR_RECORD;
-        case media::AudioPolicyForceUse::DOCK:
-            return AUDIO_POLICY_FORCE_FOR_DOCK;
-        case media::AudioPolicyForceUse::SYSTEM:
-            return AUDIO_POLICY_FORCE_FOR_SYSTEM;
-        case media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
-            return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
-        case media::AudioPolicyForceUse::ENCODED_SURROUND:
-            return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
-        case media::AudioPolicyForceUse::VIBRATE_RINGING:
-            return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<media::AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
-    switch (legacy) {
-        case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
-            return media::AudioPolicyForceUse::COMMUNICATION;
-        case AUDIO_POLICY_FORCE_FOR_MEDIA:
-            return media::AudioPolicyForceUse::MEDIA;
-        case AUDIO_POLICY_FORCE_FOR_RECORD:
-            return media::AudioPolicyForceUse::RECORD;
-        case AUDIO_POLICY_FORCE_FOR_DOCK:
-            return media::AudioPolicyForceUse::DOCK;
-        case AUDIO_POLICY_FORCE_FOR_SYSTEM:
-            return media::AudioPolicyForceUse::SYSTEM;
-        case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
-            return media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
-        case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
-            return media::AudioPolicyForceUse::ENCODED_SURROUND;
-        case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
-            return media::AudioPolicyForceUse::VIBRATE_RINGING;
-        case AUDIO_POLICY_FORCE_USE_CNT:
-            break;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl) {
-    switch (aidl) {
-        case media::AudioPolicyForcedConfig::NONE:
-            return AUDIO_POLICY_FORCE_NONE;
-        case media::AudioPolicyForcedConfig::SPEAKER:
-            return AUDIO_POLICY_FORCE_SPEAKER;
-        case media::AudioPolicyForcedConfig::HEADPHONES:
-            return AUDIO_POLICY_FORCE_HEADPHONES;
-        case media::AudioPolicyForcedConfig::BT_SCO:
-            return AUDIO_POLICY_FORCE_BT_SCO;
-        case media::AudioPolicyForcedConfig::BT_A2DP:
-            return AUDIO_POLICY_FORCE_BT_A2DP;
-        case media::AudioPolicyForcedConfig::WIRED_ACCESSORY:
-            return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
-        case media::AudioPolicyForcedConfig::BT_CAR_DOCK:
-            return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
-        case media::AudioPolicyForcedConfig::BT_DESK_DOCK:
-            return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
-        case media::AudioPolicyForcedConfig::ANALOG_DOCK:
-            return AUDIO_POLICY_FORCE_ANALOG_DOCK;
-        case media::AudioPolicyForcedConfig::DIGITAL_DOCK:
-            return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
-        case media::AudioPolicyForcedConfig::NO_BT_A2DP:
-            return AUDIO_POLICY_FORCE_NO_BT_A2DP;
-        case media::AudioPolicyForcedConfig::SYSTEM_ENFORCED:
-            return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
-        case media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
-            return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
-        case media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
-            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
-        case media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
-            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
-        case media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
-            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
-        case media::AudioPolicyForcedConfig::BT_BLE:
-            return AUDIO_POLICY_FORCE_BT_BLE;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<media::AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
-    switch (legacy) {
-        case AUDIO_POLICY_FORCE_NONE:
-            return media::AudioPolicyForcedConfig::NONE;
-        case AUDIO_POLICY_FORCE_SPEAKER:
-            return media::AudioPolicyForcedConfig::SPEAKER;
-        case AUDIO_POLICY_FORCE_HEADPHONES:
-            return media::AudioPolicyForcedConfig::HEADPHONES;
-        case AUDIO_POLICY_FORCE_BT_SCO:
-            return media::AudioPolicyForcedConfig::BT_SCO;
-        case AUDIO_POLICY_FORCE_BT_A2DP:
-            return media::AudioPolicyForcedConfig::BT_A2DP;
-        case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
-            return media::AudioPolicyForcedConfig::WIRED_ACCESSORY;
-        case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
-            return media::AudioPolicyForcedConfig::BT_CAR_DOCK;
-        case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
-            return media::AudioPolicyForcedConfig::BT_DESK_DOCK;
-        case AUDIO_POLICY_FORCE_ANALOG_DOCK:
-            return media::AudioPolicyForcedConfig::ANALOG_DOCK;
-        case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
-            return media::AudioPolicyForcedConfig::DIGITAL_DOCK;
-        case AUDIO_POLICY_FORCE_NO_BT_A2DP:
-            return media::AudioPolicyForcedConfig::NO_BT_A2DP;
-        case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
-            return media::AudioPolicyForcedConfig::SYSTEM_ENFORCED;
-        case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
-            return media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
-        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
-            return media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
-        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
-            return media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
-        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
-            return media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
-        case AUDIO_POLICY_FORCE_BT_BLE:
-            return media::AudioPolicyForcedConfig::BT_BLE;
-        case AUDIO_POLICY_FORCE_CFG_CNT:
-            break;
-    }
-    return unexpected(BAD_VALUE);
-}
-
 ConversionResult<device_role_t>
 aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl) {
     switch (aidl) {
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index 68dba34..29b876c 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -47,12 +47,7 @@
       "name": "audioeffect_analysis"
     },
     {
-      "name": "CtsVirtualDevicesTestCases",
-      "options" : [
-        {
-          "include-filter": "android.virtualdevice.cts.VirtualAudioTest"
-        }
-      ]
+      "name": "CtsVirtualDevicesAudioTestCases"
     }
   ]
 }
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 79fcea8..d325d0a 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1033,17 +1033,11 @@
 
     mState = TONE_IDLE;
 
-    if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
-        ALOGE("Unable to marshal AudioFlinger");
-        return;
-    }
     mThreadCanCallJava = threadCanCallJava;
     mStreamType = streamType;
     mVolume = volume;
     mpToneDesc = NULL;
     mpNewToneDesc = NULL;
-    // Generate tone by chunks of 20 ms to keep cadencing precision
-    mProcessSize = (mSamplingRate * 20) / 1000;
 
     char value[PROPERTY_VALUE_MAX];
     if (property_get("gsm.operator.iso-country", value, "") == 0) {
@@ -1321,21 +1315,21 @@
     mpAudioTrack = new AudioTrack(attributionSource);
     ALOGV("AudioTrack(%p) created", mpAudioTrack.get());
 
+
     audio_attributes_t attr;
     audio_stream_type_t streamType = mStreamType;
-    if (mStreamType == AUDIO_STREAM_VOICE_CALL) {
+    if (mStreamType == AUDIO_STREAM_VOICE_CALL || mStreamType == AUDIO_STREAM_BLUETOOTH_SCO) {
         streamType = AUDIO_STREAM_DTMF;
     }
     attr = AudioSystem::streamTypeToAttributes(streamType);
     attr.flags = static_cast<audio_flags_mask_t>(attr.flags | AUDIO_FLAG_LOW_LATENCY);
 
-    const size_t frameCount = mProcessSize;
     status_t status = mpAudioTrack->set(
             AUDIO_STREAM_DEFAULT,
             0,    // sampleRate
             AUDIO_FORMAT_PCM_16_BIT,
             AUDIO_CHANNEL_OUT_MONO,
-            frameCount,
+            0,    // frameCount
             AUDIO_OUTPUT_FLAG_NONE,
             wp<AudioTrack::IAudioTrackCallback>::fromExisting(this),
             0,    // notificationFrames
@@ -1355,6 +1349,10 @@
         return false;
     }
 
+    mSamplingRate = mpAudioTrack->getSampleRate();
+    // Generate tone by chunks of 20 ms to keep cadencing precision
+    mProcessSize = (mSamplingRate * 20) / 1000;
+
     mpAudioTrack->setVolume(mVolume);
     mState = TONE_INIT;
     return true;
diff --git a/media/libaudioclient/TrackPlayerBase.cpp b/media/libaudioclient/TrackPlayerBase.cpp
index 4fc1c44..bc38251 100644
--- a/media/libaudioclient/TrackPlayerBase.cpp
+++ b/media/libaudioclient/TrackPlayerBase.cpp
@@ -38,12 +38,12 @@
                            player_type_t playerType, audio_usage_t usage,
                            audio_session_t sessionId) {
     PlayerBase::init(playerType, usage, sessionId);
-    mAudioTrack = pat;
-    if (mAudioTrack != 0) {
+    mAudioTrack.store(pat);
+    if (pat != 0) {
         mCallbackHandle = callback;
         mSelfAudioDeviceCallback = new SelfAudioDeviceCallback(*this);
-        mAudioTrack->addAudioDeviceCallback(mSelfAudioDeviceCallback);
-        mAudioTrack->setPlayerIId(mPIId); // set in PlayerBase::init().
+        pat->addAudioDeviceCallback(mSelfAudioDeviceCallback);
+        pat->setPlayerIId(mPIId);  // set in PlayerBase::init().
     }
 }
 
@@ -65,12 +65,15 @@
 }
 
 void TrackPlayerBase::doDestroy() {
-    if (mAudioTrack != 0) {
-        mAudioTrack->stop();
-        mAudioTrack->removeAudioDeviceCallback(mSelfAudioDeviceCallback);
+    sp<AudioTrack> audioTrack = getAudioTrack();
+
+    // Note that there may still be another reference in post-unlock phase of SetPlayState
+    clearAudioTrack();
+
+    if (audioTrack != 0) {
+        audioTrack->stop();
+        audioTrack->removeAudioDeviceCallback(mSelfAudioDeviceCallback);
         mSelfAudioDeviceCallback.clear();
-        // Note that there may still be another reference in post-unlock phase of SetPlayState
-        mAudioTrack.clear();
     }
 }
 
@@ -87,16 +90,16 @@
 // Implementation of IPlayer
 status_t TrackPlayerBase::playerStart() {
     status_t status = NO_INIT;
-    if (mAudioTrack != 0) {
-        status = mAudioTrack->start();
+    if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+        status = audioTrack->start();
     }
     return status;
 }
 
 status_t TrackPlayerBase::playerPause() {
     status_t status = NO_INIT;
-    if (mAudioTrack != 0) {
-        mAudioTrack->pause();
+    if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+        audioTrack->pause();
         status = NO_ERROR;
     }
     return status;
@@ -105,8 +108,8 @@
 
 status_t TrackPlayerBase::playerStop() {
     status_t status = NO_INIT;
-    if (mAudioTrack != 0) {
-        mAudioTrack->stop();
+    if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+        audioTrack->stop();
         status = NO_ERROR;
     }
     return status;
@@ -118,10 +121,10 @@
 
 status_t TrackPlayerBase::doSetVolume() {
     status_t status = NO_INIT;
-    if (mAudioTrack != 0) {
+    if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
         float tl = mPlayerVolumeL * mPanMultiplierL * mVolumeMultiplierL;
         float tr = mPlayerVolumeR * mPanMultiplierR * mVolumeMultiplierR;
-        mAudioTrack->setVolume(tl, tr);
+        audioTrack->setVolume(tl, tr);
         status = NO_ERROR;
     }
     return status;
@@ -140,10 +143,9 @@
     if (s != OK) {
         return binderStatusFromStatusT(s);
     }
-
-    if (mAudioTrack != 0) {
+    if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
         ALOGD("TrackPlayerBase::applyVolumeShaper() from IPlayer");
-        VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
+        VolumeShaper::Status status = audioTrack->applyVolumeShaper(spConfiguration, spOperation);
         if (status < 0) { // a non-negative value is the volume shaper id.
             ALOGE("TrackPlayerBase::applyVolumeShaper() failed with status %d", status);
         }
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
deleted file mode 100644
index 9bb0605..0000000
--- a/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media;
-
-/**
- * {@hide}
- */
-@Backing(type="int")
-enum AudioPolicyForceUse {
-    COMMUNICATION = 0,
-    MEDIA = 1,
-    RECORD = 2,
-    DOCK = 3,
-    SYSTEM = 4,
-    HDMI_SYSTEM_AUDIO = 5,
-    ENCODED_SURROUND = 6,
-    VIBRATE_RINGING = 7,
-}
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
deleted file mode 100644
index 111bb2f..0000000
--- a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media;
-
-/**
- * {@hide}
- */
-@Backing(type="int")
-enum AudioPolicyForcedConfig {
-    NONE = 0,
-    SPEAKER = 1,
-    HEADPHONES = 2,
-    BT_SCO = 3,
-    BT_A2DP = 4,
-    WIRED_ACCESSORY = 5,
-    BT_CAR_DOCK = 6,
-    BT_DESK_DOCK = 7,
-    ANALOG_DOCK = 8,
-    DIGITAL_DOCK = 9,
-    NO_BT_A2DP = 10, /* A2DP sink is not preferred to speaker or wired HS */
-    SYSTEM_ENFORCED = 11,
-    HDMI_SYSTEM_AUDIO_ENFORCED = 12,
-    ENCODED_SURROUND_NEVER = 13,
-    ENCODED_SURROUND_ALWAYS = 14,
-    ENCODED_SURROUND_MANUAL = 15,
-    BT_BLE = 16,
-}
diff --git a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
index 4b26d5b..d3975c0 100644
--- a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
@@ -41,4 +41,6 @@
     AudioAttributes attr;
     /** initial port volume for the new audio track */
     float volume;
+    /** initial port muted state for the new audio track */
+    boolean muted;
 }
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 1c825bc..474ab11 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -96,15 +96,17 @@
     /*
      * Set stream type state. This will probably be used by
      * the preference panel, mostly.
+     * This method is deprecated. Please use the setPortsVolume method instead.
      */
-    void setStreamVolume(AudioStreamType stream, float value, int /* audio_io_handle_t */ output);
+    void setStreamVolume(AudioStreamType stream, float value, boolean muted,
+            int /* audio_io_handle_t */ output);
     void setStreamMute(AudioStreamType stream, boolean muted);
 
     /*
      * Set AudioTrack port ids volume attribute. This is the new way of controlling volume from
      * AudioPolicyManager to AudioFlinger.
      */
-    void setPortsVolume(in int[] /* audio_port_handle_t[] */ portIds, float volume,
+    void setPortsVolume(in int[] /* audio_port_handle_t[] */ portIds, float volume, boolean muted,
             int /* audio_io_handle_t */ output);
 
     // set audio mode.
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index ac42ea9..40ab938 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -25,8 +25,6 @@
 import android.media.AudioOffloadMode;
 import android.media.AudioPatchFw;
 import android.media.AudioPolicyDeviceState;
-import android.media.AudioPolicyForcedConfig;
-import android.media.AudioPolicyForceUse;
 import android.media.AudioPortFw;
 import android.media.AudioPortConfigFw;
 import android.media.AudioPortRole;
@@ -49,6 +47,8 @@
 import android.media.audio.common.AudioDeviceDescription;
 import android.media.audio.common.AudioFormatDescription;
 import android.media.audio.common.AudioMode;
+import android.media.audio.common.AudioPolicyForcedConfig;
+import android.media.audio.common.AudioPolicyForceUse;
 import android.media.audio.common.AudioProfile;
 import android.media.audio.common.AudioOffloadInfo;
 import android.media.audio.common.AudioPort;
@@ -116,9 +116,9 @@
 
     void releaseInput(int /* audio_port_handle_t */ portId);
 
-    oneway void setDeviceAbsoluteVolumeEnabled(in AudioDevice device,
-                                               boolean enabled,
-                                               AudioStreamType streamToDriveAbs);
+    void setDeviceAbsoluteVolumeEnabled(in AudioDevice device,
+                                        boolean enabled,
+                                        AudioStreamType streamToDriveAbs);
 
     void initStreamVolume(AudioStreamType stream,
                           int indexMin,
@@ -126,14 +126,14 @@
 
     void setStreamVolumeIndex(AudioStreamType stream,
                               in AudioDeviceDescription device,
-                              int index);
+                              int index, boolean muted);
 
     int getStreamVolumeIndex(AudioStreamType stream,
                              in AudioDeviceDescription device);
 
     void setVolumeIndexForAttributes(in AudioAttributes attr,
                                      in AudioDeviceDescription device,
-                                     int index);
+                                     int index, boolean muted);
 
     int getVolumeIndexForAttributes(in AudioAttributes attr,
                                     in AudioDeviceDescription device);
diff --git a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
index 710a656..b0b7e03 100644
--- a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
+++ b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
@@ -511,11 +511,11 @@
 
         stream = getValue(&mFdp, kStreamtypes);
         AudioSystem::setStreamVolume(stream, mFdp.ConsumeFloatingPoint<float>(),
-                                     mFdp.ConsumeIntegral<int32_t>());
+                                     mFdp.ConsumeBool(), mFdp.ConsumeIntegral<int32_t>());
     } else {
         std::vector <audio_port_handle_t> portsForVolumeChange{};
         AudioSystem::setPortsVolume(portsForVolumeChange, mFdp.ConsumeFloatingPoint<float>(),
-                                    mFdp.ConsumeIntegral<int32_t>());
+                                    mFdp.ConsumeBool(), mFdp.ConsumeIntegral<int32_t>());
     }
     audio_mode_t mode = getValue(&mFdp, kModes);
     AudioSystem::setMode(mode);
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index d4479ef..25d91d3 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -138,6 +138,12 @@
                                       audio_format_t format,
                                       audio_channel_mask_t channelMask);
 
+    /* Checks for erroneous status, marks error in MediaMetrics, logs the error message.
+     * Updates and returns mStatus.
+     */
+    status_t logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage,
+                                       const std::string& func);
+
     /* How data is transferred from AudioRecord
      */
     enum transfer_type {
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 40e5673..31e4f05 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -126,7 +126,7 @@
 
     // set stream volume on specified output
     static status_t setStreamVolume(audio_stream_type_t stream, float value,
-                                    audio_io_handle_t output);
+                                    bool muted, audio_io_handle_t output);
 
     // mute/unmute stream
     static status_t setStreamMute(audio_stream_type_t stream, bool mute);
@@ -135,11 +135,12 @@
      * Set volume for given AudioTrack port ids on specified output
      * @param portIds to consider
      * @param volume to set
+     * @param muted to set
      * @param output to consider
      * @return NO_ERROR if successful
      */
     static status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds,
-                                   float volume, audio_io_handle_t output);
+                                   float volume, bool muted, audio_io_handle_t output);
 
     // set audio mode in audio hardware
     static status_t setMode(audio_mode_t mode);
@@ -345,7 +346,8 @@
                                      std::vector<audio_io_handle_t> *secondaryOutputs,
                                      bool *isSpatialized,
                                      bool *isBitPerfect,
-                                     float *volume);
+                                     float *volume,
+                                     bool *muted);
     static status_t startOutput(audio_port_handle_t portId);
     static status_t stopOutput(audio_port_handle_t portId);
     static void releaseOutput(audio_port_handle_t portId);
@@ -391,6 +393,7 @@
                                      int indexMax);
     static status_t setStreamVolumeIndex(audio_stream_type_t stream,
                                          int index,
+                                         bool muted,
                                          audio_devices_t device);
     static status_t getStreamVolumeIndex(audio_stream_type_t stream,
                                          int *index,
@@ -398,6 +401,7 @@
 
     static status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
                                                 int index,
+                                                bool muted,
                                                 audio_devices_t device);
     static status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
                                                 int &index,
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 3a001a4..de97863 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -233,8 +233,7 @@
      * FIXME This API assumes a route, and so should be deprecated.
      */
 
-    static status_t getMinFrameCount(size_t* frameCount,
-                                     audio_stream_type_t streamType,
+    static status_t getMinFrameCount(size_t* frameCount, audio_stream_type_t streamType,
                                      uint32_t sampleRate);
 
     /* Check if direct playback is possible for the given audio configuration and attributes.
@@ -243,6 +242,11 @@
     static bool isDirectOutputSupported(const audio_config_base_t& config,
                                         const audio_attributes_t& attributes);
 
+    /* Checks for erroneous status, logs the error message.
+     * Updates and returns mStatus.
+     */
+    status_t logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage);
+
     /* How data is transferred to AudioTrack
      */
     enum transfer_type {
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index a5f3217..21ecb09 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -226,18 +226,19 @@
      * the preference panel, mostly.
      */
     virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value,
-                                    audio_io_handle_t output) = 0;
+                                    bool muted, audio_io_handle_t output) = 0;
     virtual     status_t    setStreamMute(audio_stream_type_t stream, bool muted) = 0;
 
     /**
      * Set volume for given AudioTrack port ids on specified output
      * @param portIds to consider
      * @param volume to set
+     * @param muted to set
      * @param output to consider
      * @return NO_ERROR if successful
      */
     virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
-            audio_io_handle_t output) = 0;
+            bool muted, audio_io_handle_t output) = 0;
 
     // set audio mode
     virtual     status_t    setMode(audio_mode_t mode) = 0;
@@ -428,10 +429,10 @@
     status_t setMasterBalance(float balance) override;
     status_t getMasterBalance(float* balance) const override;
     status_t setStreamVolume(audio_stream_type_t stream, float value,
-                             audio_io_handle_t output) override;
+                             bool muted, audio_io_handle_t output) override;
     status_t setStreamMute(audio_stream_type_t stream, bool muted) override;
     status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
-            audio_io_handle_t output) override;
+            bool muted, audio_io_handle_t output) override;
     status_t setMode(audio_mode_t mode) override;
     status_t setMicMute(bool state) override;
     bool getMicMute() const override;
@@ -675,10 +676,10 @@
     Status setMasterBalance(float balance) override;
     Status getMasterBalance(float* _aidl_return) override;
     Status setStreamVolume(media::audio::common::AudioStreamType stream,
-                           float value, int32_t output) override;
+                           float value, bool muted, int32_t output) override;
     Status setStreamMute(media::audio::common::AudioStreamType stream, bool muted) override;
-    Status setPortsVolume(const std::vector<int32_t>& portIds, float volume, int32_t output)
-            override;
+    Status setPortsVolume(const std::vector<int32_t>& portIds, float volume, bool muted,
+                          int32_t output) override;
     Status setMode(media::audio::common::AudioMode mode) override;
     Status setMicMute(bool state) override;
     Status getMicMute(bool* _aidl_return) override;
diff --git a/media/libaudioclient/include/media/PolicyAidlConversion.h b/media/libaudioclient/include/media/PolicyAidlConversion.h
index ed9ddd6..1b90d6b 100644
--- a/media/libaudioclient/include/media/PolicyAidlConversion.h
+++ b/media/libaudioclient/include/media/PolicyAidlConversion.h
@@ -28,8 +28,6 @@
 #include <android/media/AudioMixRouteFlag.h>
 #include <android/media/AudioMixType.h>
 #include <android/media/AudioOffloadMode.h>
-#include <android/media/AudioPolicyForceUse.h>
-#include <android/media/AudioPolicyForcedConfig.h>
 #include <android/media/DeviceRole.h>
 
 #include <media/AidlConversionUtil.h>
@@ -84,16 +82,6 @@
 ConversionResult<media::AudioPolicyDeviceState>
 legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(audio_policy_dev_state_t legacy);
 
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl);
-ConversionResult<media::AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
-
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl);
-ConversionResult<media::AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
-
 ConversionResult<device_role_t>
 aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl);
 ConversionResult<media::DeviceRole>
diff --git a/media/libaudioclient/include/media/TrackPlayerBase.h b/media/libaudioclient/include/media/TrackPlayerBase.h
index fe88116..8df9ff8 100644
--- a/media/libaudioclient/include/media/TrackPlayerBase.h
+++ b/media/libaudioclient/include/media/TrackPlayerBase.h
@@ -19,6 +19,7 @@
 
 #include <media/AudioTrack.h>
 #include <media/PlayerBase.h>
+#include <mediautils/Synchronization.h>
 
 namespace android {
 
@@ -37,10 +38,11 @@
             const media::VolumeShaperConfiguration& configuration,
             const media::VolumeShaperOperation& operation);
 
-    //FIXME move to protected field, so far made public to minimize changes to AudioTrack logic
-    sp<AudioTrack> mAudioTrack;
+    sp<AudioTrack> getAudioTrack() { return mAudioTrack.load(); }
 
-            void setPlayerVolume(float vl, float vr);
+    void clearAudioTrack() { mAudioTrack.store(nullptr); }
+
+    void setPlayerVolume(float vl, float vr);
 
 protected:
 
@@ -68,6 +70,7 @@
     float mPlayerVolumeL, mPlayerVolumeR;
     sp<AudioTrack::IAudioTrackCallback> mCallbackHandle;
     sp<SelfAudioDeviceCallback> mSelfAudioDeviceCallback;
+    mediautils::atomic_sp<AudioTrack> mAudioTrack;
 };
 
 } // namespace android
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index 7f55e48..2076045 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -483,8 +483,27 @@
                                  AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>(
                                          std::vector<int32_t>{1, 2}))));
 
+TEST(AnonymizedBluetoothAddressRoundTripTest, Legacy2Aidl2Legacy) {
+    const std::vector<uint8_t> sAnonymizedAidlAddress {0xFD, 0xFF, 0xFF, 0xFF, 0xAB, 0xCD};
+    const std::string sAnonymizedLegacyAddress = std::string("XX:XX:XX:XX:AB:CD");
+    auto device = legacy2aidl_audio_device_AudioDevice(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+                                                       sAnonymizedLegacyAddress);
+    ASSERT_TRUE(device.ok());
+    ASSERT_EQ(AudioDeviceAddress::Tag::mac, device.value().address.getTag());
+    ASSERT_EQ(sAnonymizedAidlAddress, device.value().address.get<AudioDeviceAddress::mac>());
+
+    audio_devices_t legacyType;
+    std::string legacyAddress;
+    status_t status =
+            aidl2legacy_AudioDevice_audio_device(device.value(), &legacyType, &legacyAddress);
+    ASSERT_EQ(OK, status);
+    EXPECT_EQ(legacyType, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
+    EXPECT_EQ(sAnonymizedLegacyAddress, legacyAddress);
+}
+
 class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> {
 };
+
 TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
     const auto initial = GetParam();
     auto conv = aidl2legacy_AudioFormatDescription_audio_format_t(initial);
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 8151d39..a3ab9d2 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -86,7 +86,18 @@
     }
 }
 
-TEST(AudioTrackTest, DefaultRoutingTest) {
+class AudioTrackTest
+        : public ::testing::TestWithParam<int> {
+
+public:
+    AudioTrackTest()
+            : mSampleRate(GetParam()){};
+
+    const uint32_t mSampleRate;
+
+};
+
+TEST_P(AudioTrackTest, DefaultRoutingTest) {
     audio_port_v7 port;
     if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
                                   AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
@@ -95,7 +106,8 @@
 
     // create record instance
     sp<AudioCapture> capture = sp<AudioCapture>::make(
-            AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
+            AUDIO_SOURCE_REMOTE_SUBMIX, mSampleRate, AUDIO_FORMAT_PCM_16_BIT,
+            AUDIO_CHANNEL_IN_STEREO);
     ASSERT_NE(nullptr, capture);
     ASSERT_EQ(OK, capture->create()) << "record creation failed";
     sp<OnAudioDeviceUpdateNotifier> cbCapture = sp<OnAudioDeviceUpdateNotifier>::make();
@@ -103,7 +115,7 @@
 
     // create playback instance
     sp<AudioPlayback> playback = sp<AudioPlayback>::make(
-            48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            mSampleRate, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
             AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE);
     ASSERT_NE(nullptr, playback);
     ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
@@ -133,6 +145,12 @@
     playback->stop();
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        AudioTrackParameterizedTest,
+        AudioTrackTest,
+        ::testing::Values(44100, 48000)
+);
+
 class AudioRoutingTest : public ::testing::Test {
   public:
     void SetUp() override {
diff --git a/media/libaudioclient/tests/trackplayerbase_tests.cpp b/media/libaudioclient/tests/trackplayerbase_tests.cpp
index 7317bf0..a4dba9b 100644
--- a/media/libaudioclient/tests/trackplayerbase_tests.cpp
+++ b/media/libaudioclient/tests/trackplayerbase_tests.cpp
@@ -54,7 +54,7 @@
         mPlayer = new TrackPlayer();
         mPlayer->init(track.get(), mPlayer, PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA,
                       AUDIO_SESSION_NONE);
-        sp<AudioTrack> playerTrack = mPlayer->mAudioTrack;
+        sp<AudioTrack> playerTrack = mPlayer->getAudioTrack();
         ASSERT_EQ(playerTrack->initCheck(), NO_ERROR);
 
         mBufferSize = mFrameCount * playerTrack->frameSize();
@@ -74,7 +74,7 @@
 
     void playBuffer() {
         bool blocking = true;
-        ssize_t nbytes = mPlayer->mAudioTrack->write(mBuffer.data(), mBufferSize, blocking);
+        ssize_t nbytes = mPlayer->getAudioTrack()->write(mBuffer.data(), mBufferSize, blocking);
         EXPECT_EQ(nbytes, mBufferSize) << "Did not write all data in blocking mode";
     }
 
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 3cc923d..629cd7c 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -22,6 +22,7 @@
 #include <aidl/android/hardware/audio/core/BnStreamCallback.h>
 #include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
 #include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <android/binder_ibinder_platform.h>
 #include <error/expected_utils.h>
 #include <media/AidlConversionCppNdk.h>
 #include <media/AidlConversionNdk.h>
@@ -29,6 +30,8 @@
 #include <media/AidlConversionUtil.h>
 #include <mediautils/TimeCheck.h>
 #include <system/audio.h>
+#include <system/thread_defs.h>
+
 #include <Utils.h>
 #include <utils/Log.h>
 
@@ -504,8 +507,15 @@
     std::shared_ptr<OutputStreamCallbackAidl> streamCb;
     if (isOffload) {
         streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
+        ndk::SpAIBinder binder = streamCb->asBinder();
+        AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+        AIBinder_setInheritRt(binder.get(), true);
     }
     auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
+    ndk::SpAIBinder binder = eventCb->asBinder();
+    AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+    AIBinder_setInheritRt(binder.get(), true);
+
     if (isOffload || isHwAvSync) {
         args.offloadInfo = aidlConfig.offloadInfo;
     }
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 0a262e4..263ef96 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -619,7 +619,14 @@
             result != NO_ERROR) {
         return result;
     }
-    return processReturn("setConnectedState", mDevice->setConnectedState(hidlAddress, connected));
+    Return<Result> ret = mDevice->setConnectedState(hidlAddress, connected);
+    if (ret.isOk() || ret == Result::NOT_SUPPORTED) {
+        // The framework is only interested in errors occurring due to connection state handling,
+        // so it can decide whether retrying is needed. If the HAL does not support this operation,
+        // it's not an error.
+        return NO_ERROR;
+    }
+    return processReturn("setConnectedState", ret);
 }
 
 error::Result<audio_hw_sync_t> DeviceHalHidl::getHwAvSync() {
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index a13903b..f719d97 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -532,5 +532,13 @@
                            AudioChannelLayout::LAYOUT_HAPTIC_AB /* mask */);
 }
 
+size_t EffectConversionHelperAidl::getInputChannelCount() const {
+    return getChannelCount(mCommon.input.base.channelMask);
+}
+
+size_t EffectConversionHelperAidl::getOutputChannelCount() const {
+    return getChannelCount(mCommon.output.base.channelMask);
+}
+
 }  // namespace effect
 }  // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 50b47a9..e9e9fc2 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -51,6 +51,8 @@
 
     size_t getAudioChannelCount() const;
     size_t getHapticChannelCount() const;
+    size_t getInputChannelCount() const;
+    size_t getOutputChannelCount() const;
 
     uint8_t mOutputAccessMode = EFFECT_BUFFER_ACCESS_WRITE;
 
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index ea4dbf6..9fdde49 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -75,7 +75,14 @@
       mEffect(effect),
       mSessionId(sessionId),
       mIoId(ioId),
-      mIsProxyEffect(isProxyEffect) {
+      mIsProxyEffect(isProxyEffect),
+      mHalVersion([factory]() {
+          int version = 0;
+          // use factory HAL version because effect can be an EffectProxy instance
+          return factory->getInterfaceVersion(&version).isOk() ? version : 0;
+      }()),
+      mEventFlagDataMqNotEmpty(mHalVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
+                                                                      : kEventFlagNotEmpty) {
     assert(mFactory != nullptr);
     assert(mEffect != nullptr);
     createAidlConversion(effect, sessionId, ioId, desc);
@@ -159,6 +166,7 @@
         mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
                 effect, sessionId, ioId, desc, mIsProxyEffect);
     }
+    mEffectName = mConversion->getDescriptor().common.name;
     return OK;
 }
 
@@ -174,100 +182,153 @@
 
 // write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
 status_t EffectHalAidl::process() {
-    const std::string effectName = mConversion->getDescriptor().common.name;
     State state = State::INIT;
     if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
         state != State::PROCESSING) {
-        ALOGI("%s skipping %s process because it's %s", __func__, effectName.c_str(),
+        ALOGI("%s skipping process because it's %s", mEffectName.c_str(),
               mConversion->isBypassing()
                       ? "bypassing"
                       : aidl::android::hardware::audio::effect::toString(state).c_str());
         return -ENODATA;
     }
 
-    // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
-    auto efGroup = mConversion->getEventFlagGroup();
+    const std::shared_ptr<android::hardware::EventFlag> efGroup = mConversion->getEventFlagGroup();
     if (!efGroup) {
-        ALOGE("%s invalid efGroup", __func__);
+        ALOGE("%s invalid efGroup", mEffectName.c_str());
         return INVALID_OPERATION;
     }
 
-    // use IFactory HAL version because IEffect can be an EffectProxy instance
-    static const int halVersion = [&]() {
-        int version = 0;
-        return mFactory->getInterfaceVersion(&version).isOk() ? version : 0;
-    }();
+    // reopen if halVersion >= kReopenSupportedVersion and receive kEventFlagDataMqUpdate
+    RETURN_STATUS_IF_ERROR(maybeReopen(efGroup));
+    const size_t samplesWritten = writeToHalInputFmqAndSignal(efGroup);
+    if (0 == samplesWritten) {
+        return INVALID_OPERATION;
+    }
 
-    if (uint32_t efState = 0; halVersion >= kReopenSupportedVersion &&
-                              ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
+    RETURN_STATUS_IF_ERROR(waitHalStatusFmq(samplesWritten));
+    RETURN_STATUS_IF_ERROR(readFromHalOutputFmq(samplesWritten));
+    return OK;
+}
+
+status_t EffectHalAidl::maybeReopen(
+        const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
+    if (mHalVersion < kReopenSupportedVersion) {
+        return OK;
+    }
+
+    // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
+    if (uint32_t efState = 0; ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
                                                              1 /* ns */, true /* retry */) &&
                               efState & kEventFlagDataMqUpdate) {
-        ALOGD("%s %s V%d receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str(),
-              halVersion);
-
-        mConversion->reopen();
+        ALOGD("%s V%d receive dataMQUpdate eventFlag from HAL", mEffectName.c_str(), mHalVersion);
+        return mConversion->reopen();
     }
-    auto statusQ = mConversion->getStatusMQ();
-    auto inputQ = mConversion->getInputMQ();
-    auto outputQ = mConversion->getOutputMQ();
-    if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
-        !outputQ->isValid()) {
-        ALOGE("%s invalid FMQ [Status %d I %d O %d]", __func__, statusQ ? statusQ->isValid() : 0,
-              inputQ ? inputQ->isValid() : 0, outputQ ? outputQ->isValid() : 0);
-        return INVALID_OPERATION;
+    return OK;
+}
+
+size_t EffectHalAidl::writeToHalInputFmqAndSignal(
+        const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
+    const auto inputQ = mConversion->getInputMQ();
+    if (!inputQ || !inputQ->isValid()) {
+        ALOGE("%s invalid input FMQ", mEffectName.c_str());
+        return 0;
     }
 
-    size_t available = inputQ->availableToWrite();
-    const size_t floatsToWrite = std::min(available, mInBuffer->getSize() / sizeof(float));
-    if (floatsToWrite == 0) {
-        ALOGE("%s not able to write, floats in buffer %zu, space in FMQ %zu", __func__,
-              mInBuffer->getSize() / sizeof(float), available);
-        return INVALID_OPERATION;
-    }
-    if (!mInBuffer->audioBuffer() ||
-        !inputQ->write((float*)mInBuffer->audioBuffer()->f32, floatsToWrite)) {
-        ALOGE("%s failed to write %zu floats from audiobuffer %p to inputQ [avail %zu]", __func__,
-              floatsToWrite, mInBuffer->audioBuffer(), inputQ->availableToWrite());
-        return INVALID_OPERATION;
+    const size_t fmqSpaceSamples = inputQ->availableToWrite();
+    const size_t samplesInBuffer =
+            mInBuffer->audioBuffer()->frameCount * mConversion->getInputChannelCount();
+    const size_t samplesToWrite = std::min(fmqSpaceSamples, samplesInBuffer);
+    if (samplesToWrite == 0) {
+        ALOGE("%s not able to write, samplesInBuffer %zu, fmqSpaceSamples %zu", mEffectName.c_str(),
+              samplesInBuffer, fmqSpaceSamples);
+        return 0;
     }
 
-    // for V2 audio effect HAL, expect different EventFlag to avoid bit conflict with FMQ_NOT_EMPTY
-    efGroup->wake(halVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
-                                                        : kEventFlagNotEmpty);
+    const float* const inputRawBuffer = static_cast<const float*>(mInBuffer->audioBuffer()->f32);
+    if (!inputQ->write(inputRawBuffer, samplesToWrite)) {
+        ALOGE("%s failed to write %zu samples to inputQ [avail %zu]", mEffectName.c_str(),
+              samplesToWrite, inputQ->availableToWrite());
+        return 0;
+    }
+
+    efGroup->wake(mEventFlagDataMqNotEmpty);
+    return samplesToWrite;
+}
+
+void EffectHalAidl::writeHapticGeneratorData(size_t totalSamples, float* const outputRawBuffer,
+                                             float* const fmqOutputBuffer) const {
+    const auto audioChNum = mConversion->getAudioChannelCount();
+    const auto audioSamples =
+            totalSamples * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
+
+    static constexpr float kHalFloatSampleLimit = 2.0f;
+    // for HapticGenerator, the input data buffer will be updated
+    float* const inputRawBuffer = static_cast<float*>(mInBuffer->audioBuffer()->f32);
+    // accumulate or copy input to output, haptic samples remains all zero
+    if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+        accumulate_float(outputRawBuffer, inputRawBuffer, audioSamples);
+    } else {
+        memcpy_to_float_from_float_with_clamping(outputRawBuffer, inputRawBuffer, audioSamples,
+                                                 kHalFloatSampleLimit);
+    }
+    // append the haptic sample at the end of input audio samples
+    memcpy_to_float_from_float_with_clamping(inputRawBuffer + audioSamples,
+                                             fmqOutputBuffer + audioSamples,
+                                             totalSamples - audioSamples, kHalFloatSampleLimit);
+}
+
+status_t EffectHalAidl::waitHalStatusFmq(size_t samplesWritten) const {
+    const auto statusQ = mConversion->getStatusMQ();
+    if (const bool statusValid = statusQ && statusQ->isValid(); !statusValid) {
+        ALOGE("%s statusFMQ %s", mEffectName.c_str(), statusValid ? "valid" : "invalid");
+        return INVALID_OPERATION;
+    }
 
     IEffect::Status retStatus{};
     if (!statusQ->readBlocking(&retStatus, 1)) {
-        ALOGE("%s %s V%d read status from status FMQ failed", __func__, effectName.c_str(),
-              halVersion);
+        ALOGE("%s V%d read status from status FMQ failed", mEffectName.c_str(), mHalVersion);
         return INVALID_OPERATION;
     }
-    if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != floatsToWrite ||
+    if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != samplesWritten ||
         retStatus.fmqProduced == 0) {
-        ALOGE("%s read status failed: %s, consumed %d (of %zu) produced %d", __func__,
-              retStatus.toString().c_str(), retStatus.fmqConsumed, floatsToWrite,
-              retStatus.fmqProduced);
+        ALOGE("%s read status failed: %s, FMQ consumed %d (of %zu) produced %d",
+              mEffectName.c_str(), retStatus.toString().c_str(), retStatus.fmqConsumed,
+              samplesWritten, retStatus.fmqProduced);
         return INVALID_OPERATION;
     }
 
-    available = outputQ->availableToRead();
-    const size_t floatsToRead = std::min(available, mOutBuffer->getSize() / sizeof(float));
-    if (floatsToRead == 0) {
-        ALOGE("%s not able to read, buffer space %zu, floats in FMQ %zu", __func__,
-              mOutBuffer->getSize() / sizeof(float), available);
+    return OK;
+}
+
+status_t EffectHalAidl::readFromHalOutputFmq(size_t samplesWritten) const {
+    const auto outputQ = mConversion->getOutputMQ();
+    if (const bool outputValid = outputQ && outputQ->isValid(); !outputValid) {
+        ALOGE("%s outputFMQ %s", mEffectName.c_str(), outputValid ? "valid" : "invalid");
         return INVALID_OPERATION;
     }
 
-    float *outputRawBuffer = mOutBuffer->audioBuffer()->f32;
+    const size_t fmqProducedSamples = outputQ->availableToRead();
+    const size_t bufferSpaceSamples =
+            mOutBuffer->audioBuffer()->frameCount * mConversion->getOutputChannelCount();
+    const size_t samplesToRead = std::min(fmqProducedSamples, bufferSpaceSamples);
+    if (samplesToRead == 0) {
+        ALOGE("%s unable to read, bufferSpace %zu, fmqProduced %zu samplesWritten %zu",
+              mEffectName.c_str(), bufferSpaceSamples, fmqProducedSamples, samplesWritten);
+        return INVALID_OPERATION;
+    }
+
+    float* const outputRawBuffer = static_cast<float*>(mOutBuffer->audioBuffer()->f32);
+    float* fmqOutputBuffer = outputRawBuffer;
     std::vector<float> tempBuffer;
     // keep original data in the output buffer for accumulate mode or HapticGenerator effect
     if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE || mIsHapticGenerator) {
-        tempBuffer.resize(floatsToRead);
-        outputRawBuffer = tempBuffer.data();
+        tempBuffer.resize(samplesToRead, 0);
+        fmqOutputBuffer = tempBuffer.data();
     }
     // always read floating point data for AIDL
-    if (!outputQ->read(outputRawBuffer, floatsToRead)) {
-        ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", __func__, floatsToRead,
-              mOutBuffer->audioBuffer());
+    if (!outputQ->read(fmqOutputBuffer, samplesToRead)) {
+        ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", mEffectName.c_str(),
+              samplesToRead, fmqOutputBuffer);
         return INVALID_OPERATION;
     }
 
@@ -276,26 +337,10 @@
     // offset as input buffer, here we skip the audio samples in output FMQ and append haptic
     // samples to the end of input buffer
     if (mIsHapticGenerator) {
-        static constexpr float kHalFloatSampleLimit = 2.0f;
-        assert(floatsToRead == floatsToWrite);
-        const auto audioChNum = mConversion->getAudioChannelCount();
-        const auto audioSamples =
-                floatsToWrite * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
-        // accumulate or copy input to output, haptic samples remains all zero
-        if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
-            accumulate_float(mOutBuffer->audioBuffer()->f32, mInBuffer->audioBuffer()->f32,
-                             audioSamples);
-        } else {
-            memcpy_to_float_from_float_with_clamping(mOutBuffer->audioBuffer()->f32,
-                                                     mInBuffer->audioBuffer()->f32, audioSamples,
-                                                     kHalFloatSampleLimit);
-        }
-        // append the haptic sample at the end of input audio samples
-        memcpy_to_float_from_float_with_clamping(mInBuffer->audioBuffer()->f32 + audioSamples,
-                                                 outputRawBuffer + audioSamples,
-                                                 floatsToRead - audioSamples, kHalFloatSampleLimit);
+        assert(samplesRead == samplesWritten);
+        writeHapticGeneratorData(samplesToRead, outputRawBuffer, fmqOutputBuffer);
     } else if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
-        accumulate_float(mOutBuffer->audioBuffer()->f32, outputRawBuffer, floatsToRead);
+        accumulate_float(outputRawBuffer, fmqOutputBuffer, samplesToRead);
     }
 
     return OK;
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
index 4f7de7c..a775337 100644
--- a/media/libaudiohal/impl/EffectHalAidl.h
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -73,7 +73,12 @@
     const int32_t mSessionId;
     const int32_t mIoId;
     const bool mIsProxyEffect;
+    const int32_t mHalVersion;
+    // Audio effect HAL v2+ changes flag to kEventFlagDataMqNotEmpty to avoid conflict from using
+    // kEventFlagNotEmpty
+    const uint32_t mEventFlagDataMqNotEmpty;
     bool mIsHapticGenerator = false;
+    std::string mEffectName;
 
     std::unique_ptr<EffectConversionHelperAidl> mConversion;
 
@@ -93,6 +98,14 @@
     bool setEffectReverse(bool reverse);
     bool needUpdateReturnParam(uint32_t cmdCode);
 
+    status_t maybeReopen(const std::shared_ptr<android::hardware::EventFlag>& efGroup) const;
+    void writeHapticGeneratorData(size_t totalSamples, float* const outputRawBuffer,
+                                  float* const fmqOutputBuffer) const;
+    size_t writeToHalInputFmqAndSignal(
+            const std::shared_ptr<android::hardware::EventFlag>& efGroup) const;
+    status_t waitHalStatusFmq(size_t samplesWritten) const;
+    status_t readFromHalOutputFmq(size_t samplesWritten) const;
+
     // The destructor automatically releases the effect.
     virtual ~EffectHalAidl();
 };
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index f352849..0cdf0f2 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -368,16 +368,21 @@
         const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
         AudioSource source, const std::set<int32_t>& destinationPortIds,
         AudioPortConfig* portConfig, bool* created) {
-    // These flags get removed one by one in this order when retrying port finding.
-    static const std::vector<AudioInputFlags> kOptionalInputFlags{
-        AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
     if (auto portConfigIt = findPortConfig(config, flags, ioHandle);
             portConfigIt == mPortConfigs.end() && flags.has_value()) {
-        auto optionalInputFlagsIt = kOptionalInputFlags.begin();
+        // These input flags get removed one by one in this order when retrying port finding.
+        std::vector<AudioInputFlags> optionalInputFlags {
+            AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
+        // For remote submix input, retry with direct input flag removed as the remote submix
+        // input is not expected to manipulate the contents of the audio stream.
+        if (mRemoteSubmixIn.has_value()) {
+            optionalInputFlags.push_back(AudioInputFlags::DIRECT);
+        }
+        auto optionalInputFlagsIt = optionalInputFlags.begin();
         AudioIoFlags matchFlags = flags.value();
         auto portsIt = findPort(config, matchFlags, destinationPortIds);
         while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
-                && optionalInputFlagsIt != kOptionalInputFlags.end()) {
+                && optionalInputFlagsIt != optionalInputFlags.end()) {
             if (!isBitPositionFlagSet(
                             matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
                 ++optionalInputFlagsIt;
@@ -392,6 +397,36 @@
                         config.toString().c_str(), flags.value().toString().c_str(),
                         matchFlags.toString().c_str());
         }
+        // These output flags get removed one by one in this order when retrying port finding.
+        std::vector<AudioOutputFlags> optionalOutputFlags { };
+        // For remote submix output, retry with these output flags removed one by one:
+        // 1. DIRECT: remote submix outputs are expected not to manipulate the contents of the
+        //            audio stream.
+        // 2. IEC958_NONAUDIO: remote submix outputs are not connected to ALSA and do not require
+        //                     non audio signalling.
+        if (mRemoteSubmixOut.has_value()) {
+            optionalOutputFlags.push_back(AudioOutputFlags::DIRECT);
+            optionalOutputFlags.push_back(AudioOutputFlags::IEC958_NONAUDIO);
+        }
+        auto optionalOutputFlagsIt = optionalOutputFlags.begin();
+        matchFlags = flags.value();
+        while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::output
+                && optionalOutputFlagsIt != optionalOutputFlags.end()) {
+            if (!isBitPositionFlagSet(
+                            matchFlags.get<AudioIoFlags::Tag::output>(),*optionalOutputFlagsIt)) {
+                ++optionalOutputFlagsIt;
+                continue;
+            }
+            matchFlags.set<AudioIoFlags::Tag::output>(matchFlags.get<AudioIoFlags::Tag::output>() &
+                    ~makeBitPositionFlagMask(*optionalOutputFlagsIt++));
+            portsIt = findPort(config, matchFlags, destinationPortIds);
+            AUGMENT_LOG(I,
+                        "mix port for config %s, flags %s was not found"
+                        "retried with flags %s",
+                        config.toString().c_str(), flags.value().toString().c_str(),
+                        matchFlags.toString().c_str());
+        }
+
         if (portsIt == mPorts.end()) {
             AUGMENT_LOG(E, "mix port for config %s, flags %s is not found",
                         config.toString().c_str(), matchFlags.toString().c_str());
@@ -792,7 +827,8 @@
     status_t status = prepareToOpenStreamHelper(ioHandle, devicePortConfig.portId,
             devicePortConfig.id, flags, source, initialConfig, cleanups, config,
             mixPortConfig, patch);
-    if (status != OK) {
+    if (status != OK && !(mRemoteSubmixOut.has_value() &&
+                initialConfig.base.format.type != AudioFormatType::PCM)) {
         // If using the client-provided config did not work out for establishing a mix port config
         // or patching, try with the device port config. Note that in general device port config and
         // mix port config are not required to be the same, however they must match if the HAL
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 63be1bc..9863fec 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -59,6 +59,16 @@
 template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
     return HalCommand::make<cmd>(data);
 }
+
+template <typename MQTypeError>
+auto fmqErrorHandler(const char* mqName) {
+    return [m = std::string(mqName)](MQTypeError fmqError, std::string&& errorMessage) {
+        mediautils::TimeCheck::signalAudioHals();
+        LOG_ALWAYS_FATAL_IF(fmqError != MQTypeError::NONE, "%s: %s",
+                m.c_str(), errorMessage.c_str());
+    };
+}
+
 }  // namespace
 
 // static
@@ -103,6 +113,17 @@
             StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
         mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
     }
+
+    if (mStream != nullptr) {
+        mContext.getCommandMQ()->setErrorHandler(
+                fmqErrorHandler<StreamContextAidl::CommandMQ::Error>("CommandMQ"));
+        mContext.getReplyMQ()->setErrorHandler(
+                fmqErrorHandler<StreamContextAidl::ReplyMQ::Error>("ReplyMQ"));
+        if (mContext.getDataMQ() != nullptr) {
+            mContext.getDataMQ()->setErrorHandler(
+                    fmqErrorHandler<StreamContextAidl::DataMQ::Error>("DataMQ"));
+        }
+    }
 }
 
 StreamHalAidl::~StreamHalAidl() {
@@ -388,11 +409,8 @@
             return INVALID_OPERATION;
         }
     }
-    StreamContextAidl::DataMQ::Error fmqError = StreamContextAidl::DataMQ::Error::NONE;
-    std::string fmqErrorMsg;
     if (!mIsInput) {
-        bytes = std::min(bytes,
-                mContext.getDataMQ()->availableToWrite(&fmqError, &fmqErrorMsg));
+        bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
     }
     StreamDescriptor::Command burst =
             StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
@@ -409,14 +427,12 @@
         LOG_ALWAYS_FATAL_IF(*transferred > bytes,
                 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
                 __func__, *transferred, bytes);
-        if (auto toRead = mContext.getDataMQ()->availableToRead(&fmqError, &fmqErrorMsg);
+        if (auto toRead = mContext.getDataMQ()->availableToRead();
                 toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
             AUGMENT_LOG(E, "failed to read %zu bytes to data MQ", toRead);
             return NOT_ENOUGH_DATA;
         }
     }
-    LOG_ALWAYS_FATAL_IF(fmqError != StreamContextAidl::DataMQ::Error::NONE,
-            "%s", fmqErrorMsg.c_str());
     mStreamPowerLog.log(buffer, *transferred);
     return OK;
 }
@@ -427,9 +443,29 @@
     if (!mStream) return NO_INIT;
 
     if (const auto state = getState(); isInPlayOrRecordState(state)) {
-        return sendCommand(
-                makeHalCommand<HalCommand::Tag::pause>(), reply,
+        StreamDescriptor::Reply localReply{};
+        StreamDescriptor::Reply* innerReply = reply ?: &localReply;
+        auto status = sendCommand(
+                makeHalCommand<HalCommand::Tag::pause>(), innerReply,
                 true /*safeFromNonWorkerThread*/);  // The workers stops its I/O activity first.
+        if (status == STATUS_INVALID_OPERATION &&
+                !isInPlayOrRecordState(innerReply->state)) {
+            /**
+             * In case of transient states like DRAINING, the HAL may change its
+             * StreamDescriptor::State on its own and may not be in synchronization with client.
+             * Thus, client can send the unexpected command and HAL returns failure. such failure is
+             * natural. The client handles it gracefully.
+             * Example where HAL change its state,
+             * 1) DRAINING -> IDLE (on empty buffer)
+             * 2) DRAINING -> IDLE (on IStreamCallback::onDrainReady)
+             **/
+            AUGMENT_LOG(D,
+                        "HAL failed to handle the 'pause' command, but stream state is in one of"
+                        " the PAUSED kind of states, current state: %s",
+                        toString(state).c_str());
+            return OK;
+        }
+        return status;
     } else {
         AUGMENT_LOG(D, "already stream in one of the PAUSED kind of states, current state: %s",
                 toString(state).c_str());
@@ -457,13 +493,9 @@
                 return INVALID_OPERATION;
             }
             return OK;
-        } else if (state == StreamDescriptor::State::PAUSED ||
-                   state == StreamDescriptor::State::TRANSFER_PAUSED ||
-                   state == StreamDescriptor::State::DRAIN_PAUSED) {
+        } else if (isInPausedState(state)) {
             return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
-        } else if (state == StreamDescriptor::State::ACTIVE ||
-                   state == StreamDescriptor::State::TRANSFERRING ||
-                   state == StreamDescriptor::State::DRAINING) {
+        } else if (isInPlayOrRecordState(state)) {
             AUGMENT_LOG(D, "already in stream state: %s", toString(state).c_str());
             return OK;
         } else {
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index ab6a8b6..8f60d29 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -347,6 +347,7 @@
         [6] = AUDIO_CHANNEL_OUT_5POINT1,
         [7] = AUDIO_CHANNEL_OUT_6POINT1,
         [8] = AUDIO_CHANNEL_OUT_7POINT1,
+        [10] = AUDIO_CHANNEL_OUT_5POINT1POINT4,
         [12] = AUDIO_CHANNEL_OUT_7POINT1POINT4,
         [14] = AUDIO_CHANNEL_OUT_9POINT1POINT4,
         [16] = AUDIO_CHANNEL_OUT_9POINT1POINT6,
diff --git a/media/libaudioprocessing/tests/mixerops_tests.cpp b/media/libaudioprocessing/tests/mixerops_tests.cpp
index 2500ba9..235129f 100644
--- a/media/libaudioprocessing/tests/mixerops_tests.cpp
+++ b/media/libaudioprocessing/tests/mixerops_tests.cpp
@@ -154,6 +154,9 @@
 TEST(mixerops, stereovolume_8) {
     MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 8>::testStereoVolume();
 }
+TEST(mixerops, stereovolume_10) {
+    MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 10>::testStereoVolume();
+}
 TEST(mixerops, stereovolume_12) {
     if constexpr (FCC_LIMIT >= 12) { // NOTE: FCC_LIMIT is an enum, so can't #if
         MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 12>::testStereoVolume();
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
index 55e07fb..dd29e86 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
@@ -55,6 +55,17 @@
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::vector<Range::HapticGeneratorRange> kHapticRange = {
+        MAKE_RANGE(HapticGenerator, vibratorInfo,
+                   HapticGenerator::VibratorInformation(
+                           {.resonantFrequencyHz = 1, .qFactor = 1, .maxAmplitude = -1}),
+                   HapticGenerator::VibratorInformation(
+                           {.resonantFrequencyHz = std::numeric_limits<float>::max(),
+                            .qFactor = std::numeric_limits<float>::max(),
+                            .maxAmplitude = 1}))};
+
+static const Capability kHapticCap = {.range = kHapticRange};
+
 const std::string HapticGeneratorImpl::kEffectName = "Haptic Generator";
 const Descriptor HapticGeneratorImpl::kDescriptor = {
         .common = {.id = {.type = getEffectTypeUuidHapticGenerator(),
@@ -62,7 +73,8 @@
                           .proxy = std::nullopt},
                    .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST},
                    .name = HapticGeneratorImpl::kEffectName,
-                   .implementor = "The Android Open Source Project"}};
+                   .implementor = "The Android Open Source Project"},
+        .capability = kHapticCap};
 
 ndk::ScopedAStatus HapticGeneratorImpl::getDescriptor(Descriptor* _aidl_return) {
     RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
@@ -76,6 +88,8 @@
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+    RETURN_IF(!inRange(hgParam, kHapticRange), EX_ILLEGAL_ARGUMENT, "outOfRange");
+
     auto tag = hgParam.getTag();
 
     switch (tag) {
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
index 535b886..d8f9093 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -353,7 +353,7 @@
 
 std::string HapticGeneratorContext::paramToString(const struct HapticGeneratorParam& param) const {
     std::stringstream ss;
-    ss << "\t\ttHapticGenerator Parameters:\n";
+    ss << "\t\tHapticGenerator Parameters:\n";
     ss << "\t\t- mHapticChannelCount: " << param.mHapticChannelCount << '\n';
     ss << "\t\t- mAudioChannelCount: " << param.mAudioChannelCount << '\n';
     ss << "\t\t- mHapticChannelSource: " << param.mHapticChannelSource[0] << ", "
@@ -378,7 +378,7 @@
     ss << "\t\t- distortion input gain: " << DEFAULT_DISTORTION_INPUT_GAIN << '\n';
     ss << "\t\t- distortion cube threshold: " << DEFAULT_DISTORTION_CUBE_THRESHOLD << '\n';
     ss << "\t\t- distortion output gain: " << getDistortionOutputGain() << '\n';
-    ss << "\t\tHapticGenerator Parameters:\n" << paramToString(mParams) << "\n";
+    ss << paramToString(mParams) << "\n";
     return ss.str();
 }
 
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index d5e3cf7..53d4311 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -90,6 +90,12 @@
     }
 }
 
+RetCode BundleContext::setCommon(const Parameter::Common& common) {
+    RetCode ret = EffectContext::setCommon(common);
+    RETURN_VALUE_IF(ret != RetCode::SUCCESS, ret, " setCommonFailed");
+    return init();
+}
+
 RetCode BundleContext::enable() {
     if (mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER;
     // Bass boost or Virtualizer can be temporarily disabled if playing over device speaker due to
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index e5ab40d..d5de5bd 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -35,6 +35,8 @@
     void deInit();
     lvm::BundleEffectType getBundleType() const { return mType; }
 
+    RetCode setCommon(const Parameter::Common& common) override;
+
     RetCode enable() override;
     RetCode enableOperatingMode();
     RetCode disable() override;
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 116ed9a..d76ed25 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -122,6 +122,10 @@
     static sp<IMediaPlayerService>            sService;
 
     Mutex                                     mLock;
+    // Static lock was added to the client in order to consume at most
+    // one service thread from image extraction requests of the same
+    // client process(See also b/21277449).
+    static Mutex                              sLock;
     sp<IMediaMetadataRetriever>               mRetriever;
 
 };
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 40fd022..9196f9f 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -35,6 +35,8 @@
 sp<IMediaPlayerService> MediaMetadataRetriever::sService;
 sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
 
+Mutex MediaMetadataRetriever::sLock;
+
 const sp<IMediaPlayerService> MediaMetadataRetriever::getService()
 {
     Mutex::Autolock lock(sServiceLock);
@@ -143,6 +145,7 @@
     ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d) colorFormat(%d) metaOnly(%d)",
             timeUs, option, colorFormat, metaOnly);
     Mutex::Autolock _l(mLock);
+    Mutex::Autolock _gLock(sLock);
     if (mRetriever == 0) {
         ALOGE("retriever is not initialized");
         return NULL;
@@ -155,6 +158,7 @@
     ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
             index, colorFormat, metaOnly, thumbnail);
     Mutex::Autolock _l(mLock);
+    Mutex::Autolock _gLock(sLock);
     if (mRetriever == 0) {
         ALOGE("retriever is not initialized");
         return NULL;
@@ -167,6 +171,7 @@
     ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
             index, colorFormat, left, top, right, bottom);
     Mutex::Autolock _l(mLock);
+    Mutex::Autolock _gLock(sLock);
     if (mRetriever == 0) {
         ALOGE("retriever is not initialized");
         return NULL;
@@ -180,6 +185,7 @@
     ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
             index, colorFormat, metaOnly);
     Mutex::Autolock _l(mLock);
+    Mutex::Autolock _gLock(sLock);
     if (mRetriever == 0) {
         ALOGE("retriever is not initialized");
         return NULL;
diff --git a/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp b/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
index cc60933..f0db018 100644
--- a/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
+++ b/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
@@ -50,7 +50,7 @@
 
     // We write a length greater than the following session id array. Should be discarded.
     data.writeUint32(2);
-    data.writeUnpadded(kMockByteArray, 1);
+    data.write(kMockByteArray, 1);
 
     status_t result = IMediaPlayer::asBinder(iMediaPlayer_)
             ->transact(PREPARE_DRM, data, &reply);
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index ecb248d..2c58461 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -334,21 +334,21 @@
 
     // This is checked only once in the lifetime of the process.
     const uid_t uid = getuid();
-    switch (uid) {
-    case AID_RADIO:     // telephony subsystem, RIL
+    const uid_t appid = multiuser_get_app_id(uid);
+
+    if (appid == AID_RADIO) {
+        // telephony subsystem, RIL
         return false;
-    default:
+    }
+
+    if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
         // Some isolated processes can access the audio system; see
         // AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead
         // of also allowing access to the MediaMetrics service, it's simpler to just disable it for
         // now.
         // TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or
         // make this disabling specific to that process.
-        uid_t appid = multiuser_get_app_id(uid);
-        if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
-            return false;
-        }
-        break;
+        return false;
     }
 
     int enabled = property_get_int32(Item::EnabledProperty, -1);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 718f782..a10c509 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -45,6 +45,7 @@
         "android.hardware.media.omx@1.0",
         "av-types-aidl-cpp",
         "framework-permission-aidl-cpp",
+        "libaconfig_storage_read_api_cc",
         "libaudioclient_aidl_conversion",
         "libbase",
         "libbinder_ndk",
@@ -76,6 +77,7 @@
         "libstagefright_httplive",
         "libutils",
         "packagemanager_aidl-cpp",
+        "server_configurable_flags",
     ],
 
     header_libs: [
@@ -86,6 +88,7 @@
     ],
 
     static_libs: [
+        "com.android.media.flags.editing-aconfig-cc",
         "libplayerservice_datasource",
         "libstagefright_nuplayer",
         "libstagefright_rtsp",
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index dce6ba8..086baa3 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -68,6 +68,7 @@
 #include <system/audio.h>
 
 #include <media/stagefright/rtsp/ARTPWriter.h>
+#include <com_android_media_editing_flags.h>
 
 namespace android {
 
@@ -2121,7 +2122,8 @@
         uint32_t bLayers = std::min(2u, tsLayers - 1); // use up-to 2 B-layers
         // TODO(b/341121900): Remove this once B frames are handled correctly in screen recorder
         // use case in case of mic only
-        if (mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) {
+        if (!com::android::media::editing::flags::stagefrightrecorder_enable_b_frames()
+                && mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) {
             bLayers = 0;
         }
         uint32_t pLayers = tsLayers - bLayers;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index f4143da..3987a67 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -43,6 +43,12 @@
 #include <mpeg2ts/ATSParser.h>
 #include <gui/Surface.h>
 
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
 namespace android {
 
 static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
@@ -157,7 +163,10 @@
                     int32_t index;
                     CHECK(msg->findInt32("index", &index));
 
+                    ATRACE_BEGIN(StringPrintf("Nuplayer::handleAnInputBuffer [%s]",
+                                              mIsAudio ? "audio" : "video").c_str());
                     handleAnInputBuffer(index);
+                    ATRACE_END();
                     break;
                 }
 
@@ -175,7 +184,10 @@
                     CHECK(msg->findInt64("timeUs", &timeUs));
                     CHECK(msg->findInt32("flags", &flags));
 
+                    ATRACE_BEGIN(StringPrintf("Nuplayer::handleAnOutputBuffer [%s]",
+                                              mIsAudio ? "audio" : "video").c_str());
                     handleAnOutputBuffer(index, offset, size, timeUs, flags);
+                    ATRACE_END();
                     break;
                 }
 
@@ -184,7 +196,10 @@
                     sp<AMessage> format;
                     CHECK(msg->findMessage("format", &format));
 
+                    ATRACE_BEGIN(StringPrintf("Nuplayer::handleOutputFormatChange [%s]",
+                                              mIsAudio ? "audio" : "video").c_str());
                     handleOutputFormatChange(format);
+                    ATRACE_END();
                     break;
                 }
 
@@ -205,15 +220,16 @@
                     break;
                 }
             }
-
             break;
         }
 
         case kWhatRenderBuffer:
         {
+            ATRACE_BEGIN("Nuplayer::onRenderBuffer");
             if (!isStaleReply(msg)) {
                 onRenderBuffer(msg);
             }
+            ATRACE_END();
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 3e96d27..0cb5062 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -27,6 +27,12 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
 namespace android {
 
 NuPlayer::DecoderBase::DecoderBase(const sp<AMessage> &notify)
@@ -129,9 +135,11 @@
     switch (msg->what()) {
         case kWhatConfigure:
         {
+            ATRACE_BEGIN("NuPlayer::DecoderBase::onConfigure");
             sp<AMessage> format;
             CHECK(msg->findMessage("format", &format));
             onConfigure(format);
+            ATRACE_END();
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index c6595ba..851d252 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -36,6 +36,11 @@
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/FoundationUtils.h>
 
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleepUs = 20000;
 
@@ -146,9 +151,11 @@
         const char *url,
         const KeyedVector<String8, String8> *headers) {
     ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
+    ATRACE_BEGIN(StringPrintf("setDataSource(%p)", this).c_str());
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
+        ATRACE_END();
         return INVALID_OPERATION;
     }
 
@@ -159,15 +166,18 @@
     while (mState == STATE_SET_DATASOURCE_PENDING) {
         mCondition.wait(mLock);
     }
+    ATRACE_END();
 
     return mAsyncResult;
 }
 
 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
     ALOGV("setDataSource(%p) file(%d)", this, fd);
+    ATRACE_BEGIN(StringPrintf("setDataSource(%p) file(%d)", this, fd).c_str());
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
+        ATRACE_END();
         return INVALID_OPERATION;
     }
 
@@ -178,15 +188,18 @@
     while (mState == STATE_SET_DATASOURCE_PENDING) {
         mCondition.wait(mLock);
     }
+    ATRACE_END();
 
     return mAsyncResult;
 }
 
 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
     ALOGV("setDataSource(%p) stream source", this);
+    ATRACE_BEGIN(StringPrintf("setDataSource(%p) stream source", this).c_str());
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
+        ATRACE_END();
         return INVALID_OPERATION;
     }
 
@@ -197,15 +210,18 @@
     while (mState == STATE_SET_DATASOURCE_PENDING) {
         mCondition.wait(mLock);
     }
+    ATRACE_END();
 
     return mAsyncResult;
 }
 
 status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) {
     ALOGV("setDataSource(%p) callback source", this);
+    ATRACE_BEGIN(StringPrintf("setDataSource(%p) callback source", this).c_str());
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
+        ATRACE_END();
         return INVALID_OPERATION;
     }
 
@@ -216,15 +232,18 @@
     while (mState == STATE_SET_DATASOURCE_PENDING) {
         mCondition.wait(mLock);
     }
+    ATRACE_END();
 
     return mAsyncResult;
 }
 
 status_t NuPlayerDriver::setDataSource(const String8& rtpParams) {
     ALOGV("setDataSource(%p) rtp source", this);
+    ATRACE_BEGIN(StringPrintf("setDataSource(%p) rtp source", this).c_str());
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
+        ATRACE_END();
         return INVALID_OPERATION;
     }
 
@@ -235,6 +254,7 @@
     while (mState == STATE_SET_DATASOURCE_PENDING) {
         mCondition.wait(mLock);
     }
+    ATRACE_END();
 
     return mAsyncResult;
 }
@@ -295,8 +315,11 @@
 
 status_t NuPlayerDriver::prepare() {
     ALOGV("prepare(%p)", this);
+    ATRACE_BEGIN(StringPrintf("prepare(%p)", this).c_str());
     Mutex::Autolock autoLock(mLock);
-    return prepare_l();
+    status_t ret = prepare_l();
+    ATRACE_END();
+    return ret;
 }
 
 status_t NuPlayerDriver::prepare_l() {
@@ -354,8 +377,11 @@
 
 status_t NuPlayerDriver::start() {
     ALOGV("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
+    ATRACE_BEGIN(StringPrintf("start(%p), state is %d, eos is %d", this, mState, mAtEOS).c_str());
     Mutex::Autolock autoLock(mLock);
-    return start_l();
+    status_t ret = start_l();
+    ATRACE_END();
+    return ret;
 }
 
 status_t NuPlayerDriver::start_l() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 3c8b809..899d50e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -15,6 +15,7 @@
  */
 
 //#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
 #define LOG_TAG "NuPlayerRenderer"
 #include <utils/Log.h>
 
@@ -37,6 +38,9 @@
 
 #include <inttypes.h>
 
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
 namespace android {
 
 /*
@@ -2000,6 +2004,8 @@
         bool isStreaming) {
     ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
             offloadOnly, offloadingAudio());
+    ATRACE_BEGIN(StringPrintf("NuPlayer::Renderer::onOpenAudioSink: offloadOnly(%d) "
+            "offloadingAudio(%d)", offloadOnly, offloadingAudio()).c_str());
     bool audioSinkChanged = false;
 
     int32_t numChannels;
@@ -2071,6 +2077,7 @@
             if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
                 ALOGV("openAudioSink: no change in offload mode");
                 // no change from previous configuration, everything ok.
+                ATRACE_END();
                 return OK;
             }
             mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
@@ -2140,6 +2147,7 @@
         if (memcmp(&mCurrentPcmInfo, &info, sizeof(info)) == 0) {
             ALOGV("openAudioSink: no change in pcm mode");
             // no change from previous configuration, everything ok.
+            ATRACE_END();
             return OK;
         }
 
@@ -2184,6 +2192,7 @@
             ALOGW("openAudioSink: non offloaded open failed status: %d", err);
             mAudioSink->close();
             mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
+            ATRACE_END();
             return err;
         }
         mCurrentPcmInfo = info;
@@ -2195,13 +2204,16 @@
         onAudioSinkChanged();
     }
     mAudioTornDown = false;
+    ATRACE_END();
     return OK;
 }
 
 void NuPlayer::Renderer::onCloseAudioSink() {
+    ATRACE_BEGIN("NuPlyer::Renderer::onCloseAudioSink");
     mAudioSink->close();
     mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
     mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
+    ATRACE_END();
 }
 
 void NuPlayer::Renderer::onChangeAudioFormat(
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index ac178aa..d084f10 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -321,6 +321,7 @@
 
     static_libs: [
         "android.media.codec-aconfig-cc",
+        "com.android.media.flags.editing-aconfig-cc",
         "libstagefright_esds",
         "libstagefright_color_conversion",
         "libyuv",
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 893b442..cc78510 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -654,7 +654,9 @@
     mReadOptions.clearSeekTo();
     if (err != OK) {
         ALOGW("Input Error: err=%d", err);
-        mediaBuffer->release();
+        if (mediaBuffer) {
+            mediaBuffer->release();
+        }
         return err;
     }
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 76b6aa6..3aa0107 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -53,6 +53,8 @@
 #include <media/esds/ESDS.h>
 #include "include/HevcUtils.h"
 
+#include <com_android_media_editing_flags.h>
+
 #ifndef __predict_false
 #define __predict_false(exp) __builtin_expect((exp) != 0, 0)
 #endif
@@ -4944,6 +4946,8 @@
             // Track with start offset.
             ALOGV("Tracks starting > 0");
             int32_t editDurationTicks = 0;
+            int32_t trackStartOffsetBFramesUs = getMinCttsOffsetTimeUs() - kMaxCttsOffsetTimeUs;
+            ALOGV("trackStartOffsetBFramesUs:%" PRId32, trackStartOffsetBFramesUs);
             if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
                 // Video with no B frame or non-video track.
                 editDurationTicks =
@@ -4952,8 +4956,6 @@
                 ALOGV("editDuration:%" PRId64 "us", (trackStartOffsetUs + movieStartOffsetBFramesUs));
             } else {
                 // Track with B frame.
-                int32_t trackStartOffsetBFramesUs = getMinCttsOffsetTimeUs() - kMaxCttsOffsetTimeUs;
-                ALOGV("trackStartOffsetBFramesUs:%" PRId32, trackStartOffsetBFramesUs);
                 editDurationTicks =
                         ((trackStartOffsetUs + movieStartOffsetBFramesUs +
                           trackStartOffsetBFramesUs) * mvhdTimeScale + 5E5) / 1E6;
@@ -4967,7 +4969,15 @@
             } else if (editDurationTicks < 0) {
                 // Only video tracks with B Frames would hit this case.
                 ALOGV("Edit list entry to negate start offset by B frames in other tracks");
-                addOneElstTableEntry(tkhdDurationTicks, std::abs(editDurationTicks), 1, 0);
+                if (com::android::media::editing::flags::
+                        stagefrightrecorder_enable_b_frames()) {
+                    int32_t mediaTimeTicks =
+                            ((trackStartOffsetUs + movieStartOffsetBFramesUs +
+                              trackStartOffsetBFramesUs) * mTimeScale - 5E5) / 1E6;
+                    addOneElstTableEntry(tkhdDurationTicks, std::abs(mediaTimeTicks), 1, 0);
+                } else {
+                    addOneElstTableEntry(tkhdDurationTicks, std::abs(editDurationTicks), 1, 0);
+                }
             } else {
                 ALOGV("No edit list entry needed for this track");
             }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 1422868..9abe037 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2018,6 +2018,7 @@
     int32_t flags;
     CHECK(buffer->meta()->findInt32("flags", &flags));
     if (flags & BUFFER_FLAG_DECODE_ONLY) {
+        ALOGV("discardDecodeOnlyOutputBuffer: mPortBuffers[out][%zu] NOT owned by client", index);
         info->mOwnedByClient = false;
         info->mData.clear();
         mBufferChannel->discardBuffer(buffer);
@@ -2462,7 +2463,12 @@
             mediametrics_setInt32(nextMetricsHandle, kCodecCrypto, 1);
         }
     } else if (mFlags & kFlagIsSecure) {
-        ALOGW("Crypto or descrambler should be given for secure codec");
+        if (android::media::codec::provider_->secure_codecs_require_crypto()) {
+            mErrorLog.log(LOG_TAG, "Crypto or descrambler must be given for secure codec");
+            return INVALID_OPERATION;
+        } else {
+            ALOGW("Crypto or descrambler should be given for secure codec");
+        }
     }
 
     if (mConfigureMsg != nullptr) {
@@ -4492,9 +4498,16 @@
                 {
                     /* size_t index = */updateBuffers(kPortIndexInput, msg);
 
-                    if (mState == FLUSHING
-                            || mState == STOPPING
-                            || mState == RELEASING) {
+                    bool inStateToReturnBuffers =
+                        mState == FLUSHING || mState == STOPPING || mState == RELEASING;
+                    if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+                        // Late callbacks from the codec could arrive here
+                        // after the codec is already stopped or released.
+                        inStateToReturnBuffers = mState == FLUSHING ||
+                                                 mState == STOPPING || mState == INITIALIZED ||
+                                                 mState == RELEASING || mState == UNINITIALIZED;
+                    }
+                    if (inStateToReturnBuffers) {
                         returnBuffersToCodecOnPort(kPortIndexInput);
                         break;
                     }
@@ -4573,9 +4586,16 @@
 
                     /* size_t index = */updateBuffers(kPortIndexOutput, msg);
 
-                    if (mState == FLUSHING
-                            || mState == STOPPING
-                            || mState == RELEASING) {
+                    bool inStateToReturnBuffers =
+                        mState == FLUSHING || mState == STOPPING || mState == RELEASING;
+                    if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+                        // Late callbacks from the codec could arrive here
+                        // after the codec is already stopped or released.
+                        inStateToReturnBuffers = mState == FLUSHING ||
+                                                 mState == STOPPING || mState == INITIALIZED ||
+                                                 mState == RELEASING || mState == UNINITIALIZED;
+                    }
+                    if (inStateToReturnBuffers) {
                         returnBuffersToCodecOnPort(kPortIndexOutput);
                         break;
                     }
@@ -5941,7 +5961,7 @@
     }
 
     updateHdrMetrics(false /* isConfig */);
- }
+}
 
 void MediaCodec::extractCSD(const sp<AMessage> &format) {
     mCSD.clear();
@@ -6020,7 +6040,6 @@
             return -EINVAL;
         }
         if (codecInputData->data() == NULL) {
-            ALOGV("Input buffer %zu is not properly allocated", bufferIndex);
             mErrorLog.log(LOG_TAG, base::StringPrintf(
                     "Fatal error: input buffer %zu is not properly allocated", bufferIndex));
             return -EINVAL;
@@ -6066,6 +6085,10 @@
 
         mInputFormat.clear();
         mOutputFormat.clear();
+        if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+            mCSD.clear();
+            mLeftover.clear();
+        }
         mFlags &= ~kFlagOutputFormatChanged;
         mFlags &= ~kFlagOutputBuffersChanged;
         mFlags &= ~kFlagStickyError;
@@ -6124,6 +6147,8 @@
                 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
                         portIndex, i);
             } else {
+                ALOGV("returnBuffersToCodecOnPort: mPortBuffers[%s][%zu] NOT owned by client",
+                      portIndex == kPortIndexInput ? "in" : "out", i);
                 info->mOwnedByClient = false;
                 info->mData.clear();
             }
@@ -6476,6 +6501,7 @@
 
         // synchronization boundary for getBufferAndFormat
         Mutex::Autolock al(mBufferLock);
+        ALOGV("onQueueInputBuffer: mPortBuffers[in][%zu] NOT owned by client", index);
         info->mOwnedByClient = false;
         info->mData.clear();
 
@@ -6492,6 +6518,7 @@
     sp<AMessage> msg = mLeftover.front();
     mLeftover.pop_front();
     msg->setSize("index", index);
+    ALOGV("handleLeftover(%zu)", index);
     return onQueueInputBuffer(msg);
 }
 
@@ -6560,6 +6587,7 @@
     sp<MediaCodecBuffer> buffer;
     {
         Mutex::Autolock al(mBufferLock);
+        ALOGV("onReleaseOutputBuffer: mPortBuffers[out][%zu] NOT owned by client", index);
         info->mOwnedByClient = false;
         buffer = info->mData;
         info->mData.clear();
@@ -6672,6 +6700,8 @@
 
     {
         Mutex::Autolock al(mBufferLock);
+        ALOGV("dequeuePortBuffer: mPortBuffers[%s][%zu] checking if not owned by client",
+              portIndex == kPortIndexInput ? "in" : "out", index);
         CHECK(!info->mOwnedByClient);
         info->mOwnedByClient = true;
 
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index b7efbce..354fab0 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -85,13 +85,37 @@
     // writerTest fails about 5 out of 66
     // { "name": "writerTest" },
     {
-       "name": "BatteryChecker_test"
+        "name": "BatteryChecker_test"
     },
     {
         "name": "ExtractorFactoryTest"
     },
     {
         "name": "HEVCUtilsUnitTest"
+    },
+    {
+      "name": "MctsMediaDecoderTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        }
+      ]
+    },
+    {
+      "name": "MctsMediaEncoderTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        }
+      ]
+    },
+    {
+      "name": "MctsMediaCodecTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        }
+      ]
     }
   ]
 }
diff --git a/media/libstagefright/writer_fuzzers/Android.bp b/media/libstagefright/writer_fuzzers/Android.bp
index 58aa7cd..840c6b3c 100644
--- a/media/libstagefright/writer_fuzzers/Android.bp
+++ b/media/libstagefright/writer_fuzzers/Android.bp
@@ -24,6 +24,7 @@
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["frameworks_av_media_libstagefright_license"],
+    default_team: "trendy_team_android_media_solutions_editing",
 }
 
 cc_defaults {
@@ -35,14 +36,17 @@
         "include",
     ],
     static_libs: [
+        "com.android.media.flags.editing-aconfig-cc",
         "liblog",
-        "libstagefright_foundation",
         "libstagefright",
+        "libstagefright_foundation",
     ],
     shared_libs: [
+        "libaconfig_storage_read_api_cc",
         "libbinder",
         "libcutils",
         "libutils",
+        "server_configurable_flags",
     ],
 }
 
@@ -96,9 +100,9 @@
 }
 
 cc_fuzz {
-    name : "mpeg4_writer_fuzzer",
-    defaults : ["writer-fuzzer-defaults"],
-    srcs : [
+    name: "mpeg4_writer_fuzzer",
+    defaults: ["writer-fuzzer-defaults"],
+    srcs: [
         "mpeg4_writer_fuzzer.cpp",
     ],
     static_libs: [
@@ -107,9 +111,9 @@
 }
 
 cc_fuzz {
-    name : "ogg_writer_fuzzer",
-    defaults : ["writer-fuzzer-defaults"],
-    srcs : [
+    name: "ogg_writer_fuzzer",
+    defaults: ["writer-fuzzer-defaults"],
+    srcs: [
         "ogg_writer_fuzzer.cpp",
     ],
     static_libs: [
@@ -118,9 +122,9 @@
 }
 
 cc_fuzz {
-    name : "webm_writer_fuzzer",
-    defaults : ["writer-fuzzer-defaults"],
-    srcs : [
+    name: "webm_writer_fuzzer",
+    defaults: ["writer-fuzzer-defaults"],
+    srcs: [
         "webm_writer_fuzzer.cpp",
     ],
     static_libs: [
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 8c1ef3b..bd11326 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -1069,7 +1069,7 @@
         codec.rank = rank;
     }
 
-    codec.variantSet = variants;
+    codec.variantSet.insert(variants.begin(), variants.end());
 
     // we allow sets of domains...
     for (const std::string &domain : domains) {
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 6ea40e3..b5124d0 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -51,9 +51,16 @@
     ],
 }
 
+vintf_fragment {
+    name: "manifest_media_c2_software.xml",
+    src: "manifest_media_c2_software.xml",
+}
+
 mediaserver_cc_binary {
     name: "mediaserver",
 
+    defaults: ["libcodec2_hal_selection"],
+
     srcs: ["main_mediaserver.cpp"],
 
     shared_libs: [
@@ -61,6 +68,7 @@
         "libicu",
         "libfmq",
         "libbinder",
+        "libbinder_ndk",
         "libhidlbase",
         "liblog",
         "libmediaplayerservice",
@@ -85,7 +93,7 @@
         "-Wall",
     ],
 
-    vintf_fragments: ["manifest_media_c2_software.xml"],
+    vintf_fragment_modules: ["manifest_media_c2_software.xml"],
 
     soong_config_variables: {
         TARGET_DYNAMIC_64_32_MEDIASERVER: {
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 026847a..8a62f30 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -17,11 +17,12 @@
 
 #define LOG_TAG "mediaserver"
 //#define LOG_NDEBUG 0
-
+#include <android/binder_process.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
 #include <hidl/HidlTransportSupport.h>
+#include <codec2/common/HalSelection.h>
 #include <utils/Log.h>
 #include "RegisterExtensions.h"
 
@@ -30,6 +31,14 @@
 
 using namespace android;
 
+namespace {
+    constexpr int kCodecThreadPoolCount = 16;
+
+    // This is the default thread count for binder thread pool
+    // if the thread count is not configured.
+    constexpr int kDefaultBinderThreadPoolCount = 15;
+}; // anonymous
+
 int main(int argc __unused, char **argv __unused)
 {
     signal(SIGPIPE, SIG_IGN);
@@ -40,8 +49,14 @@
     MediaPlayerService::instantiate();
     ResourceManagerService::instantiate();
     registerExtensions();
-    ::android::hardware::configureRpcThreadpool(16, false);
+
+    bool aidl = ::android::IsCodec2AidlHalSelected();
+    if (!aidl) {
+        ::android::hardware::configureRpcThreadpool(kCodecThreadPoolCount, false);
+    } else {
+        ABinderProcess_setThreadPoolMaxThreadCount(
+                kCodecThreadPoolCount + kDefaultBinderThreadPoolCount);
+    }
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
-    ::android::hardware::joinRpcThreadpool();
 }
diff --git a/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h b/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
index 8817621..64fdfb9 100644
--- a/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
+++ b/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
@@ -115,7 +115,6 @@
      Returns:
         L_sum = 32-bit sum of L_var1 and L_var2 (Word32)
     */
-    __attribute__((no_sanitize("integer")))
     static inline Word32 L_add(Word32 L_var1, Word32 L_var2, Flag *pOverflow)
     {
         Word32 L_sum;
@@ -454,7 +453,8 @@
     {
         Word32 result;
 
-        result = L_var3 + L_var1 * L_var2;
+        __builtin_mul_overflow(L_var1, L_var2, &result);
+        __builtin_add_overflow(L_var3, result, &result);
 
         return result;
     }
@@ -463,7 +463,8 @@
     {
         Word32 result;
 
-        result = L_var3 - L_var1 * L_var2;
+        __builtin_mul_overflow(L_var1, L_var2, &result);
+        __builtin_sub_overflow(L_var3, result, &result);
 
         return result;
     }
diff --git a/media/module/codecs/amrnb/common/src/az_lsp.cpp b/media/module/codecs/amrnb/common/src/az_lsp.cpp
index f3098f5..a19ddbf 100644
--- a/media/module/codecs/amrnb/common/src/az_lsp.cpp
+++ b/media/module/codecs/amrnb/common/src/az_lsp.cpp
@@ -237,9 +237,6 @@
 
 ------------------------------------------------------------------------------
 */
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
 static Word16 Chebps(Word16 x,
                      Word16 f[], /* (n) */
                      Word16 n,
diff --git a/media/module/codecs/amrnb/common/src/l_abs.cpp b/media/module/codecs/amrnb/common/src/l_abs.cpp
index 7e0ae99..b13a40a 100644
--- a/media/module/codecs/amrnb/common/src/l_abs.cpp
+++ b/media/module/codecs/amrnb/common/src/l_abs.cpp
@@ -186,8 +186,12 @@
     ; Function body here
     ----------------------------------------------------------------------------*/
 
-    Word32 y = L_var1 - (L_var1 < 0);
-    y = y ^(y >> 31);
-    return (y);
+    if (L_var1 >= 0) return L_var1;
+    if (L_var1 != 0x80000000) return -L_var1;
+    // abs(0x80000000) can not be represented in Word32.
+    // we choose to return the closest value we can -- 0x7fffffff
+    // This is acceptable because it keeps the result within the valid 32-bit signed integer range,
+    // consistent with other overflow handling in the code. such as amrnb/enc/src/l_negate.cpp.
+    return 0x7FFFFFFF;
 
 }
diff --git a/media/module/codecs/amrnb/common/src/lsp_az.cpp b/media/module/codecs/amrnb/common/src/lsp_az.cpp
index 495359f..bb8a34d 100644
--- a/media/module/codecs/amrnb/common/src/lsp_az.cpp
+++ b/media/module/codecs/amrnb/common/src/lsp_az.cpp
@@ -281,8 +281,8 @@
             t0 += ((Word32)lo * *lsp) >> 15;
 
             *(f) +=  *(f - 2);          /*      *f += f[-2]      */
-            *(f--) -=  t0 << 2;         /*      *f -= t0         */
-
+            __builtin_sub_overflow(*(f), (t0 << 2), f);   /*      *f -= t0         */
+            f--;
         }
 
         *f -= (Word32)(*lsp++) << 10;
diff --git a/media/module/codecs/amrnb/common/src/norm_l.cpp b/media/module/codecs/amrnb/common/src/norm_l.cpp
index d8d1259..b24ebda 100644
--- a/media/module/codecs/amrnb/common/src/norm_l.cpp
+++ b/media/module/codecs/amrnb/common/src/norm_l.cpp
@@ -211,8 +211,7 @@
     if (L_var1)
     {
 
-        Word32 y = L_var1 - (L_var1 < 0);
-        L_var1 = y ^(y >> 31);
+        L_var1 = L_abs(L_var1);
 
 
         while (!(0x40000000L & L_var1))
diff --git a/media/module/codecs/amrnb/common/src/residu.cpp b/media/module/codecs/amrnb/common/src/residu.cpp
index 2ad132f..9b077e2 100644
--- a/media/module/codecs/amrnb/common/src/residu.cpp
+++ b/media/module/codecs/amrnb/common/src/residu.cpp
@@ -227,22 +227,35 @@
         p_input3 = p_input_ptr--;
         p_input4 = p_input_ptr--;
 
+        Word32 tmp;
         for (j = M >> 1; j != 0; j--)
         {
-            s1 += ((Word32) * (p_coef) * *(p_input1++));
-            s2 += ((Word32) * (p_coef) * *(p_input2++));
-            s3 += ((Word32) * (p_coef) * *(p_input3++));
-            s4 += ((Word32) * (p_coef--) * *(p_input4++));
-            s1 += ((Word32) * (p_coef) * *(p_input1++));
-            s2 += ((Word32) * (p_coef) * *(p_input2++));
-            s3 += ((Word32) * (p_coef) * *(p_input3++));
-            s4 += ((Word32) * (p_coef--) * *(p_input4++));
+            __builtin_mul_overflow(*p_coef, *(p_input1++), &tmp);
+            __builtin_add_overflow(s1, tmp, &s1);
+            __builtin_mul_overflow(*p_coef, *(p_input2++), &tmp);
+            __builtin_add_overflow(s2, tmp, &s2);
+            __builtin_mul_overflow(*p_coef, *(p_input3++), &tmp);
+            __builtin_add_overflow(s3, tmp, &s3);
+            __builtin_mul_overflow(*(p_coef--), *(p_input4++), &tmp);
+            __builtin_add_overflow(s4, tmp, &s4);
+            __builtin_mul_overflow(*p_coef, *(p_input1++), &tmp);
+            __builtin_add_overflow(s1, tmp, &s1);
+            __builtin_mul_overflow(*p_coef, *(p_input2++), &tmp);
+            __builtin_add_overflow(s2, tmp, &s2);
+            __builtin_mul_overflow(*p_coef, *(p_input3++), &tmp);
+            __builtin_add_overflow(s3, tmp, &s3);
+            __builtin_mul_overflow(*(p_coef--), *(p_input4++), &tmp);
+            __builtin_add_overflow(s4, tmp, &s4);
         }
 
-        s1 += (((Word32) * (p_coef)) * *(p_input1));
-        s2 += (((Word32) * (p_coef)) * *(p_input2));
-        s3 += (((Word32) * (p_coef)) * *(p_input3));
-        s4 += (((Word32) * (p_coef)) * *(p_input4));
+        __builtin_mul_overflow(*p_coef, *(p_input1), &tmp);
+        __builtin_add_overflow(s1, tmp, &s1);
+        __builtin_mul_overflow(*p_coef, *(p_input2), &tmp);
+        __builtin_add_overflow(s2, tmp, &s2);
+        __builtin_mul_overflow(*p_coef, *(p_input3), &tmp);
+        __builtin_add_overflow(s3, tmp, &s3);
+        __builtin_mul_overflow(*p_coef, *(p_input4), &tmp);
+        __builtin_add_overflow(s4, tmp, &s4);
 
         *(p_residual_ptr--) = (Word16)(s1 >> 12);
         *(p_residual_ptr--) = (Word16)(s2 >> 12);
diff --git a/media/module/codecs/amrnb/common/src/sub.cpp b/media/module/codecs/amrnb/common/src/sub.cpp
index b956912..d936128 100644
--- a/media/module/codecs/amrnb/common/src/sub.cpp
+++ b/media/module/codecs/amrnb/common/src/sub.cpp
@@ -187,9 +187,6 @@
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
 
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
 Word16 sub(Word16 var1, Word16 var2, Flag *pOverflow)
 {
 
diff --git a/media/module/codecs/amrnb/common/src/syn_filt.cpp b/media/module/codecs/amrnb/common/src/syn_filt.cpp
index 36c1d84..82770f1 100644
--- a/media/module/codecs/amrnb/common/src/syn_filt.cpp
+++ b/media/module/codecs/amrnb/common/src/syn_filt.cpp
@@ -245,9 +245,6 @@
 
 ------------------------------------------------------------------------------
 */
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
 void Syn_filt(
     Word16 a[],     /* (i)   : a[M+1] prediction coefficients   (M=10)  */
     Word16 x[],     /* (i)   : input signal                             */
diff --git a/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp b/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
index af62074..984baf8 100644
--- a/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
+++ b/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
@@ -22,6 +22,7 @@
 
 #include <audio_utils/sndfile.h>
 #include <stdio.h>
+#include <fstream>
 
 #include "gsmamr_dec.h"
 
@@ -40,7 +41,7 @@
 
 static AmrnbDecTestEnvironment *gEnv = nullptr;
 
-class AmrnbDecoderTest : public ::testing::TestWithParam<string> {
+class AmrnbDecoderTest : public ::testing::TestWithParam<std::tuple<string, string>> {
   public:
     AmrnbDecoderTest() : mFpInput(nullptr) {}
 
@@ -54,6 +55,7 @@
     FILE *mFpInput;
     SNDFILE *openOutputFile(SF_INFO *sfInfo);
     int32_t DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, int32_t frameCount = INT32_MAX);
+    bool compareBinaryFiles(const std::string& refFilePath, const std::string& outFilePath);
 };
 
 SNDFILE *AmrnbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
@@ -97,6 +99,42 @@
     return 0;
 }
 
+bool AmrnbDecoderTest::compareBinaryFiles(const std::string &refFilePath,
+                                          const std::string &outFilePath) {
+    std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+    std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+    assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+    assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+    std::streamsize refFileSize = refFile.tellg();
+    std::streamsize outFileSize = outFile.tellg();
+    if (refFileSize != outFileSize) {
+        ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+              " but output file size = %td bytes.", refFileSize, outFileSize);
+        return false;
+    }
+
+    refFile.seekg(0, std::ios::beg);
+    outFile.seekg(0, std::ios::beg);
+    constexpr std::streamsize kBufferSize = 16 * 1024;
+    char refBuffer[kBufferSize];
+    char outBuffer[kBufferSize];
+
+    while (refFile && outFile) {
+        refFile.read(refBuffer, kBufferSize);
+        outFile.read(outBuffer, kBufferSize);
+
+        std::streamsize refBytesRead = refFile.gcount();
+        std::streamsize outBytesRead = outFile.gcount();
+
+        if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+            ALOGE("Error, File content mismatch.");
+            return false;
+        }
+    }
+    return true;
+}
+
 TEST_F(AmrnbDecoderTest, CreateAmrnbDecoderTest) {
     void *amrHandle;
     int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
@@ -106,7 +144,7 @@
 }
 
 TEST_P(AmrnbDecoderTest, DecodeTest) {
-    string inputFile = gEnv->getRes() + GetParam();
+    string inputFile = gEnv->getRes() + std::get<0>(GetParam());
     mFpInput = fopen(inputFile.c_str(), "rb");
     ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
 
@@ -126,10 +164,15 @@
     sf_close(outFileHandle);
     GSMDecodeFrameExit(&amrHandle);
     ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+
+    string refFilePath = gEnv->getRes() + std::get<1>(GetParam());
+    ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+       << "Error, Binary file comparison failed: Output file " << OUTPUT_FILE
+       << " does not match the reference file " << refFilePath << ".";
 }
 
 TEST_P(AmrnbDecoderTest, ResetDecodeTest) {
-    string inputFile = gEnv->getRes() + GetParam();
+    string inputFile = gEnv->getRes() + std::get<0>(GetParam());
     mFpInput = fopen(inputFile.c_str(), "rb");
     ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
 
@@ -159,8 +202,24 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(AmrnbDecoderTestAll, AmrnbDecoderTest,
-                         ::testing::Values(("bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb"),
-                                           ("sine_amrnb_1ch_12kbps_8000hz.amrnb")));
+                         ::testing::Values(std::make_tuple(
+                                                   "bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb",
+                                                   "bbb_8000hz_1ch_8kbps_amrnb_30sec_ref.pcm"),
+                                           std::make_tuple(
+                                                   "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+                                                   "sine_amrnb_1ch_12kbps_8000hz_ref.pcm"),
+                                           std::make_tuple(
+                                                   "trim_8000hz_1ch_12kpbs_amrnb_200ms.amrnb",
+                                                   "trim_8000hz_1ch_12kpbs_amrnb_200ms_ref.pcm"),
+                                           std::make_tuple(
+                                                   "bbb_8kHz_1ch_4.75kbps_amrnb_3sec.amrnb",
+                                                   "bbb_8kHz_1ch_4.75kbps_amrnb_3sec_ref.pcm"),
+                                           std::make_tuple(
+                                                   "bbb_8kHz_1ch_10kbps_amrnb_1sec.amrnb",
+                                                   "bbb_8kHz_1ch_10kbps_amrnb_1sec_ref.pcm"),
+                                           std::make_tuple(
+                                                   "bbb_8kHz_1ch_12.2kbps_amrnb_3sec.amrnb",
+                                                   "bbb_8kHz_1ch_12.2kbps_amrnb_3sec_ref.pcm")));
 
 int main(int argc, char **argv) {
     gEnv = new AmrnbDecTestEnvironment();
diff --git a/media/module/codecs/amrnb/dec/test/AndroidTest.xml b/media/module/codecs/amrnb/dec/test/AndroidTest.xml
index 539fa5c..7b2ba15 100644
--- a/media/module/codecs/amrnb/dec/test/AndroidTest.xml
+++ b/media/module/codecs/amrnb/dec/test/AndroidTest.xml
@@ -23,17 +23,17 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="host" />
         <option name="config-filename" value="AmrnbDecoderTest" />
-        <option name="version" value="1.0"/>
+        <option name="version" value="2.0"/>
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
-        <option name="media-folder-name" value="AmrnbDecoderTest-1.0" />
+        <option name="media-folder-name" value="AmrnbDecoderTest-2.0" />
         <option name="dynamic-config-module" value="AmrnbDecoderTest" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="AmrnbDecoderTest" />
-        <option name="native-test-flag" value="-P /sdcard/test/AmrnbDecoderTest-1.0/" />
+        <option name="native-test-flag" value="-P /sdcard/test/AmrnbDecoderTest-2.0/" />
     </test>
 </configuration>
diff --git a/media/module/codecs/amrnb/dec/test/DynamicConfig.xml b/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
index 701a752..02b869a 100644
--- a/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
+++ b/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
 
 <dynamicConfig>
     <entry key="media_files_url">
-            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-1.0.zip</value>
+            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-2.0.zip</value>
     </entry>
 </dynamicConfig>
diff --git a/media/module/codecs/amrnb/dec/test/README.md b/media/module/codecs/amrnb/dec/test/README.md
index 41fb80a..ea54975 100644
--- a/media/module/codecs/amrnb/dec/test/README.md
+++ b/media/module/codecs/amrnb/dec/test/README.md
@@ -22,15 +22,15 @@
 adb push ${OUT}/data/nativetest/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-2.0.zip). Download, unzip and push these files into device for testing.
 
 ```
-adb push AmrnbDecoderTest-1.0 /data/local/tmp/
+adb push AmrnbDecoderTest-2.0 /data/local/tmp/
 ```
 
 usage: AmrnbDecoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/AmrnbDecoderTest-1.0/
+adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/AmrnbDecoderTest-2.0/
 ```
 Alternatively, the test can also be run using atest command.
 
diff --git a/media/module/codecs/amrnb/enc/src/autocorr.cpp b/media/module/codecs/amrnb/enc/src/autocorr.cpp
index c71811d..a078f5a 100644
--- a/media/module/codecs/amrnb/enc/src/autocorr.cpp
+++ b/media/module/codecs/amrnb/enc/src/autocorr.cpp
@@ -312,6 +312,7 @@
 
     Word16 y[L_WINDOW];
     Word32 sum;
+    Word32 mul;
     Word16 overfl_shft;
 
 
@@ -343,7 +344,8 @@
         temp = (amrnb_fxp_mac_16_by_16bb((Word32) * (p_x++), (Word32) * (p_wind++), 0x04000)) >> 15;
         *(p_y++) = temp;
 
-        sum += ((Word32)temp * temp) << 1;
+        __builtin_mul_overflow(temp, temp, &mul);
+        __builtin_add_overflow(sum, mul << 1, &sum);
         if (sum < 0)
         {
             /*
@@ -395,10 +397,12 @@
         {
             temp = *p_y >> 2;
             *(p_y++) = temp;
-            sum += ((Word32)temp * temp) << 1;
+            __builtin_mul_overflow(temp, temp, &mul);
+            __builtin_add_overflow(sum, mul << 1, &sum);
             temp = *p_y >> 2;
             *(p_y++) = temp;
-            sum += ((Word32)temp * temp) << 1;
+            __builtin_mul_overflow(temp, temp, &mul);
+            __builtin_add_overflow(sum, mul << 1, &sum);
         }
         if (sum > 0)
         {
diff --git a/media/module/codecs/amrnb/enc/src/c2_9pf.cpp b/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
index b211032..56b4fb8 100644
--- a/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
@@ -610,6 +610,7 @@
         Word32 alp1;
         Word16 i;
         Word32 L_temp;
+        Word32 mul;
         Word16 *p_codvec = &codvec[0];
 
         OSCL_UNUSED_ARG(pOverflow);
@@ -693,7 +694,8 @@
                     L_temp = ((Word32) alp * sq1) << 1;
 
                     /* s = L_msu(L_temp, sq, alp_16, pOverflow); */
-                    s = L_temp - (((Word32) sq * alp_16) << 1);
+                    __builtin_mul_overflow(sq, alp_16, &mul);
+                    __builtin_sub_overflow(L_temp, (mul << 1), &s);
 
                     if (s > 0)
                     {
diff --git a/media/module/codecs/amrnb/enc/src/c3_14pf.cpp b/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
index 58ab2fa..bb4fe36 100644
--- a/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
@@ -403,6 +403,7 @@
     Word16 *p_codvec = &codvec[0];
 
     Word32 s;
+    Word32 mul;
     Word32 alp0;
     Word32 alp1;
 
@@ -487,7 +488,8 @@
                             s = ((Word32) alp * sq1) << 1;
 
                             /* s = L_msu(s, sq, alp_16, pOverflow); */
-                            s -= (((Word32) sq * alp_16) << 1);
+                            __builtin_mul_overflow(sq, alp_16, &mul);
+                            __builtin_sub_overflow(s, (mul << 1), &s);
 
                             if (s > 0)
                             {
diff --git a/media/module/codecs/amrnb/enc/src/c4_17pf.cpp b/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
index d52b43b..062ee5a 100644
--- a/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
@@ -416,6 +416,7 @@
         Word16 *p_codvec = &codvec[0];
 
         Word32 s;
+        Word32 mul;
         Word32 alp0;
         Word32 alp1;
 
@@ -497,7 +498,8 @@
                             s = ((Word32) alp * sq1) << 1;
 
                             /* s = L_msu(s, sq, alp_16, pOverflow); */
-                            s -= (((Word32) sq * alp_16) << 1);
+                            __builtin_mul_overflow(sq, alp_16, &mul);
+                            __builtin_sub_overflow(s, (mul << 1), &s);
 
                             if (s > 0)
                             {
@@ -610,7 +612,8 @@
                             s = ((Word32) alp * sq1) << 1;
 
                             /* s = L_msu(s, sq, alp_16, pOverflow); */
-                            s -= (((Word32) sq * alp_16) << 1);
+                            __builtin_mul_overflow(sq, alp_16, &mul);
+                            __builtin_sub_overflow(s, (mul << 1), &s);
 
                             if (s > 0)
                             {
@@ -630,7 +633,8 @@
                         s = ((Word32) alpk * sq) << 1;
 
                         /* s = L_msu(s, psk, alp, pOverflow); */
-                        s -= (((Word32) psk * alp) << 1);
+                        __builtin_mul_overflow(psk, alp, &mul);
+                        __builtin_sub_overflow(s, (mul << 1), &s);
 
                         if (s > 0)
                         {
diff --git a/media/module/codecs/amrnb/enc/src/cor_h_x.cpp b/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
index c25c026..398c71f 100644
--- a/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
+++ b/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
@@ -254,6 +254,7 @@
     Word16 k;
 
     Word32 s;
+    Word32 mul;
     Word32 y32[L_CODE];
     Word32 max;
     Word32 tot;
@@ -275,15 +276,19 @@
 
             for (j = (L_CODE - i - 1) >> 1; j != 0; j--)
             {
-                s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
-                s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+                __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+                __builtin_add_overflow(s, mul << 1, &s);
+                __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+                __builtin_add_overflow(s, mul << 1, &s);
             }
 
-            s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+            __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+            __builtin_add_overflow(s, mul << 1, &s);
 
             if (!((L_CODE - i) & 1))    /* if even number of iterations */
             {
-                s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+                __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+                __builtin_add_overflow(s, mul << 1, &s);
             }
 
             y32[i] = s;
@@ -299,7 +304,7 @@
             }
         }
 
-        tot += (max >> 1);
+        __builtin_add_overflow(tot, (max >> 1), &tot);
     }
 
 
@@ -310,10 +315,13 @@
 
     for (i = L_CODE >> 1; i != 0; i--)
     {
+        Word32 result;
         s = L_shl(*(p_y32++), j, pOverflow);
-        *(p_ptr++) = (s + 0x00008000) >> 16;
+        __builtin_add_overflow(s, 0x00008000, &result);
+        *(p_ptr++) = result >> 16;
         s = L_shl(*(p_y32++), j, pOverflow);
-        *(p_ptr++) = (s + 0x00008000) >> 16;
+        __builtin_add_overflow(s, 0x00008000, &result);
+        *(p_ptr++) = result >> 16;
     }
 
     return;
diff --git a/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp b/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
index e32eb4a..80ebb73 100644
--- a/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
+++ b/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
@@ -268,7 +268,7 @@
                 max = s;
             }
         }
-        tot = (tot + (max >> 1));
+        __builtin_add_overflow(tot, (max >> 1), &tot);
     }
 
     j = sub(norm_l(tot), sf, pOverflow);
diff --git a/media/module/codecs/amrnb/enc/src/dtx_enc.cpp b/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
index 2ccb777..0d56c9b 100644
--- a/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
+++ b/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
@@ -945,6 +945,7 @@
 
     Word16 i;
     Word32 L_frame_en;
+    Word32 mul;
     Word32 L_temp;
     Word16 log_en_e;
     Word16 log_en_m;
@@ -967,7 +968,8 @@
 
     for (i = L_FRAME; i != 0; i--)
     {
-        L_frame_en += (((Word32) * p_speech) * *(p_speech)) << 1;
+        __builtin_mul_overflow(*p_speech, *p_speech, &mul);
+        __builtin_add_overflow(L_frame_en, mul << 1, &L_frame_en);
         p_speech++;
         if (L_frame_en < 0)
         {
diff --git a/media/module/codecs/amrnb/enc/src/levinson.cpp b/media/module/codecs/amrnb/enc/src/levinson.cpp
index 29cdac6..83dd81e 100644
--- a/media/module/codecs/amrnb/enc/src/levinson.cpp
+++ b/media/module/codecs/amrnb/enc/src/levinson.cpp
@@ -731,7 +731,7 @@
         t0 = t0 << 5;
 
         t1 = ((Word32) * (Rh + i) << 16) + ((Word32)(*(Rl + i)) << 1);
-        t0 += t1;
+        __builtin_add_overflow(t0, t1, &t0);
 
         /* K = -t0 / Alpha */
 
diff --git a/media/module/codecs/amrnb/enc/src/pitch_fr.cpp b/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
index 584f79b..ab0a221 100644
--- a/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
+++ b/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
@@ -326,6 +326,7 @@
     Word16 norm_h;
     Word16 norm_l;
     Word32 s;
+    Word32 mul;
     Word32 s2;
     Word16 excf[L_SUBFR];
     Word16 scaling;
@@ -353,10 +354,12 @@
     {
         temp = *(p_excf++);
         *(p_s_excf++) = temp >> 2;
-        s += (Word32) temp * temp;
+        __builtin_mul_overflow(temp, temp, &mul);
+        __builtin_add_overflow(s, mul, &s);
         temp = *(p_excf++);
         *(p_s_excf++) = temp >> 2;
-        s += (Word32) temp * temp;
+        __builtin_mul_overflow(temp, temp, &mul);
+        __builtin_add_overflow(s, mul, &s);
     }
 
 
@@ -387,20 +390,24 @@
 
         while (j--)
         {
-            s  += (Word32) * (p_x++) * *(p_s_excf);
-            s2 += ((Word32)(*(p_s_excf)) * (*(p_s_excf)));
+            __builtin_mul_overflow(*(p_x++), *p_s_excf, &mul);
+            __builtin_add_overflow(s, mul, &s);
+            __builtin_mul_overflow(*p_s_excf, *p_s_excf, &mul);
+            __builtin_add_overflow(s2, mul, &s2);
             p_s_excf++;
-            s  += (Word32) * (p_x++) * *(p_s_excf);
-            s2 += ((Word32)(*(p_s_excf)) * (*(p_s_excf)));
+            __builtin_mul_overflow(*(p_x++), *p_s_excf, &mul);
+            __builtin_add_overflow(s, mul, &s);
+            __builtin_mul_overflow(*p_s_excf, *p_s_excf, &mul);
+            __builtin_add_overflow(s2, mul, &s2);
             p_s_excf++;
         }
 
         s2     = s2 << 1;
         s2     = Inv_sqrt(s2, pOverflow);
         norm_h = (Word16)(s2 >> 16);
-        norm_l = (Word16)((s2 >> 1) - (norm_h << 15));
+        __builtin_sub_overflow((s2 >> 1), (norm_h << 15), &norm_l);
         corr_h = (Word16)(s >> 15);
-        corr_l = (Word16)((s) - (corr_h << 15));
+        __builtin_sub_overflow(s, (corr_h << 15), &corr_l);
 
         /* Normalize correlation = correlation * (1/sqrt(energy)) */
 
diff --git a/media/module/codecs/amrnb/enc/src/pitch_ol.cpp b/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
index c039bb0..0e4b74b 100644
--- a/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
+++ b/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
@@ -959,6 +959,7 @@
     Word16 p_max3;
     Word16 scal_flag = 0;
     Word32 t0;
+    Word32 mul;
 
 #ifdef VAD2
     Word32 r01;
@@ -1002,7 +1003,8 @@
 
     for (i = -pit_max; i < L_frame; i++)
     {
-        t0 += (((Word32) * (p_signal)) * *(p_signal)) << 1;
+        __builtin_mul_overflow(*p_signal, *p_signal, &mul);
+        __builtin_add_overflow(t0, mul << 1, &t0);
         p_signal++;
         if (t0 < 0)
         {
diff --git a/media/module/codecs/amrnb/enc/src/pre_proc.cpp b/media/module/codecs/amrnb/enc/src/pre_proc.cpp
index 042920e..0e2be41 100644
--- a/media/module/codecs/amrnb/enc/src/pre_proc.cpp
+++ b/media/module/codecs/amrnb/enc/src/pre_proc.cpp
@@ -576,7 +576,7 @@
         *(p_signal++) = (Word16)((L_tmp + 0x0000800L) >> 12);
 
         st->y1_hi = (Word16)(L_tmp >> 12);
-        st->y1_lo = (Word16)((L_tmp << 3) - ((Word32)(st->y1_hi) << 15));
+        __builtin_sub_overflow((Word16)(L_tmp << 3), (st->y1_hi) << 15, &st->y1_lo);
 
     }
 
diff --git a/media/module/codecs/amrnb/enc/src/s10_8pf.cpp b/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
index 352b611..97d0318 100644
--- a/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
@@ -746,11 +746,13 @@
 
             for (i5 = ipos[5]; i5 < L_CODE; i5 += step)
             {
-                ps2 = ps1 + *(p_temp1++);
+                __builtin_add_overflow(ps1, *(p_temp1++), &ps2);
 
-                alp2 = alp1 + ((Word32) * (p_temp2 + i5) << 12);
+                __builtin_add_overflow(alp1, *(p_temp2 + i5) << 12, &alp2);
 
-                alp_16 = (Word16)((alp2 + ((Word32) * (p_temp1++) << 14)) >> 16);
+                Word32 result;
+                __builtin_add_overflow(alp2, *(p_temp1++) << 14, &result);
+                alp_16 = (Word16)(result >> 16);
                 sq2 = (Word16)(((Word32) ps2 * ps2) >> 15);
 
                 if (((Word32) sq2 * alp) > ((Word32) sq * alp_16))
diff --git a/media/module/codecs/amrnb/enc/src/set_sign.cpp b/media/module/codecs/amrnb/enc/src/set_sign.cpp
index fa43f78..55658a4 100644
--- a/media/module/codecs/amrnb/enc/src/set_sign.cpp
+++ b/media/module/codecs/amrnb/enc/src/set_sign.cpp
@@ -505,6 +505,7 @@
     Word16 en[L_CODE];                  /* correlation vector */
     Word32 s;
     Word32 t;
+    Word32 mul;
     Word32 L_temp;
     Word16 *p_cn;
     Word16 *p_dn;
@@ -525,7 +526,8 @@
         val = *(p_cn++);
         s = L_mac(s, val, val, pOverflow);
         val = *(p_dn++);
-        t += ((Word32) val * val) << 1;
+        __builtin_mul_overflow(val, val, &mul);
+        __builtin_add_overflow(t, mul << 1, &t);
     }
     s = Inv_sqrt(s, pOverflow);
     k_cn = (Word16)((L_shl(s, 5, pOverflow)) >> 16);
diff --git a/media/module/codecs/amrnb/enc/src/spstproc.cpp b/media/module/codecs/amrnb/enc/src/spstproc.cpp
index b9574aa..5210a39 100644
--- a/media/module/codecs/amrnb/enc/src/spstproc.cpp
+++ b/media/module/codecs/amrnb/enc/src/spstproc.cpp
@@ -192,6 +192,7 @@
     Word16 i;
     Word16 j;
     Word16 temp;
+    Word32 mul;
     Word32 L_temp;
     Word32 L_temp2;
     Word16 tempShift;
@@ -262,8 +263,10 @@
          */
         L_temp     = ((Word32) * (p_exc++) * pitch_fac) << 1;
         L_temp2    = ((Word32) * (p_exc--) * pitch_fac) << 1;
-        L_temp    += ((Word32) * (p_code++) * gain_code) << 1;
-        L_temp2   += ((Word32) * (p_code++) * gain_code) << 1;
+        __builtin_mul_overflow(*(p_code++), gain_code, &mul);
+        __builtin_add_overflow(L_temp, mul << 1, &L_temp);
+        __builtin_mul_overflow(*(p_code++), gain_code, &mul);
+        __builtin_add_overflow(L_temp2, mul << 1, &L_temp2);
         L_temp   <<=  tempShift;
         L_temp2  <<=  tempShift;
         *(p_exc++) = (Word16)((L_temp  + 0x08000L) >> 16);
diff --git a/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp b/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
index fb72998..e3bd0e0 100644
--- a/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
+++ b/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
@@ -21,6 +21,7 @@
 
 #include <audio_utils/sndfile.h>
 #include <stdio.h>
+#include <fstream>
 
 #include "gsmamr_enc.h"
 
@@ -39,7 +40,7 @@
 
 static AmrnbEncTestEnvironment *gEnv = nullptr;
 
-class AmrnbEncoderTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+class AmrnbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, string>> {
   public:
     AmrnbEncoderTest() : mAmrEncHandle(nullptr) {}
 
@@ -53,6 +54,7 @@
     AmrNbEncState *mAmrEncHandle;
     int32_t EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
                          int32_t frameCount = INT32_MAX);
+    bool compareBinaryFiles(const string& refFilePath, const string& outFilePath);
 };
 
 int32_t AmrnbEncoderTest::EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
@@ -87,6 +89,42 @@
     return 0;
 }
 
+bool AmrnbEncoderTest::compareBinaryFiles(const std::string &refFilePath,
+                                          const std::string &outFilePath) {
+    std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+    std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+    assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+    assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+    std::streamsize refFileSize = refFile.tellg();
+    std::streamsize outFileSize = outFile.tellg();
+    if (refFileSize != outFileSize) {
+        ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+              " but output file size = %td bytes.", refFileSize, outFileSize);
+        return false;
+    }
+
+    refFile.seekg(0, std::ios::beg);
+    outFile.seekg(0, std::ios::beg);
+    constexpr std::streamsize kBufferSize = 16 * 1024;
+    char refBuffer[kBufferSize];
+    char outBuffer[kBufferSize];
+
+    while (refFile && outFile) {
+        refFile.read(refBuffer, kBufferSize);
+        outFile.read(outBuffer, kBufferSize);
+
+        std::streamsize refBytesRead = refFile.gcount();
+        std::streamsize outBytesRead = outFile.gcount();
+
+        if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+            ALOGE("Error, File content mismatch.");
+            return false;
+        }
+    }
+    return true;
+}
+
 TEST_F(AmrnbEncoderTest, CreateAmrnbEncoderTest) {
     mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
     ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
@@ -111,7 +149,7 @@
     int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
     ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
 
-    string inputFile = gEnv->getRes() + GetParam().first;
+    string inputFile = gEnv->getRes() + std::get<0>(GetParam());
     FILE *fpInput = fopen(inputFile.c_str(), "rb");
     ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
 
@@ -121,7 +159,7 @@
     // Write file header.
     fwrite("#!AMR\n", 1, 6, fpOutput);
 
-    int32_t mode = GetParam().second;
+    int32_t mode = std::get<1>(GetParam());
     int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput);
     ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
 
@@ -134,6 +172,11 @@
     free(mAmrEncHandle);
     mAmrEncHandle = nullptr;
     ALOGV("Successfully deleted encoder");
+
+    string refFilePath = gEnv->getRes() + std::get<2>(GetParam());
+    ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+       << "Error, Binary file comparison failed: Output file " << OUTPUT_FILE
+       << " does not match the reference file " << refFilePath << ".";
 }
 
 TEST_P(AmrnbEncoderTest, ResetEncoderTest) {
@@ -142,7 +185,7 @@
     int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
     ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
 
-    string inputFile = gEnv->getRes() + GetParam().first;
+    string inputFile = gEnv->getRes() + std::get<0>(GetParam());
     FILE *fpInput = fopen(inputFile.c_str(), "rb");
     ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
 
@@ -152,7 +195,7 @@
     // Write file header.
     fwrite("#!AMR\n", 1, 6, fpOutput);
 
-    int32_t mode = GetParam().second;
+    int32_t mode = std::get<1>(GetParam());
     // Encode kNumFrameReset first
     int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput, kNumFrameReset);
     ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
@@ -177,22 +220,23 @@
 
 // TODO: Add more test vectors
 INSTANTIATE_TEST_SUITE_P(AmrnbEncoderTestAll, AmrnbEncoderTest,
-                         ::testing::Values(make_pair("bbb_raw_1ch_8khz_s16le.raw", MR475),
-                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR515),
-                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR59),
-                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR67),
-                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR74),
-                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR795),
-                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR102),
-                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR122),
-                                           make_pair("sinesweepraw.raw", MR475),
-                                           make_pair("sinesweepraw.raw", MR515),
-                                           make_pair("sinesweepraw.raw", MR59),
-                                           make_pair("sinesweepraw.raw", MR67),
-                                           make_pair("sinesweepraw.raw", MR74),
-                                           make_pair("sinesweepraw.raw", MR795),
-                                           make_pair("sinesweepraw.raw", MR102),
-                                           make_pair("sinesweepraw.raw", MR122)));
+    ::testing::Values(
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR475, "bbb_raw_1ch_8khz_s16le_MR475_ref.amrnb"),
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR515, "bbb_raw_1ch_8khz_s16le_MR515_ref.amrnb"),
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR59, "bbb_raw_1ch_8khz_s16le_MR59_ref.amrnb"),
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR67, "bbb_raw_1ch_8khz_s16le_MR67_ref.amrnb"),
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR74, "bbb_raw_1ch_8khz_s16le_MR74_ref.amrnb"),
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR795, "bbb_raw_1ch_8khz_s16le_MR795_ref.amrnb"),
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR102, "bbb_raw_1ch_8khz_s16le_MR102_ref.amrnb"),
+        make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR122, "bbb_raw_1ch_8khz_s16le_MR122_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR475, "sinesweepraw_MR475_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR515, "sinesweepraw_MR515_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR59, "sinesweepraw_MR59_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR67, "sinesweepraw_MR67_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR74, "sinesweepraw_MR74_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR795, "sinesweepraw_MR795_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR102, "sinesweepraw_MR102_ref.amrnb"),
+        make_tuple("sinesweepraw.raw", MR122, "sinesweepraw_MR122_ref.amrnb")));
 
 int main(int argc, char **argv) {
     gEnv = new AmrnbEncTestEnvironment();
diff --git a/media/module/codecs/amrnb/enc/test/AndroidTest.xml b/media/module/codecs/amrnb/enc/test/AndroidTest.xml
index 1509728..a325ee8 100644
--- a/media/module/codecs/amrnb/enc/test/AndroidTest.xml
+++ b/media/module/codecs/amrnb/enc/test/AndroidTest.xml
@@ -23,17 +23,17 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="host" />
         <option name="config-filename" value="AmrnbEncoderTest" />
-        <option name="version" value="1.0"/>
+        <option name="version" value="2.0"/>
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
-        <option name="media-folder-name" value="AmrnbEncoderTest-1.0" />
+        <option name="media-folder-name" value="AmrnbEncoderTest-2.0" />
         <option name="dynamic-config-module" value="AmrnbEncoderTest" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="AmrnbEncoderTest" />
-        <option name="native-test-flag" value="-P /sdcard/test/AmrnbEncoderTest-1.0/" />
+        <option name="native-test-flag" value="-P /sdcard/test/AmrnbEncoderTest-2.0/" />
     </test>
 </configuration>
diff --git a/media/module/codecs/amrnb/enc/test/DynamicConfig.xml b/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
index 713667a..fdc0daa 100644
--- a/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
+++ b/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
 
 <dynamicConfig>
     <entry key="media_files_url">
-            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-1.0.zip</value>
+            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-2.0.zip</value>
     </entry>
 </dynamicConfig>
diff --git a/media/module/codecs/amrnb/enc/test/README.md b/media/module/codecs/amrnb/enc/test/README.md
index f896bd1..c7b9964 100644
--- a/media/module/codecs/amrnb/enc/test/README.md
+++ b/media/module/codecs/amrnb/enc/test/README.md
@@ -22,15 +22,15 @@
 adb push ${OUT}/data/nativetest/AmrnbEncoderTest/AmrnbEncoderTest /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-2.0.zip). Download, unzip and push these files into device for testing.
 
 ```
-adb push AmrnbEncoderTest-1.0 /data/local/tmp/
+adb push AmrnbEncoderTest-2.0 /data/local/tmp/
 ```
 
 usage: AmrnbEncoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/AmrnbEncoderTest-1.0/
+adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/AmrnbEncoderTest-2.0/
 ```
 Alternatively, the test can also be run using atest command.
 
diff --git a/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp b/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
index 2cc88ce..c0e032f 100644
--- a/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
+++ b/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
@@ -23,6 +23,7 @@
 #include <audio_utils/sndfile.h>
 #include <memory>
 #include <stdio.h>
+#include <fstream>
 
 #include "pvamrwbdecoder.h"
 #include "pvamrwbdecoder_api.h"
@@ -44,7 +45,7 @@
 
 static AmrwbDecTestEnvironment *gEnv = nullptr;
 
-class AmrwbDecoderTest : public ::testing::TestWithParam<string> {
+class AmrwbDecoderTest : public ::testing::TestWithParam<std::tuple<string, string>> {
   public:
     AmrwbDecoderTest() : mFpInput(nullptr) {}
 
@@ -59,6 +60,7 @@
     int32_t DecodeFrames(int16_t *decoderCookie, void *decoderBuf, SNDFILE *outFileHandle,
                          int32_t frameCount = INT32_MAX);
     SNDFILE *openOutputFile(SF_INFO *sfInfo);
+    bool compareBinaryFiles(const std::string& refFilePath, const std::string& outFilePath);
 };
 
 SNDFILE *AmrwbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
@@ -120,6 +122,42 @@
     return 0;
 }
 
+bool AmrwbDecoderTest::compareBinaryFiles(const std::string &refFilePath,
+                                          const std::string &outFilePath) {
+    std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+    std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+    assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+    assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+    std::streamsize refFileSize = refFile.tellg();
+    std::streamsize outFileSize = outFile.tellg();
+    if (refFileSize != outFileSize) {
+        ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+               "but output file size = %td bytes", refFileSize, outFileSize);
+        return false;
+    }
+
+    refFile.seekg(0, std::ios::beg);
+    outFile.seekg(0, std::ios::beg);
+    constexpr std::streamsize kBufferSize = 16 * 1024;
+    char refBuffer[kBufferSize];
+    char outBuffer[kBufferSize];
+
+    while (refFile && outFile) {
+        refFile.read(refBuffer, kBufferSize);
+        outFile.read(outBuffer, kBufferSize);
+
+        std::streamsize refBytesRead = refFile.gcount();
+        std::streamsize outBytesRead = outFile.gcount();
+
+        if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+            ALOGE("Error, File content mismatch.");
+            return false;
+        }
+    }
+    return true;
+}
+
 TEST_F(AmrwbDecoderTest, MultiCreateAmrwbDecoderTest) {
     uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
     std::unique_ptr<char[]> decoderBuf(new char[memRequirements]);
@@ -147,7 +185,7 @@
     pvDecoder_AmrWb_Init(&amrHandle, decoderBuf.get(), &decoderCookie);
     ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
 
-    string inputFile = gEnv->getRes() + GetParam();
+    string inputFile = gEnv->getRes() + std::get<0>(GetParam());
     mFpInput = fopen(inputFile.c_str(), "rb");
     ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
 
@@ -160,6 +198,10 @@
     ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
 
     sf_close(outFileHandle);
+    string refFilePath = gEnv->getRes() + std::get<1>(GetParam());
+    ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+    << "Error, Binary file comparison failed: Output file "
+    << OUTPUT_FILE << " does not match the reference file " << refFilePath << ".";
 }
 
 TEST_P(AmrwbDecoderTest, ResetDecoderTest) {
@@ -173,7 +215,7 @@
     pvDecoder_AmrWb_Init(&amrHandle, decoderBuf.get(), &decoderCookie);
     ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
 
-    string inputFile = gEnv->getRes() + GetParam();
+    string inputFile = gEnv->getRes() + std::get<0>(GetParam());
     mFpInput = fopen(inputFile.c_str(), "rb");
     ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
 
@@ -198,8 +240,21 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(AmrwbDecoderTestAll, AmrwbDecoderTest,
-                         ::testing::Values(("bbb_amrwb_1ch_14kbps_16000hz.amrwb"),
-                                           ("bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb")));
+                         ::testing::Values(std::make_tuple(
+                                                "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+                                                "bbb_amrwb_1ch_14kbps_16000hz_ref.pcm"),
+                                           std::make_tuple(
+                                                "bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb",
+                                                "bbb_16000hz_1ch_9kbps_amrwb_30sec_ref.pcm"),
+                                           std::make_tuple(
+                                                "bbb_16kHz_1ch_16bps_1sec.amrwb",
+                                                "bbb_16kHz_1ch_16bps_1sec_ref.pcm"),
+                                           std::make_tuple(
+                                                "bbb_16kHz_1ch_6.6bps_3sec.amrwb",
+                                                "bbb_16kHz_1ch_6.6bps_3sec_ref.pcm"),
+                                           std::make_tuple(
+                                                "bbb_16kHz_1ch_23.85bps_3sec.amrwb",
+                                                "bbb_16kHz_1ch_23.85bps_3sec_ref.pcm")));
 
 int main(int argc, char **argv) {
     gEnv = new AmrwbDecTestEnvironment();
diff --git a/media/module/codecs/amrwb/dec/test/AndroidTest.xml b/media/module/codecs/amrwb/dec/test/AndroidTest.xml
index 392df03..dbd1407 100644
--- a/media/module/codecs/amrwb/dec/test/AndroidTest.xml
+++ b/media/module/codecs/amrwb/dec/test/AndroidTest.xml
@@ -23,17 +23,17 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="host" />
         <option name="config-filename" value="AmrwbDecoderTest" />
-        <option name="version" value="1.0"/>
+        <option name="version" value="2.0"/>
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
-        <option name="media-folder-name" value="AmrwbDecoderTest-1.0" />
+        <option name="media-folder-name" value="AmrwbDecoderTest-2.0" />
         <option name="dynamic-config-module" value="AmrwbDecoderTest" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="AmrwbDecoderTest" />
-        <option name="native-test-flag" value="-P /sdcard/test/AmrwbDecoderTest-1.0/" />
+        <option name="native-test-flag" value="-P /sdcard/test/AmrwbDecoderTest-2.0/" />
     </test>
 </configuration>
diff --git a/media/module/codecs/amrwb/dec/test/DynamicConfig.xml b/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
index 506cc3d..52453ee 100644
--- a/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
+++ b/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
 
 <dynamicConfig>
     <entry key="media_files_url">
-            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-1.0.zip</value>
+            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-2.0.zip</value>
     </entry>
 </dynamicConfig>
diff --git a/media/module/codecs/amrwb/dec/test/README.md b/media/module/codecs/amrwb/dec/test/README.md
index 8e77456..ed76051 100644
--- a/media/module/codecs/amrwb/dec/test/README.md
+++ b/media/module/codecs/amrwb/dec/test/README.md
@@ -22,15 +22,15 @@
 adb push ${OUT}/data/nativetest/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-2.0.zip). Download, unzip and push these files into device for testing.
 
 ```
-adb push AmrwbDecoderTest-1.0 /data/local/tmp/
+adb push AmrwbDecoderTest-2.0 /data/local/tmp/
 ```
 
 usage: AmrwbDecoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/AmrwbDecoderTest-1.0/
+adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/AmrwbDecoderTest-2.0/
 ```
 Alternatively, the test can also be run using atest command.
 
diff --git a/media/module/codecs/amrwb/enc/src/az_isp.c b/media/module/codecs/amrwb/enc/src/az_isp.c
index d7074f0..22a5c25 100644
--- a/media/module/codecs/amrwb/enc/src/az_isp.c
+++ b/media/module/codecs/amrwb/enc/src/az_isp.c
@@ -248,10 +248,10 @@
         b1_h = b0_h;
     }
 
-    t0 = ((b1_h * x)<<1) + (((b1_l * x)>>15)<<1);
-    t0 += (b2_h * (-32768))<<1;             /* t0 = x*b1 - b2          */
-    t0 -= (b2_l << 1);
-    t0 += (f[n] << 12);                     /* t0 = x*b1 - b2 + f[i]/2 */
+    __builtin_add_overflow(((b1_h * x)<<1), (((b1_l * x)>>15)<<1), &t0);
+    __builtin_add_overflow(t0, (b2_h * (-32768))<<1, &t0);   /* t0 = x*b1 - b2          */
+    __builtin_sub_overflow(t0, (b2_l << 1), &t0);
+    __builtin_add_overflow(t0, (f[n] << 12), &t0);     /* t0 = x*b1 - b2 + f[i]/2 */
 
     t0 = L_shl2(t0, 6);                     /* Q24 to Q30 with saturation */
 
diff --git a/media/module/codecs/amrwb/enc/src/syn_filt.c b/media/module/codecs/amrwb/enc/src/syn_filt.c
index 7eba12f..40398f5 100644
--- a/media/module/codecs/amrwb/enc/src/syn_filt.c
+++ b/media/module/codecs/amrwb/enc/src/syn_filt.c
@@ -109,38 +109,38 @@
         p2 = &sig_lo[i - 1];
         p3 = &sig_hi[i - 1];
 
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
-        L_tmp  -= vo_mult32((*p2--), (*p1));
-        L_tmp1 -= vo_mult32((*p3--), (*p1++));
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+        __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+        __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
 
         L_tmp = L_tmp >> 11;
         L_tmp += vo_L_mult(exc[i], a0);
diff --git a/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp b/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
index 1a6ee27..dc9c1b1 100644
--- a/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
+++ b/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
@@ -20,6 +20,7 @@
 #include <utils/Log.h>
 
 #include <stdio.h>
+#include <fstream>
 
 #include "cmnMemory.h"
 #include "voAMRWB.h"
@@ -34,13 +35,15 @@
 
 static AmrwbEncTestEnvironment *gEnv = nullptr;
 
-class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, VOAMRWBFRAMETYPE>> {
+class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t,
+                                                               VOAMRWBFRAMETYPE, string>> {
   public:
     AmrwbEncoderTest() : mEncoderHandle(nullptr) {
-        tuple<string, int32_t, VOAMRWBFRAMETYPE> params = GetParam();
+        tuple<string, int32_t, VOAMRWBFRAMETYPE, string> params = GetParam();
         mInputFile = gEnv->getRes() + get<0>(params);
         mMode = get<1>(params);
         mFrameType = get<2>(params);
+        refFilePath = gEnv->getRes() + get<3>(params);
         mMemOperator.Alloc = cmnMemAlloc;
         mMemOperator.Copy = cmnMemCopy;
         mMemOperator.Free = cmnMemFree;
@@ -66,8 +69,47 @@
     VO_CODEC_INIT_USERDATA mUserData;
     VO_HANDLE mEncoderHandle;
     int32_t mMode;
+    string refFilePath;
+
+    bool compareBinaryFiles(const string& refFilePath, const string& outFilePath);
 };
 
+bool AmrwbEncoderTest::compareBinaryFiles(const std::string &refFilePath,
+                                          const std::string &outFilePath) {
+    std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+    std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+    assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+    assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+    std::streamsize refFileSize = refFile.tellg();
+    std::streamsize outFileSize = outFile.tellg();
+    if (refFileSize != outFileSize) {
+        ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+               "but output file size = %td bytes", refFileSize, outFileSize);
+        return false;
+    }
+
+    refFile.seekg(0, std::ios::beg);
+    outFile.seekg(0, std::ios::beg);
+    constexpr std::streamsize kBufferSize = 16 * 1024;
+    char refBuffer[kBufferSize];
+    char outBuffer[kBufferSize];
+
+    while (refFile && outFile) {
+        refFile.read(refBuffer, kBufferSize);
+        outFile.read(outBuffer, kBufferSize);
+
+        std::streamsize refBytesRead = refFile.gcount();
+        std::streamsize outBytesRead = outFile.gcount();
+
+        if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+            ALOGE("Error, File content mismatch.");
+            return false;
+        }
+    }
+    return true;
+}
+
 TEST_P(AmrwbEncoderTest, CreateAmrwbEncoderTest) {
     int32_t status = voGetAMRWBEncAPI(&mApiHandle);
     ASSERT_EQ(status, VO_ERR_NONE) << "Failed to get api handle";
@@ -152,38 +194,69 @@
     if (fpOutput) {
         fclose(fpOutput);
     }
+
+    ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+    << "Error, Binary file comparison failed: Output file "
+    << OUTPUT_FILE << " does not match the reference file " << refFilePath << ".";
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        AmrwbEncoderTestAll, AmrwbEncoderTest,
-        ::testing::Values(
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267),
-                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267)));
+    AmrwbEncoderTestAll, AmrwbEncoderTest,
+    ::testing::Values(
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_DEFAULT_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_ITU_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_RFC3267_ref.amrwb"),
+        make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267,
+                    "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_RFC3267_ref.amrwb")));
 
 int main(int argc, char **argv) {
     gEnv = new AmrwbEncTestEnvironment();
diff --git a/media/module/codecs/amrwb/enc/test/AndroidTest.xml b/media/module/codecs/amrwb/enc/test/AndroidTest.xml
index 8822cb2..1f4121f 100644
--- a/media/module/codecs/amrwb/enc/test/AndroidTest.xml
+++ b/media/module/codecs/amrwb/enc/test/AndroidTest.xml
@@ -23,17 +23,17 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="host" />
         <option name="config-filename" value="AmrwbEncoderTest" />
-        <option name="version" value="1.0"/>
+        <option name="version" value="2.0"/>
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
-        <option name="media-folder-name" value="AmrwbEncoderTest-1.0" />
+        <option name="media-folder-name" value="AmrwbEncoderTest-2.0" />
         <option name="dynamic-config-module" value="AmrwbEncoderTest" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="AmrwbEncoderTest" />
-        <option name="native-test-flag" value="-P /sdcard/test/AmrwbEncoderTest-1.0/" />
+        <option name="native-test-flag" value="-P /sdcard/test/AmrwbEncoderTest-2.0/" />
     </test>
 </configuration>
diff --git a/media/module/codecs/amrwb/enc/test/DynamicConfig.xml b/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
index a0b6218..59701ea 100644
--- a/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
+++ b/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
 
 <dynamicConfig>
     <entry key="media_files_url">
-            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-1.0.zip</value>
+            <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-2.0.zip</value>
     </entry>
 </dynamicConfig>
diff --git a/media/module/codecs/amrwb/enc/test/README.md b/media/module/codecs/amrwb/enc/test/README.md
index 3b9cc39..ea2c31e 100644
--- a/media/module/codecs/amrwb/enc/test/README.md
+++ b/media/module/codecs/amrwb/enc/test/README.md
@@ -22,7 +22,7 @@
 adb push ${OUT}/data/nativetest/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-2.0.zip). Download, unzip and push these files into device for testing.
 
 ```
 adb push AmrwbEncoderTest-1.0 /data/local/tmp/
@@ -30,7 +30,7 @@
 
 usage: AmrwbEncoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTest-1.0/
+adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTest-2.0/
 ```
 Alternatively, the test can also be run using atest command.
 
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 42fd94e..433b5e9 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -790,47 +790,6 @@
     }
 
     using namespace ::android::hardware::media::c2;
-
-    if (!ionPropertiesDefined()) {
-        using IComponentStore =
-            ::android::hardware::media::c2::V1_0::IComponentStore;
-        std::string const preferredStoreName = "default";
-        if (aidlSelected) {
-            std::shared_ptr<c2_aidl::IComponentStore> preferredStore;
-            if (__builtin_available(android __ANDROID_API_S__, *)) {
-                std::string instanceName = ::android::base::StringPrintf(
-                        "%s/%s", c2_aidl::IComponentStore::descriptor, preferredStoreName.c_str());
-                if (AServiceManager_isDeclared(instanceName.c_str())) {
-                    preferredStore = c2_aidl::IComponentStore::fromBinder(::ndk::SpAIBinder(
-                            AServiceManager_waitForService(instanceName.c_str())));
-                }
-            }
-            if (preferredStore) {
-                ::android::SetPreferredCodec2ComponentStore(
-                        std::make_shared<H2C2ComponentStore>(preferredStore));
-                LOG(INFO) <<
-                        "Preferred Codec2 AIDL store is set to \"" <<
-                        preferredStoreName << "\".";
-            } else {
-                LOG(INFO) <<
-                        "Preferred Codec2 AIDL store is defaulted to \"software\".";
-            }
-        } else {
-            sp<IComponentStore> preferredStore =
-                IComponentStore::getService(preferredStoreName.c_str());
-            if (preferredStore) {
-                ::android::SetPreferredCodec2ComponentStore(
-                        std::make_shared<H2C2ComponentStore>(preferredStore));
-                LOG(INFO) <<
-                        "Preferred Codec2 HIDL store is set to \"" <<
-                        preferredStoreName << "\".";
-            } else {
-                LOG(INFO) <<
-                        "Preferred Codec2 HIDL store is defaulted to \"software\".";
-            }
-        }
-    }
-
     bool registered = false;
     const std::string aidlServiceName =
         std::string(c2_aidl::IComponentStore::descriptor) + "/software";
@@ -876,6 +835,48 @@
                      " so it is not being registered with hwservicemanager.";
     }
 
+    // Preferred store must be set after the store is registered to ensure that
+    // the correct preferred store is set.
+    if (!ionPropertiesDefined()) {
+        using IComponentStore =
+            ::android::hardware::media::c2::V1_0::IComponentStore;
+        std::string const preferredStoreName = "default";
+        if (aidlSelected) {
+            std::shared_ptr<c2_aidl::IComponentStore> preferredStore;
+            if (__builtin_available(android __ANDROID_API_S__, *)) {
+                std::string instanceName = ::android::base::StringPrintf(
+                        "%s/%s", c2_aidl::IComponentStore::descriptor, preferredStoreName.c_str());
+                if (AServiceManager_isDeclared(instanceName.c_str())) {
+                    preferredStore = c2_aidl::IComponentStore::fromBinder(::ndk::SpAIBinder(
+                            AServiceManager_waitForService(instanceName.c_str())));
+                }
+            }
+            if (preferredStore) {
+                ::android::SetPreferredCodec2ComponentStore(
+                        std::make_shared<H2C2ComponentStore>(preferredStore));
+                LOG(INFO) <<
+                        "Preferred Codec2 AIDL store is set to \"" <<
+                        preferredStoreName << "\".";
+            } else {
+                LOG(INFO) <<
+                        "Preferred Codec2 AIDL store is defaulted to \"software\".";
+            }
+        } else {
+            sp<IComponentStore> preferredStore =
+                IComponentStore::getService(preferredStoreName.c_str());
+            if (preferredStore) {
+                ::android::SetPreferredCodec2ComponentStore(
+                        std::make_shared<H2C2ComponentStore>(preferredStore));
+                LOG(INFO) <<
+                        "Preferred Codec2 HIDL store is set to \"" <<
+                        preferredStoreName << "\".";
+            } else {
+                LOG(INFO) <<
+                        "Preferred Codec2 HIDL store is defaulted to \"software\".";
+            }
+        }
+    }
+
     if (registered) {
         LOG(INFO) << "Software Codec2 service created and registered.";
     }
diff --git a/media/module/extractors/Android.bp b/media/module/extractors/Android.bp
index f654ecd..e29d3e6 100644
--- a/media/module/extractors/Android.bp
+++ b/media/module/extractors/Android.bp
@@ -28,6 +28,10 @@
         "liblog",
     ],
 
+    static_libs: [
+        "libstagefright_metadatautils",
+    ],
+
     // extractors are expected to run on Q(29)
     min_sdk_version: "29",
     apex_available: [
@@ -56,6 +60,7 @@
                 "libutils",
                 "libmediandk_format",
                 "libmedia_ndkformatpriv",
+                "libstagefright_metadatautils",
             ],
         },
     },
@@ -68,3 +73,21 @@
         ],
     },
 }
+
+aconfig_declarations {
+    name: "android.media.extractor.flags-aconfig",
+    package: "com.android.media.extractor.flags",
+    container: "com.android.media",
+    srcs: ["extractor.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "android.media.extractor.flags-aconfig-cc",
+    aconfig_declarations: "android.media.extractor.flags-aconfig",
+    host_supported: true,
+    min_sdk_version: "29",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+    ],
+}
diff --git a/media/module/extractors/extractor.aconfig b/media/module/extractors/extractor.aconfig
new file mode 100644
index 0000000..c61efa4
--- /dev/null
+++ b/media/module/extractors/extractor.aconfig
@@ -0,0 +1,13 @@
+# Media Extractor flags.
+#
+# !!! Please add flags in alphabetical order. !!!
+package: "com.android.media.extractor.flags"
+container: "com.android.media"
+
+flag {
+    name: "extractor_sniff_midi_optimizations"
+    is_exported: true
+    namespace: "media_extractor"
+    description: "Enable SniffMidi optimizations."
+    bug: "359920208"
+}
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 7a49d8e..3da1589 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -24,6 +24,7 @@
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["frameworks_av_license"],
+    default_team: "trendy_team_android_media_solutions_playback",
 }
 
 cc_defaults {
@@ -131,6 +132,7 @@
         "libstagefright_id3",
         "libstagefright_esds",
         "libmp4extractor",
+        "libstagefright_metadatautils",
     ],
 
     dictionary: "mp4_extractor_fuzzer.dict",
@@ -301,12 +303,18 @@
     ],
 
     static_libs: [
+        "android.media.extractor.flags-aconfig-cc",
+        "libaconfig_storage_read_api_cc",
         "libsonivox",
         "libmedia_midiiowrapper",
         "libmidiextractor",
         "libwatchdog",
     ],
 
+    shared_libs: [
+        "server_configurable_flags",
+    ],
+
     dictionary: "midi_extractor_fuzzer.dict",
 
     host_supported: true,
diff --git a/media/module/extractors/midi/Android.bp b/media/module/extractors/midi/Android.bp
index feabf9e..0eb34fc 100644
--- a/media/module/extractors/midi/Android.bp
+++ b/media/module/extractors/midi/Android.bp
@@ -32,6 +32,8 @@
     ],
 
     static_libs: [
+        "android.media.extractor.flags-aconfig-cc",
+        "libaconfig_storage_read_api_cc",
         "libmedia_midiiowrapper",
         "libsonivoxwithoutjet",
         "libstagefright_foundation",
@@ -40,6 +42,7 @@
 
     shared_libs: [
         "libbase",
+        "server_configurable_flags",
     ],
 
     host_supported: true,
diff --git a/media/module/extractors/midi/MidiExtractor.cpp b/media/module/extractors/midi/MidiExtractor.cpp
index 167cc40..98d7716 100644
--- a/media/module/extractors/midi/MidiExtractor.cpp
+++ b/media/module/extractors/midi/MidiExtractor.cpp
@@ -20,6 +20,7 @@
 
 #include "MidiExtractor.h"
 
+#include <com_android_media_extractor_flags.h>
 #include <media/MidiIoWrapper.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -323,10 +324,97 @@
     return AMediaFormat_copy(meta, mFileMetadata);
 }
 
-// Sniffer
+static bool startsWith(const uint8_t *buf, size_t size, const char *pattern, size_t patternSize) {
+    if (size < patternSize) {
+        return false;
+    }
+    return (memcmp(buf, pattern, patternSize) == 0);
+}
 
-bool SniffMidi(CDataSource *source, float *confidence)
-{
+static bool isValidMThd(const uint8_t *buf, size_t size) {
+    return startsWith(buf, size, "MThd", 4);
+}
+
+static bool isValidXmf(const uint8_t *buf, size_t size) {
+    return startsWith(buf, size, "XMF_", 4);
+}
+
+static bool isValidImelody(const uint8_t *buf, size_t size) {
+    return startsWith(buf, size, "BEGIN:IMELODY", 13);
+}
+
+static bool isValidRtttl(const uint8_t *buf, size_t size) {
+    #define RTTTL_MAX_TITLE_LEN 32
+    // rtttl starts with the following:
+    // <title>:<type>=<value>
+    //
+    // Where:
+    // - <title>: Up to 32 characters
+    // - <type>: Single character indicating:
+    //     'd' for duration
+    //     'o' for octave
+    //     'b' for beats per minute
+    // - <value>: Corresponding value for the type
+    if (size < 4) {
+        return false;
+    }
+    for (size_t i = 0; i < RTTTL_MAX_TITLE_LEN && i < size; i++) {
+        if (buf[i] == ':') {
+            if (i < (size - 3) && buf[i + 2] == '=') {
+                return true;
+            }
+            break;
+        }
+    }
+    return false;
+}
+
+static bool isValidOta(const uint8_t *buf, size_t size) {
+    #define OTA_RINGTONE 0x25
+    #define OTA_SOUND 0x1d
+    #define OTA_UNICODE 0x22
+
+    // ota starts with the following:
+    // <cmdLen><cmd1><cmd2>..<cmdN>
+    //
+    // Where:
+    // - <cmdLen>: Single character command length
+    // - <cmd1>: Single character (OTA_RINGTONE << 1)
+    // - <cmd2>: Single character (OTA_SOUND << 1) or (OTA_UNICODE << 1)
+    //           and so on with last cmd being (0x1d << 1)
+
+    if (size < 3) {
+        return false;
+    }
+
+    uint8_t cmdLen = buf[0];
+    if (cmdLen < 2) {
+        return false;
+    }
+
+    if ((buf[1] >> 1) != OTA_RINGTONE) {
+        return false;
+    }
+    cmdLen--;
+
+    size_t i = 2;
+    while(cmdLen && i < size) {
+        switch(buf[i] >> 1) {
+            case OTA_SOUND:
+                return true;
+            case OTA_UNICODE:
+                break;
+            default:
+                return false;
+        }
+        cmdLen--;
+        i++;
+    }
+
+    return false;
+}
+
+bool SniffMidiLegacy(CDataSource *source, float *confidence) {
     MidiEngine p(source, NULL, NULL);
     if (p.initCheck() == OK) {
         *confidence = 0.8;
@@ -335,7 +423,47 @@
     }
     ALOGV("SniffMidi: no");
     return false;
+}
 
+bool SniffMidiEfficiently(CDataSource *source, float *confidence) {
+    uint8_t header[128];
+    int filled = source->readAt(source->handle, 0, header, sizeof(header));
+
+    if (isValidMThd(header, filled)) {
+        *confidence = 0.80;
+        ALOGV("SniffMidi: yes, MThd");
+        return true;
+    }
+    if (isValidXmf(header, filled)) {
+        *confidence = 0.80;
+        ALOGV("SniffMidi: yes, XMF_");
+        return true;
+    }
+    if (isValidImelody(header, filled)) {
+        *confidence = 0.80;
+        ALOGV("SniffMidi: yes, imelody");
+        return true;
+    }
+    if (isValidRtttl(header, filled)) {
+        *confidence = 0.80;
+        ALOGV("SniffMidi: yes, rtttl");
+        return true;
+    }
+    if (isValidOta(header, filled)) {
+        *confidence = 0.80;
+        ALOGV("SniffMidi: yes, ota");
+        return true;
+    }
+    ALOGV("SniffMidi: no");
+    return false;
+}
+
+// Sniffer
+bool SniffMidi(CDataSource *source, float *confidence) {
+    if(com::android::media::extractor::flags::extractor_sniff_midi_optimizations()) {
+        return SniffMidiEfficiently(source, confidence);
+    }
+    return SniffMidiLegacy(source, confidence);
 }
 
 static const char *extensions[] = {
diff --git a/media/module/extractors/mkv/MatroskaExtractor.cpp b/media/module/extractors/mkv/MatroskaExtractor.cpp
index f326db1..10ae07a 100644
--- a/media/module/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/module/extractors/mkv/MatroskaExtractor.cpp
@@ -1787,7 +1787,7 @@
         return ERROR_MALFORMED;
     }
 
-    if (!MakeVP9CodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) {
+    if (!MakeVP9CodecSpecificDataFromFirstFrame(trackInfo->mMeta, tmpData.get(), frame.len)) {
         return ERROR_MALFORMED;
     }
 
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index f247f8c..12c0aaf 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -51,6 +51,7 @@
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <utils/String8.h>
 
 #include <byteswap.h>
@@ -2596,8 +2597,32 @@
             *offset += chunk_size;
             break;
         }
-
         case FOURCC("vpcC"):
+        {
+            if (mLastTrack == NULL) {
+                return ERROR_MALFORMED;
+            }
+
+            auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+
+            if (buffer.get() == NULL) {
+                ALOGE("b/28471206");
+                return NO_MEMORY;
+            }
+
+            if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+                return ERROR_IO;
+            }
+
+            if (!MakeVP9CodecPrivateFromVpcC(mLastTrack->meta, buffer.get(), chunk_data_size)) {
+                ALOGE("Failed to create VP9 CodecPrivate from vpcC.");
+                return ERROR_MALFORMED;
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
         case FOURCC("av1C"):
         {
             auto buffer = heapbuffer<uint8_t>(chunk_data_size);
diff --git a/media/module/metadatautils/MetaDataUtils.cpp b/media/module/metadatautils/MetaDataUtils.cpp
index 0895bb5..177438a 100644
--- a/media/module/metadatautils/MetaDataUtils.cpp
+++ b/media/module/metadatautils/MetaDataUtils.cpp
@@ -134,10 +134,54 @@
     }
     return true;
 }
+
+/**
+ * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec.
+ * For reference:
+ * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate.
+ *
+ * @param meta          A pointer to AMediaFormat object.
+ * @param profile       The profile value of the VP9 stream.
+ * @param level         The VP9 codec level. If the level is unknown, pass -1 to this parameter.
+ * @param bitDepth      The bit depth of the luma and color components of the VP9 stream.
+ * @param chromaSubsampling  The chroma subsampling of the VP9 stream. If chromaSubsampling is
+ *                           unknown, pass -1 to this parameter.
+ * @return true if CodecPrivate is set as CSD of AMediaFormat object.
+ *
+ */
+static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level,
+                                int32_t bitDepth, int32_t chromaSubsampling) {
+    if (meta == nullptr) {
+        return false;
+    }
+
+    std::vector<uint8_t> codecPrivate;
+    // Construct CodecPrivate in WebM format (ID | Length | Data).
+    // Helper lambda to add a field to the codec private data
+    auto addField = [&codecPrivate](uint8_t id, uint8_t value) {
+        codecPrivate.push_back(id);
+        codecPrivate.push_back(0x01);  // Length is always 1
+        codecPrivate.push_back(value);
+    };
+
+    // Add fields
+    addField(0x01, static_cast<uint8_t>(profile));
+    if (level >= 0) {
+        addField(0x02, static_cast<uint8_t>(level));
+    }
+    addField(0x03, static_cast<uint8_t>(bitDepth));
+    if (chromaSubsampling >= 0) {
+        addField(0x04, static_cast<uint8_t>(chromaSubsampling));
+    }
+    // Set CSD in the meta format
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size());
+    return true;
+}
+
 // The param data contains the first frame data, starting with the uncompressed frame
 // header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is
 // used to parse profile, bitdepth and subsampling.
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size) {
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) {
     if (meta == nullptr || data == nullptr || size == 0) {
         return false;
     }
@@ -227,29 +271,29 @@
     if (chromaSubsampling != -1) {
         csdSize += 3;
     }
+    // As level is not present in first frame build CodecPrivate without it.
+    return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling);
+}
 
-    // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed
-    // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
-    sp<ABuffer> csd = sp<ABuffer>::make(csdSize);
-    uint8_t* csdData = csd->data();
-
-    *csdData++ = 0x01 /* FEATURE PROFILE */;
-    *csdData++ = 0x01 /* length */;
-    *csdData++ = profile;
-
-    *csdData++ = 0x03 /* FEATURE BITDEPTH */;
-    *csdData++ = 0x01 /* length */;
-    *csdData++ = bitDepth;
-
-    // csdSize more than 6 means chroma subsampling data was found.
-    if (csdSize > 6) {
-        *csdData++ = 0x04 /* FEATURE SUBSAMPLING */;
-        *csdData++ = 0x01 /* length */;
-        *csdData++ = chromaSubsampling;
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) {
+    if (meta == nullptr || csdData == nullptr || size < 12) {
+        return false;
     }
 
-    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd->data(), csd->size());
-    return true;
+    // Check the first 4 bytes (VersionAndFlags) if they match the required value.
+    if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) {
+        return false;
+    }
+
+    // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed.
+    // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
+    const uint8_t* vpcCData = csdData + 4;  // Skip the first 4 bytes (VersionAndFlags)
+
+    int32_t profile = vpcCData[0];
+    int32_t level = vpcCData[1];
+    int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F;           // Bit Depth (4 bits).
+    int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07;  // Chroma Subsampling (3 bits).
+    return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling);
 }
 
 bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
diff --git a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
index 69cf21a..9988544 100644
--- a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
+++ b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
@@ -38,7 +38,10 @@
 void parseVorbisComment(
         AMediaFormat *fileMeta, const char *comment, size_t commentLength);
 
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecSpecificData(AMediaFormat* meta, int32_t csdSize, int32_t profile, int32_t level,
+                              int32_t bitDepth, int32_t chromaSubsampling);
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* data, size_t size);
 
 }  // namespace android
 
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 979edab..26e5ddf 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -20,7 +20,6 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <memory>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -298,9 +297,11 @@
 
 void MtpFfsHandle::close() {
     // Join all child threads before destruction
-    for (auto& thread : mChildThreads) {
-        thread.join();
+    int count = mChildThreads.size();
+    for (int i = 0; i < count; i++) {
+        mChildThreads[i].join();
     }
+    mChildThreads.clear();
 
     io_destroy(mCtx);
     closeEndpoints();
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 3d873df..b250a03 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -52,9 +52,6 @@
     symbol_file: "libmediandk.map.txt",
     first_version: "21",
     unversioned_until: "current",
-    export_header_libs: [
-        "libmediandk_headers",
-    ],
 }
 
 ndk_headers {
diff --git a/media/psh_utils/Android.bp b/media/psh_utils/Android.bp
index 4662db8..dafa63b 100644
--- a/media/psh_utils/Android.bp
+++ b/media/psh_utils/Android.bp
@@ -19,18 +19,23 @@
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
     srcs: [
+        "AudioPowerManager.cpp",
+        "AudioToken.cpp",
         "HealthStats.cpp",
         "HealthStatsProvider.cpp",
+        "PowerClientStats.cpp",
         "PowerStats.cpp",
         "PowerStatsCollector.cpp",
         "PowerStatsProvider.cpp",
     ],
     shared_libs: [
+        "com.android.media.audio-aconfig-cc",
         "libaudioutils",
         "libbase",
         "libbinder_ndk",
         "libcutils",
         "liblog",
+        "libmediautils",
         "libutils",
     ],
     cflags: [
diff --git a/media/psh_utils/AudioPowerManager.cpp b/media/psh_utils/AudioPowerManager.cpp
new file mode 100644
index 0000000..3ae681a
--- /dev/null
+++ b/media/psh_utils/AudioPowerManager.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AudioToken.h"
+#define LOG_TAG "AudioPowerManager"
+#include <com_android_media_audioserver.h>
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <psh_utils/AudioPowerManager.h>
+
+namespace android::media::psh_utils {
+
+/* static */
+AudioPowerManager& AudioPowerManager::getAudioPowerManager() {
+    [[clang::no_destroy]] static AudioPowerManager apm;
+    return apm;
+}
+
+std::unique_ptr<Token> AudioPowerManager::startClient(pid_t pid, uid_t uid,
+        const std::string& additional) {
+    std::shared_ptr<PowerClientStats> powerClientStats;
+    std::lock_guard l(mMutex);
+    if (mPowerClientStats.count(uid) == 0) {
+        const auto it = mHistoricalClients.find(uid);
+        if (it == mHistoricalClients.end()) {
+            powerClientStats = std::make_shared<PowerClientStats>(uid, additional);
+        } else {
+            powerClientStats = it->second;
+            mHistoricalClients.erase(it);
+        }
+        mPowerClientStats[uid] = powerClientStats;
+    } else {
+        powerClientStats = mPowerClientStats[uid];
+    }
+    powerClientStats->addPid(pid);
+    mPidToUid[pid] = uid;
+    std::unique_ptr<Token> token =
+            std::make_unique<AudioClientToken>(powerClientStats, pid, uid, additional);
+    mOutstandingTokens.emplace(token.get());
+    return token;
+}
+
+std::unique_ptr<Token> AudioPowerManager::startTrack(uid_t uid, const std::string& additional) {
+    std::lock_guard l(mMutex);
+    if (mPowerClientStats.count(uid) == 0) {
+        ALOGW("%s: Cannot find uid: %d", __func__, uid);
+        return {};
+    }
+    auto powerClientStats = mPowerClientStats[uid];
+    std::unique_ptr<Token> token =
+            std::make_unique<AudioTrackToken>(powerClientStats, additional);
+    mOutstandingTokens.emplace(token.get());
+    return token;
+}
+
+std::unique_ptr<Token> AudioPowerManager::startThread(
+        pid_t pid, const std::string& wakeLockName,
+        WakeFlag wakeFlag, const std::string& additional) {
+    std::lock_guard l(mMutex);
+    std::unique_ptr<Token> token =
+            std::make_unique<AudioThreadToken>(pid, wakeLockName, wakeFlag, additional);
+    mOutstandingTokens.emplace(token.get());
+    return token;
+}
+
+std::string AudioPowerManager::toString() const {
+    const std::string prefix("  ");
+    std::string result;
+    std::lock_guard l(mMutex);
+    result.append("Power Tokens:\n");
+    std::vector<std::string> tokenInfo;
+    for (const auto& token: mOutstandingTokens) {
+        tokenInfo.emplace_back(token->toString());
+    }
+    std::sort(tokenInfo.begin(), tokenInfo.end());
+    for (const auto& info: tokenInfo) {
+        result.append(prefix).append(info).append("\n");
+    }
+    result.append("Power Clients:\n");
+    for (const auto& [uid, powerClientStats]: mPowerClientStats) {
+        result.append(powerClientStats->toString(true, prefix));
+    }
+    result.append("Power Client History:\n");
+    for (const auto& [power, powerClientStats]: mHistoricalClients) {
+        result.append(powerClientStats->toString(true, prefix));
+    }
+    return result;
+}
+
+void AudioPowerManager::stopClient(pid_t pid) {
+    std::lock_guard l(mMutex);
+    const auto pidit = mPidToUid.find(pid);
+    if (pidit == mPidToUid.end()) return;
+    const uid_t uid = pidit->second;
+    const auto it = mPowerClientStats.find(uid);
+    if (it == mPowerClientStats.end()) return;
+
+    auto powerClientStats = it->second;
+    size_t count = powerClientStats->removePid(pid);
+    if (count == 0) {
+        mHistoricalClients[uid] = powerClientStats;
+        mPowerClientStats.erase(it);
+        if (mHistoricalClients.size() > kHistory) {
+            mHistoricalClients.erase(mHistoricalClients.begin()); // remove oldest.
+        }
+    }
+    mPidToUid.erase(pid);
+}
+
+void AudioPowerManager::clear_token_ptr(Token* token) {
+    if (token != nullptr) {
+        std::lock_guard l(mMutex);
+        (void)mOutstandingTokens.erase(token);
+    }
+}
+
+/* static */
+bool AudioPowerManager::enabled() {
+    static const bool enabled = com::android::media::audioserver::power_stats()
+            && property_get_bool("persist.audio.power_stats.enabled", false);
+    return enabled;
+}
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/AudioToken.cpp b/media/psh_utils/AudioToken.cpp
new file mode 100644
index 0000000..f7bf382
--- /dev/null
+++ b/media/psh_utils/AudioToken.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioToken"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+#include "AudioToken.h"
+#include <psh_utils/AudioPowerManager.h>
+
+namespace android::media::psh_utils {
+
+/* static */
+constinit std::atomic<size_t> AudioClientToken::sIdCounter{};
+
+AudioClientToken::AudioClientToken(
+        std::shared_ptr<PowerClientStats> powerClientStats, pid_t pid, uid_t uid,
+        const std::string& additional)
+    : mPowerClientStats(std::move(powerClientStats))
+    , mPid(pid)
+    , mAdditional(additional)
+    , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
+        (void)uid;
+}
+
+AudioClientToken::~AudioClientToken() {
+    auto& apm = AudioPowerManager::getAudioPowerManager();
+
+    // APM has a back pointer to AudioToken, which is accessible on toString().
+    // We first remove ourselves to prevent use after free.
+    apm.clear_token_ptr(this);
+
+    // The client token is released when it is no longer registered with AudioFlinger.
+    // However, it is possible that AudioTrackTokens are still active when the client is released
+    // after crashing and some of its tracks are draining.  Those track tokens also
+    // maintain a pointer to the PowerClientStats keeping that consistent.
+
+    // Stopping the client moves its PowerClientStats from active to historical
+    // if it is the last pid associated with the client uid.
+    apm.stopClient(mPid);
+}
+
+std::string AudioClientToken::toString() const {
+    std::string result("Client-");
+    result.append(std::to_string(mId)).append(": ")
+            .append(" pid: ").append(std::to_string(mPid));
+    if (!mAdditional.empty()) {
+        result.append(" ").append(mAdditional);
+    }
+    return result;
+}
+
+std::unique_ptr<Token> createAudioClientToken(pid_t pid, uid_t uid,
+        const std::string& additional) {
+    return AudioPowerManager::getAudioPowerManager().startClient(pid, uid, additional);
+}
+
+/* static */
+constinit std::atomic<size_t> AudioThreadToken::sIdCounter{};
+
+AudioThreadToken::AudioThreadToken(
+        pid_t tid, const std::string& wakeLockName,
+        WakeFlag wakeFlag, const std::string& additional)
+    : mTid(tid)
+    , mWakeLockName(wakeLockName)
+    , mWakeFlag(wakeFlag)
+    , mAdditional(additional)
+    , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
+}
+
+AudioThreadToken::~AudioThreadToken() {
+    auto& apm = AudioPowerManager::getAudioPowerManager();
+
+    // APM has a back pointer to AudioToken, which is accessible on toString().
+    // We first remove ourselves to prevent use after free.
+    apm.clear_token_ptr(this);
+}
+
+std::string AudioThreadToken::toString() const {
+    std::string result("Thread-");
+    result.append(std::to_string(mId)).append(": ")
+            .append(" ThreadBase-tid: ").append(std::to_string(mTid))
+            .append(" wakeLockName: ").append(mWakeLockName)
+            .append(" wakeFlag: ").append(::android::media::psh_utils::toString(mWakeFlag));
+    if (!mAdditional.empty()) {
+        result.append(" ").append(mAdditional);
+    }
+    return result;
+}
+
+std::unique_ptr<Token> createAudioThreadToken(
+        pid_t pid, const std::string& wakeLockName,
+        WakeFlag wakeFlag, const std::string& additional) {
+    return AudioPowerManager::getAudioPowerManager().startThread(
+            pid, wakeLockName, wakeFlag, additional);
+}
+
+/* static */
+constinit std::atomic<size_t> AudioTrackToken::sIdCounter{};
+
+AudioTrackToken::AudioTrackToken(
+        std::shared_ptr<PowerClientStats> powerClientStats, const std::string& additional)
+    : mPowerClientStats(std::move(powerClientStats))
+    , mAdditional(additional)
+    , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
+        if (mPowerClientStats){
+            mPowerClientStats->getCommandThread().add(
+                    "start",
+                    [pas = mPowerClientStats, actualNs = systemTime(SYSTEM_TIME_BOOTTIME)]() {
+                        pas->start(actualNs);
+                    });
+        }
+}
+
+AudioTrackToken::~AudioTrackToken() {
+    // APM has a back pointer to AudioToken, which is accessible on toString().
+    // We first remove ourselves to prevent use after free.
+    AudioPowerManager::getAudioPowerManager().clear_token_ptr(this);
+    if (mPowerClientStats) {
+        mPowerClientStats->getCommandThread().add(
+                "stop",
+                [pas = mPowerClientStats, actualNs = systemTime(SYSTEM_TIME_BOOTTIME)]() {
+                    pas->stop(actualNs);
+                });
+    }
+}
+
+std::string AudioTrackToken::toString() const {
+    std::string result("Track-");
+    result.append(std::to_string(mId)).append(": ")
+            .append(mPowerClientStats ? mPowerClientStats->toString() : std::string("null"));
+    if (!mAdditional.empty()) {
+        result.append(" ").append(mAdditional);
+    }
+    return result;
+}
+
+std::unique_ptr<Token> createAudioTrackToken(uid_t uid, const std::string& additional) {
+    return AudioPowerManager::getAudioPowerManager().startTrack(uid, additional);
+}
+
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/AudioToken.h b/media/psh_utils/AudioToken.h
new file mode 100644
index 0000000..aa25b04
--- /dev/null
+++ b/media/psh_utils/AudioToken.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <psh_utils/PowerClientStats.h>
+#include <psh_utils/Token.h>
+
+#include <atomic>
+#include <memory>
+#include <string>
+
+namespace android::media::psh_utils {
+
+class AudioClientToken : public Token {
+public:
+    AudioClientToken(std::shared_ptr<PowerClientStats> powerClientStats, pid_t pid, uid_t uid,
+             const std::string& additional);
+    ~AudioClientToken() override;
+
+    // AudioPowerManager may call toString() while AudioToken is in its dtor.
+    // It is safe so long as toString is final.
+    std::string toString() const final;
+
+private:
+    const std::shared_ptr<PowerClientStats> mPowerClientStats;
+    const pid_t mPid;
+    const std::string mAdditional;
+    const size_t mId;
+    static constinit std::atomic<size_t> sIdCounter;
+};
+
+class AudioThreadToken : public Token {
+public:
+    AudioThreadToken(
+            pid_t tid, const std::string& wakeLockName,
+            WakeFlag wakeFlag, const std::string& additional);
+    ~AudioThreadToken() override;
+
+    // AudioPowerManager may call toString() while AudioToken is in its dtor.
+    // It is safe so long as toString is final.
+    std::string toString() const final;
+
+private:
+    const pid_t mTid;
+    const std::string mWakeLockName;
+    const WakeFlag mWakeFlag;
+    const std::string mAdditional;
+    const size_t mId;
+    static constinit std::atomic<size_t> sIdCounter;
+};
+
+class AudioTrackToken : public Token {
+public:
+    AudioTrackToken(
+            std::shared_ptr<PowerClientStats> powerClientStats, const std::string& additional);
+    ~AudioTrackToken() override;
+
+    // AudioPowerManager may call toString() while AudioToken is in its dtor.
+    // It is safe so long as toString is final.
+    std::string toString() const final;
+
+private:
+    const std::shared_ptr<PowerClientStats> mPowerClientStats;
+    const std::string mAdditional;
+    const size_t mId;
+    static constinit std::atomic<size_t> sIdCounter;
+};
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/PowerClientStats.cpp b/media/psh_utils/PowerClientStats.cpp
new file mode 100644
index 0000000..65f65a44
--- /dev/null
+++ b/media/psh_utils/PowerClientStats.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <psh_utils/PowerClientStats.h>
+#include <mediautils/ServiceUtilities.h>
+
+namespace android::media::psh_utils {
+
+/* static */
+audio_utils::CommandThread& PowerClientStats::getCommandThread() {
+    [[clang::no_destroy]] static audio_utils::CommandThread ct;
+    return ct;
+}
+
+PowerClientStats::PowerClientStats(uid_t uid, const std::string& additional)
+        : mUid(uid), mAdditional(additional) {}
+
+void PowerClientStats::start(int64_t actualNs) {
+    std::lock_guard l(mMutex);
+    ++mTokenCount;
+    if (mStartNs == 0) mStartNs = actualNs;
+    if (mStartStats) return;
+    mStartStats = PowerStatsCollector::getCollector().getStats(kStatTimeToleranceNs);
+}
+
+void PowerClientStats::stop(int64_t actualNs) {
+    std::lock_guard l(mMutex);
+    if (--mTokenCount > 0) return;
+    if (mStartNs != 0) mCumulativeNs += actualNs - mStartNs;
+    mStartNs = 0;
+    if (!mStartStats) return;
+    const auto stopStats = PowerStatsCollector::getCollector().getStats(kStatTimeToleranceNs);
+    if (stopStats && stopStats != mStartStats) {
+        *mCumulativeStats += *stopStats - *mStartStats;
+    }
+    mStartStats.reset();
+}
+
+void PowerClientStats::addPid(pid_t pid) {
+    std::lock_guard l(mMutex);
+    mPids.emplace(pid);
+}
+
+size_t PowerClientStats::removePid(pid_t pid) {
+    std::lock_guard l(mMutex);
+    mPids.erase(pid);
+    return mPids.size();
+}
+
+std::string PowerClientStats::toString(bool stats, const std::string& prefix) const {
+    std::lock_guard l(mMutex);
+
+    // Adjust delta time and stats if currently running.
+    auto cumulativeStats = mCumulativeStats;
+    auto cumulativeNs = mCumulativeNs;
+    if (mStartNs) cumulativeNs += systemTime(SYSTEM_TIME_BOOTTIME) - mStartNs;
+    if (mStartStats) {
+        const auto stopStats = PowerStatsCollector::getCollector().getStats(kStatTimeToleranceNs);
+        if (stopStats && stopStats != mStartStats) {
+            auto newStats = std::make_shared<PowerStats>(*cumulativeStats);
+            *newStats += *stopStats - *mStartStats;
+            cumulativeStats = newStats;
+        }
+    }
+
+    std::string result(prefix);
+    result.append("uid: ")
+            .append(std::to_string(mUid))
+            .append(" ").append(mediautils::UidInfo::getInfo(mUid)->package)
+            .append(" streams: ").append(std::to_string(mTokenCount))
+            .append(" seconds: ").append(std::to_string(cumulativeNs * 1e-9));
+    result.append(" {");
+    for (auto pid : mPids) {
+        result.append(" ").append(std::to_string(pid));
+    }
+    result.append(" }");
+    if (!mAdditional.empty()) {
+        result.append("\n").append(prefix).append(mAdditional);
+    }
+    if (stats) {
+        std::string prefix2(prefix);
+        prefix2.append("  ");
+        result.append("\n").append(cumulativeStats->normalizedEnergy(prefix2));
+    }
+    return result;
+}
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/benchmarks/Android.bp b/media/psh_utils/benchmarks/Android.bp
index 20efaa9..2382c69 100644
--- a/media/psh_utils/benchmarks/Android.bp
+++ b/media/psh_utils/benchmarks/Android.bp
@@ -17,14 +17,15 @@
         "-Werror",
     ],
     static_libs: [
-        "libaudioutils",
         "libpshutils",
     ],
     shared_libs: [
+        "libaudioutils",
         "libbase",
         "libbinder_ndk",
         "libcutils",
         "liblog",
+        "libmediautils",
         "libutils",
     ],
 }
@@ -38,14 +39,37 @@
         "-Werror",
     ],
     static_libs: [
-        "libaudioutils",
         "libpshutils",
     ],
     shared_libs: [
+        "libaudioutils",
         "libbase",
         "libbinder_ndk",
         "libcutils",
         "liblog",
+        "libmediautils",
+        "libutils",
+    ],
+}
+
+cc_benchmark {
+    name: "audio_token_benchmark",
+
+    srcs: ["audio_token_benchmark.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "libpshutils",
+    ],
+    shared_libs: [
+        "libaudioutils",
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libmediautils",
         "libutils",
     ],
 }
diff --git a/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp b/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp
index d3f815c..4d8b224 100644
--- a/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp
+++ b/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp
@@ -26,6 +26,140 @@
 #include <thread>
 #include <vector>
 
+/*
+Pixel 9 XL Pro
+---------------------------------------------------------------------------------------------------------------
+Benchmark                                               Time                        CPU              Iteration
+---------------------------------------------------------------------------------------------------------------
+audio_powerstats_benchmark:
+  #MemoryFixture/CacheAccess/64/0/0/1             5.195761589711465 ns       5.183635029038574 ns    135160912
+  #MemoryFixture/CacheAccess/128/0/0/1            10.37270431027728 ns      10.341754343667125 ns     67574354
+  #MemoryFixture/CacheAccess/256/0/0/1           20.767353363364098 ns      20.708496782017836 ns     33809541
+  #MemoryFixture/CacheAccess/512/0/0/1            41.53473855852046 ns       41.45724926375999 ns     16900399
+  #MemoryFixture/CacheAccess/1024/0/0/1           82.89673650172568 ns       82.68064919937272 ns      8462177
+  #MemoryFixture/CacheAccess/2048/0/0/1          165.77648929323732 ns      165.45127650324827 ns      4227878
+  #MemoryFixture/CacheAccess/4096/0/0/1           331.9272979248067 ns       331.0722959129879 ns      2114919
+  #MemoryFixture/CacheAccess/8192/0/0/1           663.8090302013887 ns       662.2813002594532 ns      1054528
+  #MemoryFixture/CacheAccess/16384/0/0/1         1327.4224893455748 ns      1324.0114138292752 ns       529095
+  #MemoryFixture/CacheAccess/32768/0/0/1         2657.1037276954685 ns      2651.8974883509522 ns       263970
+  #MemoryFixture/CacheAccess/65536/0/0/1          5314.170125835522 ns        5305.20127734871 ns       131679
+  #MemoryFixture/CacheAccess/131072/0/0/1        10624.517848490625 ns      10602.467739493763 ns        66056
+  #MemoryFixture/CacheAccess/262144/0/0/1         21271.09560700047 ns      21224.851075464823 ns        32916
+  #MemoryFixture/CacheAccess/524288/0/0/1         42556.76641626909 ns       42444.65628786041 ns        16508
+  #MemoryFixture/CacheAccess/1048576/0/0/1         85440.6313100312 ns       85076.15703685701 ns         8221
+  #MemoryFixture/CacheAccess/2097152/0/0/1       170908.37391089948 ns      169402.58059051324 ns         4132
+  #MemoryFixture/CacheAccess/4194304/0/0/1        373635.4350000207 ns      372955.40777777723 ns         1800
+  #MemoryFixture/CacheAccess/8388608/0/0/1        685101.2127660838 ns       681594.2330754338 ns         1034
+  #MemoryFixture/CacheAccess/16777216/0/0/1       1588009.158696047 ns      1581510.0217391246 ns          460
+  #MemoryFixture/CacheAccess/33554432/0/0/1      2721626.5387591715 ns       2708149.166666674 ns          258
+  #MemoryFixture/CacheAccess/67108864/0/0/1       5433705.728680161 ns       5413515.914728661 ns          129
+  #MemoryFixture/CacheAccess/64/1/0/1             5.201213751848433 ns       5.180967321755995 ns    135673202
+  #MemoryFixture/CacheAccess/128/1/0/1           10.386209252693448 ns      10.351378045484042 ns     67486234
+  #MemoryFixture/CacheAccess/256/1/0/1           20.742666405371747 ns      20.686210353062208 ns     33848169
+  #MemoryFixture/CacheAccess/512/1/0/1            41.52781367071582 ns        41.4438085044977 ns     16870391
+  #MemoryFixture/CacheAccess/1024/1/0/1           83.03849985460687 ns        82.6732197351271 ns      8442915
+  #MemoryFixture/CacheAccess/2048/1/0/1          166.02706801365886 ns      165.60695561393828 ns      4226169
+  #MemoryFixture/CacheAccess/4096/1/0/1          332.05696890075365 ns       331.3395040136246 ns      2112679
+  #MemoryFixture/CacheAccess/8192/1/0/1           664.3009073119205 ns       662.5811781316487 ns      1055315
+  #MemoryFixture/CacheAccess/16384/1/0/1         1329.0792867154223 ns      1325.0185471435798 ns       527251
+  #MemoryFixture/CacheAccess/32768/1/0/1         2652.9089904482526 ns      2645.5388137876826 ns       264236
+  #MemoryFixture/CacheAccess/65536/1/0/1          5312.635002724743 ns       5300.412875575496 ns       132064
+  #MemoryFixture/CacheAccess/131072/1/0/1        10625.299202810635 ns      10594.376178351697 ns        65982
+  #MemoryFixture/CacheAccess/262144/1/0/1        21270.763359464152 ns      21206.192921372138 ns        33029
+  #MemoryFixture/CacheAccess/524288/1/0/1         42496.14168177758 ns      42381.692498487435 ns        16530
+  #MemoryFixture/CacheAccess/1048576/1/0/1        85425.34302253627 ns       85063.54206182965 ns         8119
+  #MemoryFixture/CacheAccess/2097152/1/0/1        170961.8011639407 ns      169732.18840931158 ns         4124
+  #MemoryFixture/CacheAccess/4194304/1/0/1       440086.77439029363 ns      439010.07195122127 ns         1640
+  #MemoryFixture/CacheAccess/8388608/1/0/1        677684.5246376056 ns        675888.058937202 ns         1035
+  #MemoryFixture/CacheAccess/16777216/1/0/1      1571417.6297115851 ns      1566423.4922394755 ns          451
+  #MemoryFixture/CacheAccess/33554432/1/0/1       2723418.325581582 ns      2708535.8062015465 ns          258
+  #MemoryFixture/CacheAccess/67108864/1/0/1       5435209.372094963 ns       5413991.821705426 ns          129
+  #MemoryFixture/CacheAccess/64/2/0/1             5.204700890931938 ns       5.183036658664568 ns    135406460
+  #MemoryFixture/CacheAccess/128/2/0/1           10.376355078178406 ns      10.348754235460566 ns     67518337
+  #MemoryFixture/CacheAccess/256/2/0/1           20.726238269323797 ns      20.670377070062745 ns     33834057
+  #MemoryFixture/CacheAccess/512/2/0/1            41.49336362336435 ns       41.38084547087122 ns     16890919
+  #MemoryFixture/CacheAccess/1024/2/0/1           82.96761236822086 ns        82.7676652782051 ns      8440753
+  #MemoryFixture/CacheAccess/2048/2/0/1          165.90277344671065 ns      165.63781837950896 ns      4223301
+  #MemoryFixture/CacheAccess/4096/2/0/1          332.08415463794364 ns      331.07455763248197 ns      2110971
+  #MemoryFixture/CacheAccess/8192/2/0/1            662.569068830069 ns       661.1656746088121 ns      1055382
+  #MemoryFixture/CacheAccess/16384/2/0/1         1327.7767031437843 ns       1324.268331214332 ns       528552
+  #MemoryFixture/CacheAccess/32768/2/0/1          2654.714983405558 ns      2647.9097623853727 ns       264546
+  #MemoryFixture/CacheAccess/65536/2/0/1          5304.774145979664 ns       5290.380748589911 ns       131554
+  #MemoryFixture/CacheAccess/131072/2/0/1          10631.0978039924 ns      10602.125724165107 ns        65938
+  #MemoryFixture/CacheAccess/262144/2/0/1        21258.936606489668 ns      21202.585867458216 ns        33016
+  #MemoryFixture/CacheAccess/524288/2/0/1         42460.85577331506 ns      42355.304775195626 ns        16481
+  #MemoryFixture/CacheAccess/1048576/2/0/1        85428.60153206348 ns       85160.29036964968 ns         8224
+  #MemoryFixture/CacheAccess/2097152/2/0/1       170233.91140170072 ns      169409.06511740564 ns         4131
+  #MemoryFixture/CacheAccess/4194304/2/0/1        402022.9022378908 ns      401018.78327444167 ns         1698
+  #MemoryFixture/CacheAccess/8388608/2/0/1        677677.2908216701 ns       675843.1642512042 ns         1035
+  #MemoryFixture/CacheAccess/16777216/2/0/1      1554294.1339100641 ns       1549490.831533465 ns          463
+  #MemoryFixture/CacheAccess/33554432/2/0/1       2722937.453488912 ns       2709007.093023249 ns          258
+  #MemoryFixture/CacheAccess/67108864/2/0/1      5435791.6511618495 ns       5415184.511627913 ns          129
+  #MemoryFixture/CacheAccess/64/0/2/1             5.198916380394579 ns       5.178607363536682 ns    135270162
+  #MemoryFixture/CacheAccess/128/0/2/1            10.39285189976819 ns      10.361873548918089 ns     67571996
+  #MemoryFixture/CacheAccess/256/0/2/1            20.75920269645178 ns       20.69937217558235 ns     33765810
+  #MemoryFixture/CacheAccess/512/0/2/1            41.51556112567147 ns      41.372342254073665 ns     16947585
+  #MemoryFixture/CacheAccess/1024/0/2/1           82.96516513710067 ns       82.78508396196703 ns      8459485
+  #MemoryFixture/CacheAccess/2048/0/2/1          166.19624228249646 ns      165.74873814180103 ns      4221552
+  #MemoryFixture/CacheAccess/4096/0/2/1           331.7269469760912 ns      330.91601941885546 ns      2111762
+  #MemoryFixture/CacheAccess/8192/0/2/1           663.8953077112178 ns       662.4540856828183 ns      1059419
+  #MemoryFixture/CacheAccess/16384/0/2/1          1326.843343898467 ns       1323.254749209487 ns       527193
+  #MemoryFixture/CacheAccess/32768/0/2/1         2656.6743123958327 ns      2651.2139933123217 ns       264069
+  #MemoryFixture/CacheAccess/65536/0/2/1          5316.515245822549 ns       5306.343742646622 ns       131741
+  #MemoryFixture/CacheAccess/131072/0/2/1         10623.00981164003 ns      10584.927048634307 ns        66044
+  #MemoryFixture/CacheAccess/262144/0/2/1        21210.760294289023 ns      21148.895028460767 ns        33028
+  #MemoryFixture/CacheAccess/524288/0/2/1         42522.49017237178 ns       42412.58560628969 ns        16535
+  #MemoryFixture/CacheAccess/1048576/0/2/1        86800.15632693251 ns       86501.64057114806 ns         8124
+  #MemoryFixture/CacheAccess/2097152/0/2/1       177705.58147680553 ns      177010.52665832458 ns         3995
+  #MemoryFixture/CacheAccess/4194304/0/2/1        449051.5944408481 ns        448237.065698044 ns         1583
+  #MemoryFixture/CacheAccess/8388608/0/2/1       1389931.2189924652 ns      1386035.8565891527 ns          516
+  #MemoryFixture/CacheAccess/16777216/0/2/1       4438020.074999826 ns       4420751.918750021 ns          160
+  #MemoryFixture/CacheAccess/33554432/0/2/1     1.730178560976084E7 ns    1.7182623121951293E7 ns           41
+  #MemoryFixture/CacheAccess/67108864/0/2/1     5.283456416664952E7 ns     5.258297450000053E7 ns           12
+  #MemoryFixture/CacheAccess/64/1/2/1             5.204121573005314 ns       5.179569988739665 ns    135600170
+  #MemoryFixture/CacheAccess/128/1/2/1           10.387460007442089 ns      10.354541036512236 ns     67512560
+  #MemoryFixture/CacheAccess/256/1/2/1            20.77893771735786 ns      20.727591539055314 ns     33750321
+  #MemoryFixture/CacheAccess/512/1/2/1             41.4739992379063 ns      41.315239742240664 ns     16908639
+  #MemoryFixture/CacheAccess/1024/1/2/1           82.95454097741914 ns        82.7976946763163 ns      8446970
+  #MemoryFixture/CacheAccess/2048/1/2/1          165.86154320354674 ns      165.43862697234525 ns      4233855
+  #MemoryFixture/CacheAccess/4096/1/2/1           331.8942415618145 ns      331.28362462222265 ns      2109704
+  #MemoryFixture/CacheAccess/8192/1/2/1           663.6968508366361 ns        662.640989545053 ns      1057011
+  #MemoryFixture/CacheAccess/16384/1/2/1          1328.002697434852 ns         1325.3893625606 ns       527909
+  #MemoryFixture/CacheAccess/32768/1/2/1          2656.826225607798 ns       2651.831997636693 ns       264032
+  #MemoryFixture/CacheAccess/65536/1/2/1          5313.403312198365 ns      5296.6562514184625 ns       132178
+  #MemoryFixture/CacheAccess/131072/1/2/1        10603.411688232678 ns      10580.430523642488 ns        66152
+  #MemoryFixture/CacheAccess/262144/1/2/1         21213.68814698657 ns       21160.64858647625 ns        33038
+  #MemoryFixture/CacheAccess/524288/1/2/1         42446.96972817497 ns       42358.49900102921 ns        16517
+  #MemoryFixture/CacheAccess/1048576/1/2/1        85427.89922199522 ns       85099.99477267203 ns         8226
+  #MemoryFixture/CacheAccess/2097152/1/2/1       179576.28781830988 ns      178747.97179230847 ns         4006
+  #MemoryFixture/CacheAccess/4194304/1/2/1        453971.4271099782 ns      453200.38874680526 ns         1564
+  #MemoryFixture/CacheAccess/8388608/1/2/1        1413810.749999729 ns      1409767.6830708506 ns          508
+  #MemoryFixture/CacheAccess/16777216/1/2/1       4481396.176099637 ns       4463691.635220161 ns          159
+  #MemoryFixture/CacheAccess/33554432/1/2/1    1.7363190725006916E7 ns    1.7271956449999947E7 ns           40
+  #MemoryFixture/CacheAccess/67108864/1/2/1     5.310257300000861E7 ns     5.283166808333325E7 ns           12
+  #MemoryFixture/CacheAccess/64/2/2/1             5.194585073441566 ns       5.169936491706671 ns    135797225
+  #MemoryFixture/CacheAccess/128/2/2/1           10.375776978615239 ns      10.351150907177248 ns     67504271
+  #MemoryFixture/CacheAccess/256/2/2/1            20.73537619800892 ns      20.682392672592464 ns     33819437
+  #MemoryFixture/CacheAccess/512/2/2/1            41.46680809632523 ns       41.35825233901641 ns     16913944
+  #MemoryFixture/CacheAccess/1024/2/2/1           82.84606240770246 ns        82.6134204462559 ns      8446202
+  #MemoryFixture/CacheAccess/2048/2/2/1          165.87278324509214 ns      165.32429617950757 ns      4232933
+  #MemoryFixture/CacheAccess/4096/2/2/1           331.2406082982817 ns       330.5629607515063 ns      2116922
+  #MemoryFixture/CacheAccess/8192/2/2/1            663.159315900038 ns       661.6959690484747 ns      1056103
+  #MemoryFixture/CacheAccess/16384/2/2/1         1327.5666883524236 ns      1324.3426747207684 ns       528758
+  #MemoryFixture/CacheAccess/32768/2/2/1         2654.9809699966722 ns       2648.132907418347 ns       264372
+  #MemoryFixture/CacheAccess/65536/2/2/1           5314.47981229803 ns       5303.806613499892 ns       131912
+  #MemoryFixture/CacheAccess/131072/2/2/1         10606.19082560071 ns      10585.181869071148 ns        66097
+  #MemoryFixture/CacheAccess/262144/2/2/1        21187.819721722273 ns      21154.040502117125 ns        33060
+  #MemoryFixture/CacheAccess/524288/2/2/1         42442.62465239758 ns       42311.67198645875 ns        16542
+  #MemoryFixture/CacheAccess/1048576/2/2/1        85539.82432104382 ns       85200.15385547924 ns         8248
+  #MemoryFixture/CacheAccess/2097152/2/2/1         180928.070870083 ns      180122.69382093282 ns         3965
+  #MemoryFixture/CacheAccess/4194304/2/2/1       456790.68648981495 ns       455950.1693600544 ns         1547
+  #MemoryFixture/CacheAccess/8388608/2/2/1       1427351.7287124782 ns      1423232.2613861358 ns          505
+  #MemoryFixture/CacheAccess/16777216/2/2/1       4513772.829113805 ns       4495839.088607608 ns          158
+  #MemoryFixture/CacheAccess/33554432/2/2/1    1.7454686475002743E7 ns    1.7364546800000016E7 ns           40
+  #MemoryFixture/CacheAccess/67108864/2/2/1    5.2963768833327174E7 ns     5.266439433333403E7 ns           12
+
+ */
 float result = 0;
 
 using android::media::psh_utils::CoreClass;
diff --git a/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp b/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp
index 9e581bc..021eb5a 100644
--- a/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp
+++ b/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp
@@ -22,16 +22,17 @@
 #include <benchmark/benchmark.h>
 
 /*
- Pixel 8 Pro
+ Pixel 9 Pro XL
+ (tolerance is the amount of time a cached value is valid).
 ------------------------------------------------------------------------------------------
  Benchmark                            Time                      CPU             Iteration
 ------------------------------------------------------------------------------------------
 audio_powerstatscollector_benchmark:
-  #BM_StatsToleranceMs/0      1.2005660120994434E8 ns            2532739.72 ns          100
-  #BM_StatsToleranceMs/50        1281.095987079007 ns     346.0322183913503 ns      2022168
-  #BM_StatsToleranceMs/100       459.9668862534226 ns    189.47902626735942 ns      2891307
-  #BM_StatsToleranceMs/200       233.8438662484292 ns    149.84041813854736 ns      4407343
-  #BM_StatsToleranceMs/500      184.42197142314103 ns    144.86896036787098 ns      7295167
+  #BM_StatsToleranceMs/0      6.346578290999787E7 ns            2069264.56 ns          100
+  #BM_StatsToleranceMs/50      454.12461256065177 ns     203.1644161064639 ns      2615571
+  #BM_StatsToleranceMs/100     167.74983887731364 ns    101.99598388920647 ns      5436852
+  #BM_StatsToleranceMs/200     102.57950838168422 ns     79.40969988086803 ns      7600815
+  #BM_StatsToleranceMs/500      86.87348495571898 ns     75.24841434306252 ns      9789318
 */
 
 // We check how expensive it is to query stats depending
diff --git a/media/psh_utils/benchmarks/audio_token_benchmark.cpp b/media/psh_utils/benchmarks/audio_token_benchmark.cpp
new file mode 100644
index 0000000..47003c0
--- /dev/null
+++ b/media/psh_utils/benchmarks/audio_token_benchmark.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_token_benchmark"
+#include <utils/Log.h>
+
+#include <psh_utils/Token.h>
+
+#include <benchmark/benchmark.h>
+
+/*
+ Pixel 9 Pro XL
+------------------------------------------------------------------------------------------
+ Benchmark                            Time                      CPU             Iteration
+------------------------------------------------------------------------------------------
+audio_token_benchmark:
+  #BM_ClientToken     494.6548907301575 ns     492.4932166101717 ns      1376819
+  #BM_ThreadToken    140.34316175293938 ns    139.91778452790845 ns      5000397
+  #BM_TrackToken      944.0571625384163 ns     893.7912613357879 ns       643096
+*/
+
+static void BM_ClientToken(benchmark::State& state) {
+    constexpr pid_t kPid = 10;
+    constexpr uid_t kUid = 100;
+    while (state.KeepRunning()) {
+        auto token = android::media::psh_utils::createAudioClientToken(
+                kPid, kUid);
+        benchmark::ClobberMemory();
+    }
+}
+
+BENCHMARK(BM_ClientToken);
+
+static void BM_ThreadToken(benchmark::State& state) {
+    constexpr pid_t kTid = 20;
+    constexpr const char* kWakeLockTag = "thread";
+    while (state.KeepRunning()) {
+        auto token = android::media::psh_utils::createAudioThreadToken(
+                kTid, kWakeLockTag);
+        benchmark::ClobberMemory();
+    }
+}
+
+BENCHMARK(BM_ThreadToken);
+
+static void BM_TrackToken(benchmark::State& state) {
+    constexpr pid_t kPid = 10;
+    constexpr uid_t kUid = 100;
+    auto clientToken = android::media::psh_utils::createAudioClientToken(
+                kPid, kUid);
+    while (state.KeepRunning()) {
+        auto token = android::media::psh_utils::createAudioTrackToken(kUid);
+        benchmark::ClobberMemory();
+    }
+}
+
+BENCHMARK(BM_TrackToken);
+
+BENCHMARK_MAIN();
diff --git a/media/psh_utils/include/psh_utils/AudioPowerManager.h b/media/psh_utils/include/psh_utils/AudioPowerManager.h
new file mode 100644
index 0000000..47dfdb2
--- /dev/null
+++ b/media/psh_utils/include/psh_utils/AudioPowerManager.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "PowerClientStats.h"
+#include "PowerStatsCollector.h"
+#include "Token.h"
+
+#include <android-base/thread_annotations.h>
+#include <audio_utils/linked_hash_map.h>
+#include <list>
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android::media::psh_utils {
+
+/**
+ * AudioPowerManager is a singleton class that
+ * serializes the power, wakelock, and performance
+ * messages
+ */
+class AudioPowerManager {
+    friend class AudioClientToken;
+    friend class AudioThreadToken;
+    friend class AudioTrackToken;
+
+public:
+    static AudioPowerManager& getAudioPowerManager();
+
+    /**
+     * Returns a token indicating that a client is started.
+     * This is associated with an application.
+     */
+    std::unique_ptr<Token> startClient(pid_t pid, uid_t uid,
+            const std::string& additional);
+
+    /**
+     * Returns a token that represents a start instance for uid.
+     * This is typically associated with an AudioTrack / AudioRecord start.
+     */
+    std::unique_ptr<Token> startTrack(uid_t uid, const std::string& additional);
+
+    /**
+     * Returns a token that represents a wakelock for a Thread start.
+     */
+    std::unique_ptr<Token> startThread(
+            pid_t pid, const std::string& wakeLockName,
+            WakeFlag wakeFlag, const std::string& additional);
+
+    std::string toString() const;
+
+    static bool enabled();
+
+private:
+    // For AudioToken dtor only.
+    void clear_token_ptr(Token* token);
+    void stopClient(pid_t pid);
+
+    static constexpr size_t kHistory = 6;
+
+    mutable std::mutex mMutex;
+    std::unordered_set<Token *> mOutstandingTokens GUARDED_BY(mMutex);
+    std::unordered_map<pid_t, uid_t> mPidToUid GUARDED_BY(mMutex);
+    std::map<uid_t, std::shared_ptr<PowerClientStats>> mPowerClientStats GUARDED_BY(mMutex);
+    audio_utils::linked_hash_map<uid_t, std::shared_ptr<PowerClientStats>>
+            mHistoricalClients GUARDED_BY(mMutex);
+};
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/include/psh_utils/PowerClientStats.h b/media/psh_utils/include/psh_utils/PowerClientStats.h
new file mode 100644
index 0000000..6e27e41
--- /dev/null
+++ b/media/psh_utils/include/psh_utils/PowerClientStats.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "PowerStats.h"
+#include "PowerStatsCollector.h"
+
+#include <android-base/thread_annotations.h>
+#include <audio_utils/CommandThread.h>
+#include <memory>
+#include <set>
+
+namespace android::media::psh_utils {
+
+/**
+ * PowerClientStats accumulates power measurements based on start and stop events.
+ *
+ * The start and stop events must eventually be matched, but several start events
+ * in a row only results in the power counted once.
+ */
+class PowerClientStats {
+public:
+    // A command thread is used for tokens to dispatch start and stop sequentially
+    // with less overhead to the caller.
+    static audio_utils::CommandThread& getCommandThread();
+
+    /**
+     * Creates an UID based power stat tracker.
+     *
+     * @param uid uid of app
+     * @param additional string to be printed out.
+     */
+    PowerClientStats(uid_t uid, const std::string& additional);
+
+    /**
+     * Starts power tracking.
+     */
+    void start(int64_t actualNs) EXCLUDES(mMutex);
+
+    /**
+     * Stops power tracking (saves the difference) - must be paired with start().
+     */
+    void stop(int64_t actualNs) EXCLUDES(mMutex);
+
+    /**
+     * Adds a pid to the App for string printing.
+     */
+    void addPid(pid_t pid) EXCLUDES(mMutex);
+
+    /**
+     * Removes the pid from the App for string printing.
+     */
+    size_t removePid(pid_t pid) EXCLUDES(mMutex);
+
+    /**
+     * Returns the string info.
+     * @param stats if true returns the stats.
+     * @return stat string.
+     */
+    std::string toString(bool stats = false, const std::string& prefix = {})
+            const EXCLUDES(mMutex);
+
+private:
+    // Snapshots are taken no more often than 500ms.
+    static constexpr int64_t kStatTimeToleranceNs = 500'000'000;
+
+    mutable std::mutex mMutex;
+    const uid_t mUid;
+    const std::string mName;
+    const std::string mAdditional;
+    std::set<pid_t> mPids GUARDED_BY(mMutex); // pids sharing same uid
+    int64_t mTokenCount GUARDED_BY(mMutex) = 0;
+    int64_t mStartNs GUARDED_BY(mMutex) = 0;
+    std::shared_ptr<const PowerStats> mStartStats GUARDED_BY(mMutex);
+
+    // Cumulative time while active: sum of deltas of (stop - start).
+    int64_t mCumulativeNs GUARDED_BY(mMutex) = 0;
+    // Cumulative stats while active: sum of deltas of (stop - start),
+    // where snapshots are quantized to ~500ms accuracy.
+    std::shared_ptr<PowerStats> mCumulativeStats GUARDED_BY(mMutex) =
+            std::make_shared<PowerStats>();
+};
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/include/psh_utils/Token.h b/media/psh_utils/include/psh_utils/Token.h
new file mode 100644
index 0000000..2b52d11
--- /dev/null
+++ b/media/psh_utils/include/psh_utils/Token.h
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android::media::psh_utils {
+
+class Token {
+public:
+    virtual ~Token() = default;
+    virtual std::string toString() const = 0;
+};
+
+// Client tokens (one per Audio Client PID)
+std::unique_ptr<Token> createAudioClientToken(pid_t pid, uid_t uid,
+        const std::string& additional = {});
+
+enum class WakeFlag {
+    kNone = 0,
+    kLowLatency = 1,
+    kLowPower = 2,
+};
+
+inline std::string toString(WakeFlag wakeFlag) {
+    std::string result;
+    for (const auto& [flag, name] : std::initializer_list<std::pair<WakeFlag, std::string>> {
+            {WakeFlag::kLowLatency, "kLowLatency"},
+            {WakeFlag::kLowPower, "kLowPower"},
+        }) {
+        if (static_cast<int>(flag) & static_cast<int>(wakeFlag)) {
+            if (!result.empty()) result.append("|");
+            result.append(name);
+        }
+    }
+    return result;
+}
+
+// Thread tokens (one per ThreadBase PID started).
+std::unique_ptr<Token> createAudioThreadToken(
+        pid_t pid, const std::string& wakeLockName,
+        WakeFlag wakeFlag = WakeFlag::kNone, const std::string& additional = {});
+
+// AudioTrack/AudioRecord tokens.
+std::unique_ptr<Token> createAudioTrackToken(uid_t uid, const std::string& additional = {});
+
+} // namespace android::media::psh_utils
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
index d41a7f9..8f9ee86 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/Android.bp
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -36,8 +36,8 @@
     resource_dirs: ["res"],
 
     libs: [
-        "android.test.runner",
-        "android.test.base",
+        "android.test.runner.stubs.system",
+        "android.test.base.stubs.system",
     ],
 
     jni_libs: [
@@ -69,6 +69,6 @@
 java_defaults {
     name: "MediaBenchmark-defaults",
 
-    min_sdk_version: "29",
-    target_sdk_version: "30",
+    min_sdk_version: "35",
+    target_sdk_version: "35",
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
index 28c2654..bc0c16f 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
@@ -26,7 +26,7 @@
         tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"
         tools:remove="android:appComponentFactory">
     </application>
-    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="31"/>
+    <uses-sdk android:minSdkVersion="35" android:targetSdkVersion="35"/>
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="com.android.media.benchmark"
             android:label="Benchmark Media Test"/>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/build.gradle b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
index a2af701..87fc24c 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/build.gradle
+++ b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
@@ -27,11 +27,11 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 30
+    compileSdkVersion 35
     defaultConfig {
         applicationId "com.android.media.benchmark"
         minSdkVersion 29
-        targetSdkVersion 30
+        targetSdkVersion 35
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
index afd70a3..c68a990 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -46,6 +46,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertEquals;
@@ -118,7 +119,7 @@
     }
 
     @Test(timeout = PER_TEST_TIMEOUT_MS)
-    public void testDecoder() throws IOException {
+    public void testDecoder() throws IOException, InterruptedException {
         File inputFile = new File(mInputFilePath + mInputFile);
         assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
                 inputFile.exists());
@@ -133,7 +134,7 @@
             extractor.selectExtractorTrack(currentTrack);
             MediaFormat format = extractor.getFormat(currentTrack);
             String mime = format.getString(MediaFormat.KEY_MIME);
-            ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+            List<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
             assertTrue("No suitable codecs found for file: " + mInputFile + " track : " +
                     currentTrack + " mime: " + mime, (mediaCodecs.size() > 0));
 
@@ -205,7 +206,7 @@
             extractor.selectExtractorTrack(currentTrack);
             MediaFormat format = extractor.getFormat(currentTrack);
             String mime = format.getString(MediaFormat.KEY_MIME);
-            ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+            List<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
             for (String codecName : mediaCodecs) {
                 Log.i("Test: %s\n", mInputFile);
                 Native nativeDecoder = new Native();
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
index 4202732..4ce5214 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
@@ -50,6 +50,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertEquals;
@@ -150,7 +151,7 @@
     }
 
     @BeforeClass
-    public static void prepareInput() throws IOException {
+    public static void prepareInput() throws IOException, InterruptedException {
 
         mDecodedFileFullHd = new File(mFileDirPath + DECODE_FULLHD_UNPACKED);
         int status = decodeFile(mInputFilePath + DECODE_FULLHD_INPUT, mDecodedFileFullHd);
@@ -165,7 +166,8 @@
         assertEquals("Decoder returned error " + status, 0, status);
     }
 
-    private static int decodeFile(String inputFileName, File outputDecodeFile) throws IOException {
+    private static int decodeFile(String inputFileName, File outputDecodeFile)
+            throws IOException, InterruptedException {
         int status = -1;
         File inputFile = new File(inputFileName);
         assertTrue("Cannot open input file " + inputFileName, inputFile.exists());
@@ -220,7 +222,7 @@
         int status;
         int frameSize;
 
-        ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
+        List<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
         assertTrue("No suitable codecs found for mimetype: " + mMime, (mediaCodecs.size() > 0));
         Boolean[] encodeMode = {true, false};
         // Encoding the decoded input file
@@ -297,7 +299,7 @@
 
     @Test(timeout = PER_TEST_TIMEOUT_MS)
     public void testNativeEncoder() {
-        ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
+        List<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
         assertTrue("No suitable codecs found for mimetype: " + mMime, (mediaCodecs.size() > 0));
         for (String codecName : mediaCodecs) {
             Native nativeEncoder = new Native();
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
index 1e10b37..f223242 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
@@ -5,6 +5,7 @@
 import android.media.MediaFormat;
 import android.os.Build;
 import java.util.ArrayList;
+import java.util.List;
 
 public class CodecUtils {
     private CodecUtils() {}
@@ -15,7 +16,7 @@
      * @param isEncoder Specifies encoder or decoder
      * @return ArrayList of codec names
      */
-    public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
+    public static List<String> selectCodecs(String mimeType, boolean isEncoder) {
         MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
         MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
         ArrayList<String> supportedCodecs = new ArrayList<>();
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
index e947ef6..e9b337d 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -28,7 +28,10 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 import com.android.media.benchmark.library.IBufferXfer;
 
@@ -37,28 +40,28 @@
     private static final boolean DEBUG = false;
     private static final int kQueueDequeueTimeoutUs = 1000;
 
-    private final Object mLock = new Object();
-    private MediaCodec mCodec;
-    private Surface mSurface = null;
-    private boolean mRender = false;
-    private ArrayList<BufferInfo> mInputBufferInfo;
-    private Stats mStats;
-    private String mMime;
+    protected final Object mLock = new Object();
+    protected MediaCodec mCodec;
+    protected Surface mSurface = null;
+    protected boolean mRender = false;
+    protected ArrayList<BufferInfo> mInputBufferInfo;
+    protected Stats mStats;
+    protected String mMime;
 
-    private boolean mSawInputEOS;
-    private boolean mSawOutputEOS;
-    private boolean mSignalledError;
+    protected boolean mSawInputEOS;
+    protected boolean mSawOutputEOS;
+    protected boolean mSignalledError;
 
-    private int mNumInFramesProvided;
-    private int mNumInFramesRequired;
+    protected int mNumInFramesProvided;
+    protected int mNumInFramesRequired;
 
-    private int mNumOutputFrame;
-    private int mIndex;
+    protected int mNumOutputFrame;
+    protected int mIndex;
 
-    private ArrayList<ByteBuffer> mInputBuffer;
-    private FileOutputStream mOutputStream;
-    private FrameReleaseQueue mFrameReleaseQueue = null;
-    private IBufferXfer.ISendBuffer mIBufferSend = null;
+    protected ArrayList<ByteBuffer> mInputBuffer;
+    protected FileOutputStream mOutputStream;
+    protected FrameReleaseQueue mFrameReleaseQueue = null;
+    protected IBufferXfer.ISendBuffer mIBufferSend = null;
 
     /* success for decoder */
     public static final int DECODE_SUCCESS = 0;
@@ -71,7 +74,9 @@
     @Override
     public boolean receiveBuffer(IBufferXfer.BufferXferInfo info) {
         MediaCodec codec = (MediaCodec)info.obj;
-        codec.releaseOutputBuffer(info.idx, mRender);
+        if (info.isComplete) {
+            codec.releaseOutputBuffer(info.idx, mRender);
+        }
         return true;
     }
     @Override
@@ -133,6 +138,49 @@
         }
     }
 
+    protected void setCallback(MediaCodec codec) {
+        codec.setCallback(new MediaCodec.Callback() {
+        @Override
+        public void onInputBufferAvailable(
+                @NonNull MediaCodec mediaCodec, int inputBufferId) {
+            try {
+                mStats.addInputTime();
+                onInputAvailable(inputBufferId, mediaCodec);
+            } catch (Exception e) {
+                e.printStackTrace();
+                Log.e(TAG, e.toString());
+            }
+        }
+
+        @Override
+        public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+                int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+            mStats.addOutputTime();
+            onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+            if (mSawOutputEOS) {
+                synchronized (mLock) { mLock.notify(); }
+            }
+        }
+
+        @Override
+        public void onOutputFormatChanged(
+                @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+            Log.i(TAG, "Output format changed. Format: " + format.toString());
+        }
+
+        @Override
+        public void onError(
+                @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+            mSignalledError = true;
+            Log.e(TAG, "Codec Error: " + e.toString());
+            e.printStackTrace();
+            synchronized (mLock) { mLock.notify(); }
+        }
+    });
+
+
+    }
+
     /**
      * Decodes the given input buffer,
      * provided valid list of buffer info and format are passed as inputs.
@@ -146,9 +194,10 @@
      *         DECODE_CREATE_ERROR for decoder not created
      * @throws IOException if the codec cannot be created.
      */
-    public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
-            @NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
-            @NonNull MediaFormat format, String codecName) throws IOException {
+    public int decode(@NonNull List<ByteBuffer> inputBuffer,
+            @NonNull List<BufferInfo> inputBufferInfo, final boolean asyncMode,
+            @NonNull MediaFormat format, String codecName)
+            throws IOException, InterruptedException {
         mInputBuffer = new ArrayList<>(inputBuffer.size());
         mInputBuffer.addAll(inputBuffer);
         mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
@@ -170,64 +219,34 @@
             mFrameReleaseQueue.setMediaCodec(mCodec);
             mFrameReleaseQueue.setMime(mMime);
         }
+
         if (asyncMode) {
-            mCodec.setCallback(new MediaCodec.Callback() {
-                @Override
-                public void onInputBufferAvailable(
-                        @NonNull MediaCodec mediaCodec, int inputBufferId) {
-                    try {
-                        mStats.addInputTime();
-                        onInputAvailable(inputBufferId, mediaCodec);
-                    } catch (Exception e) {
-                        e.printStackTrace();
-                        Log.e(TAG, e.toString());
-                    }
-                }
-
-                @Override
-                public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
-                        int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
-                    mStats.addOutputTime();
-                    onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
-                    if (mSawOutputEOS) {
-                        synchronized (mLock) { mLock.notify(); }
-                    }
-                }
-
-                @Override
-                public void onOutputFormatChanged(
-                        @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
-                    Log.i(TAG, "Output format changed. Format: " + format.toString());
-                }
-
-                @Override
-                public void onError(
-                        @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
-                    mSignalledError = true;
-                    Log.e(TAG, "Codec Error: " + e.toString());
-                    e.printStackTrace();
-                    synchronized (mLock) { mLock.notify(); }
-                }
-            });
+            setCallback(mCodec);
         }
         int isEncoder = 0;
         if (DEBUG) {
             Log.d(TAG, "Media Format : " + format.toString());
         }
         mCodec.configure(format, mSurface, null, isEncoder);
+
         mCodec.start();
-        Log.i(TAG, "Codec started ");
+        Log.i(TAG, "Codec started async mode ?  " + asyncMode);
         long eTime = mStats.getCurTime();
         mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
         mStats.setStartTime();
         if (asyncMode) {
             try {
-                synchronized (mLock) { mLock.wait(); }
-                if (mSignalledError) {
-                    return DECODE_DECODER_ERROR;
+                synchronized (mLock) {
+                    while (!mSawOutputEOS && !mSignalledError) {
+                        mLock.wait();
+                    }
+                    if (mSignalledError) {
+                        return DECODE_DECODER_ERROR;
+                    }
                 }
             } catch (InterruptedException e) {
-                e.printStackTrace();
+                Log.e(TAG, "Error in waiting");
+                throw e;
             }
         } else {
             while (!mSawOutputEOS && !mSignalledError) {
@@ -319,7 +338,7 @@
         return mCodec.getOutputFormat();
     }
 
-    private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
+    protected void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
         if (inputBufferId >= 0) {
             ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
             BufferInfo bufInfo;
@@ -351,7 +370,7 @@
         }
     }
 
-    private void onOutputAvailable(
+    protected void onOutputAvailable(
             MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
         if (mSawOutputEOS || outputBufferId < 0) {
             return;
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
index 63d17ee..3aa38d1 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -200,7 +200,8 @@
      * @throws IOException If the codec cannot be created.
      */
     public int encode(String codecName, MediaFormat encodeFormat, String mime, int frameRate,
-                      int sampleRate, int frameSize, boolean asyncMode) throws IOException {
+            int sampleRate, int frameSize, boolean asyncMode)
+            throws IOException, InterruptedException {
         mInputBufferSize = (mInputStream != null) ? mInputStream.getChannel().size() : 0;
         mOffset = 0;
         mFrameRate = frameRate;
@@ -275,12 +276,16 @@
         mStats.setStartTime();
         if (asyncMode) {
             try {
-                synchronized (mLock) { mLock.wait(); }
-                if (mSignalledError) {
-                    return ENCODE_ENCODER_ERROR;
+                synchronized (mLock) {
+                    while (!mSawOutputEOS && !mSignalledError) {
+                        mLock.wait();
+                    }
+                    if (mSignalledError) {
+                        return ENCODE_ENCODER_ERROR;
+                    }
                 }
             } catch (InterruptedException e) {
-                e.printStackTrace();
+                throw e;
             }
         } else {
             while (!mSawOutputEOS && !mSignalledError) {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
index f3024e7..1c0f810 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
@@ -76,6 +76,21 @@
     public MediaCodec.BufferInfo getBufferInfo() { return this.mBufferInfo; }
 
     /**
+     * Returns the maximum sample size for the selected track
+     * @return max sample size in the given track
+     */
+    public int getMaxSampleSize() {
+        int size = 0;
+        int maxSampleSize = 0;
+        while ((size = (int) mExtractor.getSampleSize()) != -1) {
+            maxSampleSize = Math.max(maxSampleSize, size);
+            mExtractor.advance();
+        }
+        mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+        return maxSampleSize;
+    }
+
+    /**
      * Returns the duration of the sample
      */
     public long getClipDuration() { return this.mDurationUs; }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
index 90731ed..20a2573 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
@@ -185,7 +185,7 @@
                 try {
                     mCodec.releaseOutputBuffer(curFrameInfo.bufferId, actualRender);
                 } catch (IllegalStateException e) {
-                    e.printStackTrace();
+                    throw(e);
                 }
             });
 
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java
index a75962c..c97a35c 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java
@@ -28,6 +28,7 @@
       public Object obj;
       int flag;
       int bytesRead;
+      boolean isComplete = true;
       long presentationTimeUs;
   }
 
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java
index ab55df5..3e6cee1 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java
@@ -16,9 +16,9 @@
 
 package com.android.media.benchmark.library;
 
-/**
+/*
  * Class that manages the buffer senders
-*/
+ */
 import com.android.media.benchmark.library.IBufferXfer;
 import java.util.ArrayDeque;
 import android.util.Log;
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/MultiAccessUnitDecoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/MultiAccessUnitDecoder.java
new file mode 100644
index 0000000..cb92f06
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/MultiAccessUnitDecoder.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.view.Surface;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.android.media.benchmark.library.IBufferXfer;
+import com.android.media.benchmark.library.Decoder;
+
+public class MultiAccessUnitDecoder extends Decoder {
+    private static final String TAG = "MultiAccessUnitDecoder";
+    private static final boolean DEBUG = false;
+    private final ArrayDeque<BufferInfo> mInputInfos = new ArrayDeque<>();
+
+    @Override
+    public void setCallback(MediaCodec codec) {
+        mCodec.setCallback(new MediaCodec.Callback() {
+            boolean isUsingLargeFrameMode = false;
+
+            @Override
+            public void onInputBufferAvailable(
+                    @NonNull MediaCodec mediaCodec, int inputBufferId) {
+                try {
+                    mStats.addInputTime();
+                    if (isUsingLargeFrameMode) {
+                        onInputsAvailable(inputBufferId, mediaCodec);
+                    } else {
+                        onInputAvailable(inputBufferId, mediaCodec);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    Log.e(TAG, e.toString());
+                }
+            }
+
+            @Override
+            public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+                    int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+                mStats.addOutputTime();
+                onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+                if (mSawOutputEOS) {
+                    synchronized (mLock) { mLock.notify(); }
+                }
+            }
+
+            @Override
+            public void onOutputBuffersAvailable(
+                    @NonNull MediaCodec mediaCodec,
+                            int outputBufferId, @NonNull ArrayDeque<BufferInfo> infos) {
+                int i = 0;
+                while(i++ < infos.size()) {
+                    mStats.addOutputTime();
+                }
+                onOutputsAvailable(mediaCodec, outputBufferId, infos);
+                if (mSawOutputEOS) {
+                    synchronized (mLock) { mLock.notify(); }
+                }
+            }
+
+            @Override
+            public void onOutputFormatChanged(
+                    @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+                Log.i(TAG, "Output format changed. Format: " + format.toString());
+                final int maxOutputSize = format.getNumber(
+                        MediaFormat.KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE, 0).intValue();
+                isUsingLargeFrameMode = (maxOutputSize > 0);
+            }
+
+            @Override
+            public void onError(
+                    @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+                mSignalledError = true;
+                Log.e(TAG, "Codec Error: " + e.toString());
+                e.printStackTrace();
+                synchronized (mLock) { mLock.notify(); }
+            }
+        });
+
+    }
+    /**
+     * Decodes the given input buffer,
+     * provided valid list of buffer info and format are passed as inputs.
+     *
+     * @param inputBuffer     Decode the provided list of ByteBuffers
+     * @param inputBufferInfo List of buffer info corresponding to provided input buffers
+     * @param asyncMode       Will run on async implementation if true
+     * @param format          For creating the decoder if codec name is empty and configuring it
+     * @param codecName       Will create the decoder with codecName
+     * @return DECODE_SUCCESS if decode was successful, DECODE_DECODER_ERROR for fail,
+     *         DECODE_CREATE_ERROR for decoder not created
+     * @throws IOException if the codec cannot be created.
+     */
+    @Override
+    public int decode(@NonNull List<ByteBuffer> inputBuffer,
+            @NonNull List<BufferInfo> inputBufferInfo, final boolean asyncMode,
+            @NonNull MediaFormat format, String codecName)
+            throws IOException, InterruptedException {
+        return super.decode(inputBuffer, inputBufferInfo, asyncMode, format, codecName);
+    }
+
+    private void onInputsAvailable(int inputBufferId, MediaCodec mediaCodec) {
+        if (inputBufferId >= 0) {
+            ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
+            BufferInfo bufInfo;
+            mInputInfos.clear();
+            int offset = 0;
+            while (mNumInFramesProvided < mNumInFramesRequired) {
+                bufInfo = mInputBufferInfo.get(mIndex);
+                mSawInputEOS = (bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+                if (inputCodecBuffer.remaining() < bufInfo.size) {
+                    if (mInputInfos.size() == 0) {
+                        Log.d(TAG, "SampleSize " + inputCodecBuffer.remaining()
+                                + "greater than MediaCodec Buffer size " + bufInfo.size);
+                    }
+                    break;
+                }
+                inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+                bufInfo.offset = offset; offset += bufInfo.size;
+                mInputInfos.add(bufInfo);
+                mNumInFramesProvided++;
+                mIndex = mNumInFramesProvided % (mInputBufferInfo.size() - 1);
+            }
+            if (mNumInFramesProvided >= mNumInFramesRequired) {
+                mIndex = mInputBufferInfo.size() - 1;
+                bufInfo = mInputBufferInfo.get(mIndex);
+                if (inputCodecBuffer.remaining() > bufInfo.size) {
+                    if ((bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) {
+                        Log.e(TAG, "Error in EOS flag for Decoder");
+                    }
+                    mSawInputEOS = (bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+                    inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+                    bufInfo.offset = offset; offset += bufInfo.size;
+                    mInputInfos.add(bufInfo);
+                    mNumInFramesProvided++;
+                }
+            }
+            if (mInputInfos.size() == 0) {
+                Log.d(TAG, " No inputs to queue");
+            } else {
+                mStats.addFrameSize(offset);
+                mediaCodec.queueInputBuffers(inputBufferId, mInputInfos);
+            }
+        }
+    }
+
+    private void onOutputsAvailable(MediaCodec mc, int outputBufferId,
+            ArrayDeque<BufferInfo> infos) {
+        if (mSawOutputEOS || outputBufferId < 0) {
+            return;
+        }
+        Iterator<BufferInfo> iter = infos.iterator();
+        while (iter.hasNext()) {
+            BufferInfo bufferInfo = iter.next();
+            mNumOutputFrame++;
+            if (DEBUG) {
+                Log.d(TAG,
+                        "In OutputBufferAvailable ,"
+                                + " output frame number = " + mNumOutputFrame
+                                + " timestamp = " + bufferInfo.presentationTimeUs
+                                + " size = " + bufferInfo.size);
+            }
+            if (mIBufferSend != null) {
+                IBufferXfer.BufferXferInfo info = new IBufferXfer.BufferXferInfo();
+                info.buf = mc.getOutputBuffer(outputBufferId);
+                info.idx = outputBufferId;
+                info.obj = mc;
+                info.bytesRead = bufferInfo.size;
+                info.presentationTimeUs = bufferInfo.presentationTimeUs;
+                info.flag = bufferInfo.flags;
+                info.isComplete = iter.hasNext() ? false : true;
+                mIBufferSend.sendBuffer(this, info);
+            }
+            mSawOutputEOS |= (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+        }
+        if (mOutputStream != null) {
+            try {
+                ByteBuffer outputBuffer = mc.getOutputBuffer(outputBufferId);
+                byte[] bytesOutput = new byte[outputBuffer.remaining()];
+                outputBuffer.get(bytesOutput);
+                mOutputStream.write(bytesOutput);
+            } catch (IOException e) {
+                e.printStackTrace();
+                Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+            }
+        }
+        if (mIBufferSend == null) {
+            mc.releaseOutputBuffer(outputBufferId, mRender);
+        }
+        if (mSawOutputEOS) {
+            Log.i(TAG, "Large frame - saw output EOS");
+        }
+        // we don't support frame release queue for large audio frame
+    }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
index 340b539..786290d 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
@@ -23,6 +23,7 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.List;
 
 public class Muxer {
     private Stats mStats;
@@ -61,8 +62,8 @@
      * @param inputBufferInfo      Buffer information related to these samples
      * @return Returns Status as 0 if write operation is successful, -1 otherwise
      */
-    public int mux(int trackIndex, ArrayList<ByteBuffer> inputExtractedBuffer,
-                   ArrayList<MediaCodec.BufferInfo> inputBufferInfo) {
+    public int mux(int trackIndex, List<ByteBuffer> inputExtractedBuffer,
+                   List<MediaCodec.BufferInfo> inputBufferInfo) {
         mStats.setStartTime();
         for (int sampleCount = 0; sampleCount < inputExtractedBuffer.size(); sampleCount++) {
             try {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
index 0ebf798..17de1e7 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
@@ -23,6 +23,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Measures Performance.
@@ -88,9 +89,9 @@
 
     public long getStartTime() { return mStartTimeNs; }
 
-    public ArrayList<Long> getOutputTimers() { return mOutputTimer; }
+    public List<Long> getOutputTimers() { return mOutputTimer; }
 
-    public ArrayList<Long> getInputTimers() { return mInputTimer; }
+    public List<Long> getInputTimers() { return mInputTimer; }
 
     public long getTimeDiff(long sTime, long eTime) { return (eTime - sTime); }
 
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index ffcde42..679b111 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "ServiceUtilities"
 
 #include <audio_utils/clock.h>
+#include <android-base/properties.h>
 #include <binder/AppOpsManager.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -28,9 +29,11 @@
 #include <media/AidlConversionUtil.h>
 #include <android/content/AttributionSourceState.h>
 
-#include <iterator>
 #include <algorithm>
+#include <iterator>
+#include <mutex>
 #include <pwd.h>
+#include <thread>
 
 /* When performing permission checks we do not use permission cache for
  * runtime permissions (protection level dangerous) as they may change at
@@ -41,6 +44,10 @@
 
 namespace android {
 
+namespace {
+constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED;
+}
+
 using content::AttributionSourceState;
 
 static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO");
@@ -115,7 +122,7 @@
     return std::optional<AttributionSourceState>{myAttributionSource};
 }
 
-    static bool checkRecordingInternal(const AttributionSourceState &attributionSource,
+    static int checkRecordingInternal(const AttributionSourceState &attributionSource,
                                        const uint32_t virtualDeviceId,
                                        const String16 &msg, bool start, audio_source_t source) {
     // Okay to not track in app ops as audio server or media server is us and if
@@ -138,15 +145,15 @@
     const int32_t attributedOpCode = getOpForSource(source);
 
     permission::PermissionChecker permissionChecker;
-    bool permitted = false;
+    int permitted;
     if (start) {
-        permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
+        permitted = permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
                 sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
-                attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
+                attributedOpCode);
     } else {
-        permitted = (permissionChecker.checkPermissionForPreflightFromDatasource(
+        permitted = permissionChecker.checkPermissionForPreflightFromDatasource(
                 sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
-                attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
+                attributedOpCode);
     }
 
     return permitted;
@@ -156,17 +163,17 @@
 
 bool recordingAllowed(const AttributionSourceState &attributionSource, audio_source_t source) {
     return checkRecordingInternal(attributionSource, DEVICE_ID_DEFAULT, String16(), /*start*/ false,
-                                  source);
+                                  source) != PERMISSION_HARD_DENIED;
 }
 
 bool recordingAllowed(const AttributionSourceState &attributionSource,
                       const uint32_t virtualDeviceId,
                       audio_source_t source) {
     return checkRecordingInternal(attributionSource, virtualDeviceId,
-                                  String16(), /*start*/ false, source);
+                                  String16(), /*start*/ false, source) != PERMISSION_HARD_DENIED;
 }
 
-bool startRecording(const AttributionSourceState& attributionSource,
+int startRecording(const AttributionSourceState& attributionSource,
                     const uint32_t virtualDeviceId,
                     const String16& msg,
                     audio_source_t source) {
@@ -392,6 +399,106 @@
     return NO_ERROR;
 }
 
+// TODO(b/285588444), clean this up on main, but soak it for backporting purposes for now
+namespace {
+class BluetoothPermissionCache {
+    static constexpr auto SYSPROP_NAME = "cache_key.system_server.package_info";
+    const String16 BLUETOOTH_PERM {"android.permission.BLUETOOTH_CONNECT"};
+    mutable std::mutex mLock;
+    // Cached property conditionally defined, since only avail on bionic. On host, don't inval cache
+#if defined(__BIONIC__)
+    // Unlocked, but only accessed from mListenerThread
+    base::CachedProperty mCachedProperty;
+#endif
+    // This thread is designed to never join/terminate, so no signal is fine
+    const std::thread mListenerThread;
+    GUARDED_BY(mLock)
+    std::string mPropValue;
+    GUARDED_BY(mLock)
+    std::unordered_map<uid_t, bool> mCache;
+    PermissionController mPc{};
+public:
+    BluetoothPermissionCache()
+#if defined(__BIONIC__)
+            : mCachedProperty{SYSPROP_NAME},
+            mListenerThread([this]() mutable {
+                    while (true) {
+                        std::string newVal = mCachedProperty.WaitForChange() ?: "";
+                        std::lock_guard l{mLock};
+                        if (newVal != mPropValue) {
+                            ALOGV("Bluetooth permission update");
+                            mPropValue = newVal;
+                            mCache.clear();
+                        }
+                    }
+                })
+#endif
+            {}
+
+    bool checkPermission(uid_t uid, pid_t pid) {
+        std::lock_guard l{mLock};
+        auto it = mCache.find(uid);
+        if (it == mCache.end()) {
+            it = mCache.insert({uid, mPc.checkPermission(BLUETOOTH_PERM, pid, uid)}).first;
+        }
+        return it->second;
+    }
+};
+
+// Don't call this from locks, since it potentially calls up to system server!
+// Check for non-app UIDs above this method!
+bool checkBluetoothPermission(const AttributionSourceState& attr) {
+    [[clang::no_destroy]]  static BluetoothPermissionCache impl{};
+    return impl.checkPermission(attr.uid, attr.pid);
+}
+} // anonymous
+
+/**
+ * Determines if the MAC address in Bluetooth device descriptors returned by APIs of
+ * a native audio service (audio flinger, audio policy) must be anonymized.
+ * MAC addresses returned to system server or apps with BLUETOOTH_CONNECT permission
+ * are not anonymized.
+ *
+ * @param attributionSource The attribution source of the calling app.
+ * @param caller string identifying the caller for logging.
+ * @return true if the MAC addresses must be anonymized, false otherwise.
+ */
+bool mustAnonymizeBluetoothAddress(
+        const AttributionSourceState& attributionSource, const String16&) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    bool res;
+    switch(multiuser_get_app_id(uid)) {
+        case AID_ROOT:
+        case AID_SYSTEM:
+        case AID_RADIO:
+        case AID_BLUETOOTH:
+        case AID_MEDIA:
+        case AID_AUDIOSERVER:
+            // Don't anonymize for privileged clients
+            res = false;
+            break;
+        default:
+            res = !checkBluetoothPermission(attributionSource);
+            break;
+    }
+    ALOGV("%s uid: %d, result: %d", __func__, uid, res);
+    return res;
+}
+
+/**
+ * Modifies the passed MAC address string in place for consumption by unprivileged clients.
+ * the string is assumed to have a valid MAC address format.
+ * the anonymization must be kept in sync with toAnonymizedAddress() in BluetoothUtils.java
+ *
+ * @param address input/output the char string contining the MAC address to anonymize.
+ */
+void anonymizeBluetoothAddress(char *address) {
+    if (address == nullptr || strlen(address) != strlen("AA:BB:CC:DD:EE:FF")) {
+        return;
+    }
+    memcpy(address, "XX:XX:XX:XX", strlen("XX:XX:XX:XX"));
+}
+
 sp<content::pm::IPackageManagerNative> MediaPackageManager::retrievePackageManager() {
     const sp<IServiceManager> sm = defaultServiceManager();
     if (sm == nullptr) {
@@ -473,35 +580,38 @@
     }
 }
 
+namespace mediautils {
+
 // How long we hold info before we re-fetch it (24 hours) if we found it previously.
 static constexpr nsecs_t INFO_EXPIRATION_NS = 24 * 60 * 60 * NANOS_PER_SECOND;
 // Maximum info records we retain before clearing everything.
 static constexpr size_t INFO_CACHE_MAX = 1000;
 
 // The original code is from MediaMetricsService.cpp.
-mediautils::UidInfo::Info mediautils::UidInfo::getInfo(uid_t uid)
+std::shared_ptr<const UidInfo::Info> UidInfo::getCachedInfo(uid_t uid)
 {
+    std::shared_ptr<const UidInfo::Info> info;
+
     const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
-    struct mediautils::UidInfo::Info info;
     {
         std::lock_guard _l(mLock);
         auto it = mInfoMap.find(uid);
         if (it != mInfoMap.end()) {
             info = it->second;
             ALOGV("%s: uid %d expiration %lld now %lld",
-                    __func__, uid, (long long)info.expirationNs, (long long)now);
-            if (info.expirationNs <= now) {
+                    __func__, uid, (long long)info->expirationNs, (long long)now);
+            if (info->expirationNs <= now) {
                 // purge the stale entry and fall into re-fetching
                 ALOGV("%s: entry for uid %d expired, now %lld",
                         __func__, uid, (long long)now);
                 mInfoMap.erase(it);
-                info.uid = (uid_t)-1;  // this is always fully overwritten
+                info.reset();  // force refetch
             }
         }
     }
 
     // if we did not find it in our map, look it up
-    if (info.uid == (uid_t)(-1)) {
+    if (!info) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<content::pm::IPackageManagerNative> package_mgr;
         if (sm.get() == nullptr) {
@@ -586,17 +696,30 @@
         // first clear if we have too many cached elements.  This would be rare.
         if (mInfoMap.size() >= INFO_CACHE_MAX) mInfoMap.clear();
 
-        // always overwrite
-        info.uid = uid;
-        info.package = std::move(pkg);
-        info.installer = std::move(installer);
-        info.versionCode = versionCode;
-        info.expirationNs = now + (notFound ? 0 : INFO_EXPIRATION_NS);
+        info = std::make_shared<const UidInfo::Info>(
+                uid,
+                std::move(pkg),
+                std::move(installer),
+                versionCode,
+                now + (notFound ? 0 : INFO_EXPIRATION_NS));
         ALOGV("%s: adding uid %d package '%s' expirationNs: %lld",
-                __func__, uid, info.package.c_str(), (long long)info.expirationNs);
+                __func__, uid, info->package.c_str(), (long long)info->expirationNs);
         mInfoMap[uid] = info;
     }
     return info;
 }
 
+/* static */
+UidInfo& UidInfo::getUidInfo() {
+    [[clang::no_destroy]] static UidInfo uidInfo;
+    return uidInfo;
+}
+
+/* static */
+std::shared_ptr<const UidInfo::Info> UidInfo::getInfo(uid_t uid) {
+    return UidInfo::getUidInfo().getCachedInfo(uid);
+}
+
+} // namespace mediautils
+
 } // namespace android
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 658191e..6a5bbbe 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -184,6 +184,22 @@
 }
 
 /* static */
+std::string TimeCheck::signalAudioHals() {
+    std::vector<pid_t> pids = getAudioHalPids();
+    std::string halPids;
+    if (pids.size() != 0) {
+        for (const auto& pid : pids) {
+            ALOGI("requesting tombstone for pid: %d", pid);
+            halPids.append(std::to_string(pid)).append(" ");
+            signalAudioHAL(pid);
+        }
+        // Allow time to complete, usually the caller is forcing restart afterwards.
+        sleep(1);
+    }
+    return halPids;
+}
+
+/* static */
 TimerThread& TimeCheck::getTimeCheckThread() {
     static TimerThread sTimeCheckThread{};
     return sTimeCheckThread;
@@ -302,21 +318,14 @@
     // HAL processes which can affect thread behavior.
     const auto snapshotAnalysis = getTimeCheckThread().getSnapshotAnalysis(4 /* retiredCount */);
 
-    // Generate audio HAL processes tombstones and allow time to complete
-    // before forcing restart
-    std::vector<pid_t> pids = TimeCheck::getAudioHalPids();
-    std::string halPids = "HAL pids [ ";
-    if (pids.size() != 0) {
-        for (const auto& pid : pids) {
-            ALOGI("requesting tombstone for pid: %d", pid);
-            halPids.append(std::to_string(pid)).append(" ");
-            signalAudioHAL(pid);
-        }
-        sleep(1);
+    // Generate audio HAL processes tombstones.
+    std::string halPids = signalAudioHals();
+    if (!halPids.empty()) {
+        halPids = "HAL pids [ " + halPids + "]";
     } else {
-        ALOGI("No HAL process pid available, skipping tombstones");
+        halPids = "No HAL process pids available";
+        ALOGI("%s", (halPids + ", skipping tombstones").c_str());
     }
-    halPids.append("]");
 
     LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag.c_str());
 
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index e0fabfd..461e190 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -20,6 +20,7 @@
 #include <unistd.h>
 
 #include <android/content/pm/IPackageManagerNative.h>
+#include <android-base/thread_annotations.h>
 #include <binder/IMemory.h>
 #include <binder/PermissionController.h>
 #include <cutils/multiuser.h>
@@ -91,7 +92,7 @@
 bool recordingAllowed(const AttributionSourceState &attributionSource,
                       uint32_t virtualDeviceId,
                       audio_source_t source);
-bool startRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
+int startRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
                     const String16& msg, audio_source_t source);
 void finishRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
                      audio_source_t source);
@@ -113,6 +114,10 @@
 bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource);
 bool callAudioInterceptionAllowed(const AttributionSourceState& attributionSource);
 void purgePermissionCache();
+bool mustAnonymizeBluetoothAddress(
+        const AttributionSourceState& attributionSource, const String16& caller);
+void anonymizeBluetoothAddress(char *address);
+
 int32_t getOpForSource(audio_source_t source);
 
 AttributionSourceState getCallingAttributionSource();
@@ -167,12 +172,18 @@
      *
      * \param uid is the uid of the app or service.
      */
-    Info getInfo(uid_t uid);
+    std::shared_ptr<const Info> getCachedInfo(uid_t uid);
+
+    /* return a singleton */
+    static UidInfo& getUidInfo();
+
+    /* returns a non-null pointer to a const Info struct */
+    static std::shared_ptr<const Info> getInfo(uid_t uid);
 
 private:
     std::mutex mLock;
     // TODO: use concurrent hashmap with striped lock.
-    std::unordered_map<uid_t, Info> mInfoMap; // GUARDED_BY(mLock)
+    std::unordered_map<uid_t, std::shared_ptr<const Info>> mInfoMap GUARDED_BY(mLock);
 };
 
 } // namespace mediautils
diff --git a/media/utils/include/mediautils/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
index 3e8d35d..c112863 100644
--- a/media/utils/include/mediautils/TimeCheck.h
+++ b/media/utils/include/mediautils/TimeCheck.h
@@ -107,6 +107,7 @@
     static std::string toString();
     static void setAudioHalPids(const std::vector<pid_t>& pids);
     static std::vector<pid_t> getAudioHalPids();
+    static std::string signalAudioHals();
 
   private:
     // Helper class for handling events.
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 264fc4f..01bde42 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -234,6 +234,22 @@
         "libpermission",
     ],
 
+    export_static_lib_headers: [
+        "libpshutils",
+    ],
+
+    shared: {
+        static_libs: [
+            "libpshutils",
+        ],
+    },
+
+    static: {
+        whole_static_libs: [
+            "libpshutils",
+        ],
+    },
+
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 37fc1fc..70fa2ca 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -17,6 +17,8 @@
 
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
 
 // Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
 #define AUDIO_ARRAYS_STATIC_CHECK 1
@@ -24,9 +26,7 @@
 #include "Configuration.h"
 #include "AudioFlinger.h"
 
-//#define BUFLOG_NDEBUG 0
-#include <afutils/BufLog.h>
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
 #include <afutils/NBAIO_Tee.h>
 #include <afutils/Permission.h>
 #include <afutils/PropertyUtils.h>
@@ -66,6 +66,7 @@
 // not needed with the includes above, added to prevent transitive include dependency.
 #include <chrono>
 #include <thread>
+#include <string_view>
 
 // ----------------------------------------------------------------------------
 
@@ -84,6 +85,8 @@
 
 namespace android {
 
+using namespace std::string_view_literals;
+
 using ::android::base::StringPrintf;
 using aidl_utils::statusTFromBinderStatus;
 using media::IEffectClient;
@@ -100,10 +103,10 @@
 static const AudioHalVersionInfo kMaxAAudioPropertyDeviceHalVersion =
         AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 1);
 
-static constexpr char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
-static constexpr char kHardwareLockedString[] = "Hardware lock is taken\n";
-static constexpr char kClientLockedString[] = "Client lock is taken\n";
-static constexpr char kNoEffectsFactory[] = "Effects Factory is absent\n";
+constexpr auto kDeadlockedString = "AudioFlinger may be deadlocked\n"sv;
+constexpr auto kHardwareLockedString = "Hardware lock is taken\n"sv;
+constexpr auto kClientLockedString = "Client lock is taken\n"sv;
+constexpr auto kNoEffectsFactory = "Effects Factory is absent\n"sv;
 
 static constexpr char kAudioServiceName[] = "audio";
 
@@ -114,19 +117,26 @@
 // Keep a strong reference to media.log service around forever.
 // The service is within our parent process so it can never die in a way that we could observe.
 // These two variables are const after initialization.
-static sp<IBinder> sMediaLogServiceAsBinder;
 static sp<IMediaLogService> sMediaLogService;
 
 static pthread_once_t sMediaLogOnce = PTHREAD_ONCE_INIT;
 
 static void sMediaLogInit()
 {
-    sMediaLogServiceAsBinder = defaultServiceManager()->getService(String16("media.log"));
+    auto sMediaLogServiceAsBinder = defaultServiceManager()->getService(String16("media.log"));
     if (sMediaLogServiceAsBinder != 0) {
         sMediaLogService = interface_cast<IMediaLogService>(sMediaLogServiceAsBinder);
     }
 }
 
+static int writeStr(int fd, std::string_view s) {
+    return write(fd, s.data(), s.size());
+}
+
+static int writeStr(int fd, const String8& s) {
+    return write(fd, s.c_str(), s.size());
+}
+
 static error::BinderResult<ValidatedAttributionSourceState>
 validateAttributionFromContextOrTrustedCaller(AttributionSourceState attr,
         const IPermissionProvider& provider) {
@@ -619,6 +629,7 @@
         bool isSpatialized;
         bool isBitPerfect;
         float volume;
+        bool muted;
         ret = AudioSystem::getOutputForAttr(&localAttr, &io,
                                             actualSessionId,
                                             &streamType, adjAttributionSource,
@@ -627,7 +638,8 @@
                                                     AUDIO_OUTPUT_FLAG_DIRECT),
                                             deviceId, &portId, &secondaryOutputs, &isSpatialized,
                                             &isBitPerfect,
-                                            &volume);
+                                            &volume,
+                                            &muted);
         if (ret != NO_ERROR) {
             config->sample_rate = fullConfig.sample_rate;
             config->channel_mask = fullConfig.channel_mask;
@@ -736,42 +748,44 @@
     return NULL;
 }
 
-void AudioFlinger::dumpClients_ll(int fd, const Vector<String16>& args __unused)
-{
+void AudioFlinger::dumpClients_ll(int fd, bool dumpAllocators) {
     String8 result;
 
-    result.append("Client Allocators:\n");
-    for (size_t i = 0; i < mClients.size(); ++i) {
-        sp<Client> client = mClients.valueAt(i).promote();
-        if (client != 0) {
-          result.appendFormat("Client: %d\n", client->pid());
-          result.append(client->allocator().dump().c_str());
+    if (dumpAllocators) {
+        result.append("Client Allocators:\n");
+        for (size_t i = 0; i < mClients.size(); ++i) {
+            sp<Client> client = mClients.valueAt(i).promote();
+            if (client != 0) {
+              result.appendFormat("Client: %d\n", client->pid());
+              result.append(client->allocator().dump().c_str());
+            }
         }
-   }
+    }
 
     result.append("Notification Clients:\n");
     result.append("   pid    uid  name\n");
-    for (size_t i = 0; i < mNotificationClients.size(); ++i) {
-        const pid_t pid = mNotificationClients[i]->getPid();
-        const uid_t uid = mNotificationClients[i]->getUid();
-        const mediautils::UidInfo::Info info = mUidInfo.getInfo(uid);
-        result.appendFormat("%6d %6u  %s\n", pid, uid, info.package.c_str());
+    for (const auto& [ _, client ] : mNotificationClients) {
+        const uid_t uid = client->getUid();
+        const std::shared_ptr<const mediautils::UidInfo::Info> info =
+                mediautils::UidInfo::getInfo(uid);
+        result.appendFormat("%6d %6u  %s\n",
+                client->getPid(), uid, info->package.c_str());
     }
 
     result.append("Global session refs:\n");
     result.append("  session  cnt     pid    uid  name\n");
     for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
         AudioSessionRef *r = mAudioSessionRefs[i];
-        const mediautils::UidInfo::Info info = mUidInfo.getInfo(r->mUid);
+        const std::shared_ptr<const mediautils::UidInfo::Info> info =
+                mediautils::UidInfo::getInfo(r->mUid);
         result.appendFormat("  %7d %4d %7d %6u  %s\n", r->mSessionid, r->mCnt, r->mPid,
-                r->mUid, info.package.c_str());
+                r->mUid, info->package.c_str());
     }
-    write(fd, result.c_str(), result.size());
+    writeStr(fd, result);
 }
 
 
-void AudioFlinger::dumpInternals_l(int fd, const Vector<String16>& args __unused)
-{
+void AudioFlinger::dumpInternals_l(int fd) {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
@@ -779,7 +793,7 @@
 
     snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
     result.append(buffer);
-    write(fd, result.c_str(), result.size());
+    writeStr(fd, result);
 
     dprintf(fd, "Vibrator infos(size=%zu):\n", mAudioVibratorInfos.size());
     for (const auto& vibratorInfo : mAudioVibratorInfos) {
@@ -789,8 +803,43 @@
             mBluetoothLatencyModesEnabled ? "" : "not ");
 }
 
-void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args __unused)
-{
+void AudioFlinger::dumpStats(int fd) {
+    // Dump binder stats
+    dprintf(fd, "\nIAudioFlinger binder call profile:\n");
+    writeStr(fd, getIAudioFlingerStatistics().dump());
+
+    extern mediautils::MethodStatistics<int>& getIEffectStatistics();
+    dprintf(fd, "\nIEffect binder call profile:\n");
+    writeStr(fd, getIEffectStatistics().dump());
+
+    // Automatically fetch HIDL or AIDL statistics.
+    const std::string_view halType = (mDevicesFactoryHal->getHalVersion().getType() ==
+                              AudioHalVersionInfo::Type::HIDL)
+                                     ? METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL
+                                     : METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL;
+    const std::shared_ptr<std::vector<std::string>> halClassNames =
+            mediautils::getStatisticsClassesForModule(halType);
+    if (halClassNames) {
+        for (const auto& className : *halClassNames) {
+            auto stats = mediautils::getStatisticsForClass(className);
+            if (stats) {
+                dprintf(fd, "\n%s binder call profile:\n", className.c_str());
+                writeStr(fd, stats->dump());
+            }
+        }
+    }
+
+    dprintf(fd, "\nTimeCheck:\n");
+    writeStr(fd, mediautils::TimeCheck::toString());
+    dprintf(fd, "\n");
+    // dump mutex stats
+    writeStr(fd, audio_utils::mutex::all_stats_to_string());
+    // dump held mutexes
+    writeStr(fd, audio_utils::mutex::all_threads_to_string());
+
+}
+
+void AudioFlinger::dumpPermissionDenial(int fd) {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
@@ -799,52 +848,102 @@
             IPCThreadState::self()->getCallingPid(),
             IPCThreadState::self()->getCallingUid());
     result.append(buffer);
-    write(fd, result.c_str(), result.size());
+    writeStr(fd, result);
+}
+
+static void dump_printHelp(int fd) {
+    constexpr static auto helpStr =
+            "AudioFlinger dumpsys help options\n"
+            "  -h/--help: Print this help text\n"
+            "  --hal: Include dump of audio hal\n"
+            "  --stats: Include call/lock/watchdog stats\n"
+            "  --effects: Include effect definitions\n"
+            "  --memory: Include memory dump\n"
+            "  -a/--all: Print all except --memory\n"sv;
+
+    write(fd, helpStr.data(), helpStr.length());
 }
 
 status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
-NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
 {
+    using afutils::FallibleLockGuard;
     if (!dumpAllowed()) {
-        dumpPermissionDenial(fd, args);
-    } else {
-        // get state of hardware lock
-        const bool hardwareLocked = afutils::dumpTryLock(hardwareMutex());
-        if (!hardwareLocked) {
-            String8 result(kHardwareLockedString);
-            write(fd, result.c_str(), result.size());
+        dumpPermissionDenial(fd);
+        return NO_ERROR;
+    }
+    // Arg parsing
+    struct {
+        bool shouldDumpMem, shouldDumpStats, shouldDumpHal, shouldDumpEffects;
+    } parsedArgs {}; // zero-init
+
+    for (const auto& arg : args) {
+        const String8 utf8arg{arg};
+        if (utf8arg == "-h" || utf8arg == "--help") {
+            dump_printHelp(fd);
+            return NO_ERROR;
+        }
+        if (utf8arg == "-a" || utf8arg == "--all") {
+            parsedArgs.shouldDumpStats = true;
+            parsedArgs.shouldDumpHal = true;
+            parsedArgs.shouldDumpEffects = true;
+            continue;
+        }
+        if (utf8arg == "--hal") {
+            parsedArgs.shouldDumpHal = true;
+            continue;
+        }
+        if (utf8arg == "--stats") {
+            parsedArgs.shouldDumpStats = true;
+            continue;
+        }
+        if (utf8arg == "--effects") {
+            parsedArgs.shouldDumpEffects = true;
+            continue;
+        }
+        if (utf8arg == "--memory") {
+            parsedArgs.shouldDumpMem = true;
+            continue;
+        }
+        // Unknown arg silently ignored
+    }
+
+    {
+        std::string res;
+        res.reserve(100);
+        res += "Start begin: ";
+        const auto startTimeStr = audio_utils_time_string_from_ns(mStartTime);
+        res += startTimeStr.time;
+        const auto startFinishedTime = getStartupFinishedTime();
+        if (startFinishedTime != 0) {
+            res += "\nStart end:   ";
+            const auto startEndStr = audio_utils_time_string_from_ns(startFinishedTime);
+            res += startEndStr.time;
         } else {
-            hardwareMutex().unlock();
+            res += "\nStartup not yet finished!";
+        }
+        const auto nowTimeStr = audio_utils_time_string_from_ns(audio_utils_get_real_time_ns());
+        res += "\nNow:         ";
+        res += nowTimeStr.time;
+        res += "\n";
+        writeStr(fd, res);
+    }
+    // get state of hardware lock
+    {
+        FallibleLockGuard l{hardwareMutex()};
+        if (!l) writeStr(fd, kHardwareLockedString);
+    }
+    {
+        FallibleLockGuard  l{mutex()};
+        if (!l) writeStr(fd, kDeadlockedString);
+        {
+            FallibleLockGuard ll{clientMutex()};
+            if (!ll) writeStr(fd, kClientLockedString);
+            dumpClients_ll(fd, parsedArgs.shouldDumpMem);
         }
 
-        const bool locked = afutils::dumpTryLock(mutex());
+        dumpInternals_l(fd);
 
-        // failed to lock - AudioFlinger is probably deadlocked
-        if (!locked) {
-            String8 result(kDeadlockedString);
-            write(fd, result.c_str(), result.size());
-        }
-
-        const bool clientLocked = afutils::dumpTryLock(clientMutex());
-        if (!clientLocked) {
-            String8 result(kClientLockedString);
-            write(fd, result.c_str(), result.size());
-        }
-
-        if (mEffectsFactoryHal != 0) {
-            mEffectsFactoryHal->dumpEffects(fd);
-        } else {
-            String8 result(kNoEffectsFactory);
-            write(fd, result.c_str(), result.size());
-        }
-
-        dumpClients_ll(fd, args);
-        if (clientLocked) {
-            clientMutex().unlock();
-        }
-
-        dumpInternals_l(fd, args);
-
+        dprintf(fd, "\n ## BEGIN thread dump \n");
         // dump playback threads
         for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
             mPlaybackThreads.valueAt(i)->dump(fd, args);
@@ -862,130 +961,84 @@
 
         // dump orphan effect chains
         if (mOrphanEffectChains.size() != 0) {
-            write(fd, "  Orphan Effect Chains\n", strlen("  Orphan Effect Chains\n"));
+            writeStr(fd, "  Orphan Effect Chains\n");
             for (size_t i = 0; i < mOrphanEffectChains.size(); i++) {
                 mOrphanEffectChains.valueAt(i)->dump(fd, args);
             }
         }
-        // dump all hardware devs
-        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-            sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
-            dev->dump(fd, args);
-        }
-
-        mPatchPanel->dump(fd);
-
-        mDeviceEffectManager->dump(fd);
-
-        std::string melOutput = mMelReporter->dump();
-        write(fd, melOutput.c_str(), melOutput.size());
+        // dump historical threads in the last 10 seconds
+        writeStr(fd, mThreadLog.dumpToString(
+                "Historical Thread Log ", 0 /* lines */,
+                audio_utils_get_real_time_ns() - 10 * 60 * NANOS_PER_SECOND));
 
         // dump external setParameters
+        dprintf(fd, "\n ## BEGIN setParameters dump \n");
         auto dumpLogger = [fd](SimpleLog& logger, const char* name) {
-            dprintf(fd, "\n%s setParameters:\n", name);
+            dprintf(fd, "\n  %s setParameters:\n", name);
             logger.dump(fd, "    " /* prefix */);
         };
         dumpLogger(mRejectedSetParameterLog, "Rejected");
         dumpLogger(mAppSetParameterLog, "App");
         dumpLogger(mSystemSetParameterLog, "System");
 
-        // dump historical threads in the last 10 seconds
-        const std::string threadLog = mThreadLog.dumpToString(
-                "Historical Thread Log ", 0 /* lines */,
-                audio_utils_get_real_time_ns() - 10 * 60 * NANOS_PER_SECOND);
-        write(fd, threadLog.c_str(), threadLog.size());
 
-        BUFLOG_RESET;
+        dprintf(fd, "\n ## BEGIN misc af dump \n");
+        mPatchPanel->dump(fd);
+        mDeviceEffectManager->dump(fd);
+        writeStr(fd, mMelReporter->dump());
 
-        if (locked) {
-            mutex().unlock();
+        if (media::psh_utils::AudioPowerManager::enabled()) {
+            char value[PROPERTY_VALUE_MAX];
+            property_get("ro.build.display.id", value, "Unknown build");
+            std::string build(value);
+            writeStr(fd, build + "\n");
+            writeStr(fd, media::psh_utils::AudioPowerManager::getAudioPowerManager().toString());
         }
 
-#ifdef TEE_SINK
-        // NBAIO_Tee dump is safe to call outside of AF lock.
-        NBAIO_Tee::dumpAll(fd, "_DUMP");
-#endif
-        // append a copy of media.log here by forwarding fd to it, but don't attempt
-        // to lookup the service if it's not running, as it will block for a second
-        if (sMediaLogServiceAsBinder != 0) {
-            dprintf(fd, "\nmedia.log:\n");
-            sMediaLogServiceAsBinder->dump(fd, args);
-        }
-
-        // check for optional arguments
-        bool dumpMem = false;
-        bool unreachableMemory = false;
-        for (const auto &arg : args) {
-            if (arg == String16("-m")) {
-                dumpMem = true;
-            } else if (arg == String16("--unreachable")) {
-                unreachableMemory = true;
+        if (parsedArgs.shouldDumpEffects) {
+            dprintf(fd, "\n ## BEGIN effects dump \n");
+            if (mEffectsFactoryHal != 0) {
+                mEffectsFactoryHal->dumpEffects(fd);
+            } else {
+                writeStr(fd, kNoEffectsFactory);
             }
         }
 
-        if (dumpMem) {
-            dprintf(fd, "\nDumping memory:\n");
-            std::string s = dumpMemoryAddresses(100 /* limit */);
-            write(fd, s.c_str(), s.size());
-        }
-        if (unreachableMemory) {
-            dprintf(fd, "\nDumping unreachable memory:\n");
-            // TODO - should limit be an argument parameter?
-            std::string s = GetUnreachableMemoryString(true /* contents */, 100 /* limit */);
-            write(fd, s.c_str(), s.size());
-        }
-        {
-            std::string timeCheckStats = getIAudioFlingerStatistics().dump();
-            dprintf(fd, "\nIAudioFlinger binder call profile:\n");
-            write(fd, timeCheckStats.c_str(), timeCheckStats.size());
-
-            extern mediautils::MethodStatistics<int>& getIEffectStatistics();
-            timeCheckStats = getIEffectStatistics().dump();
-            dprintf(fd, "\nIEffect binder call profile:\n");
-            write(fd, timeCheckStats.c_str(), timeCheckStats.size());
-
-            // Automatically fetch HIDL or AIDL statistics.
-            const std::string_view halType = (mDevicesFactoryHal->getHalVersion().getType() ==
-                                      AudioHalVersionInfo::Type::HIDL)
-                                             ? METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL
-                                             : METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL;
-            const std::shared_ptr<std::vector<std::string>> halClassNames =
-                    mediautils::getStatisticsClassesForModule(halType);
-            if (halClassNames) {
-                for (const auto& className : *halClassNames) {
-                    auto stats = mediautils::getStatisticsForClass(className);
-                    if (stats) {
-                        timeCheckStats = stats->dump();
-                        dprintf(fd, "\n%s binder call profile:\n", className.c_str());
-                        write(fd, timeCheckStats.c_str(), timeCheckStats.size());
-                    }
-                }
+        if (parsedArgs.shouldDumpHal) {
+            dprintf(fd, "\n ## BEGIN HAL dump \n");
+            FallibleLockGuard ll{hardwareMutex()};
+            // dump all hardware devs
+            for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+                sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
+                dev->dump(fd, args);
             }
-
-            timeCheckStats = mediautils::TimeCheck::toString();
-            dprintf(fd, "\nTimeCheck:\n");
-            write(fd, timeCheckStats.c_str(), timeCheckStats.size());
-            dprintf(fd, "\n");
         }
-        // dump mutex stats
-        const auto mutexStats = audio_utils::mutex::all_stats_to_string();
-        write(fd, mutexStats.c_str(), mutexStats.size());
+    }  // end af lock
 
-        // dump held mutexes
-        const auto mutexThreadInfo = audio_utils::mutex::all_threads_to_string();
-        write(fd, mutexThreadInfo.c_str(), mutexThreadInfo.size());
+    if (parsedArgs.shouldDumpStats) {
+        dprintf(fd, "\n ## BEGIN stats dump \n");
+        dumpStats(fd);
     }
+
+    if (parsedArgs.shouldDumpMem) {
+        dprintf(fd, "\n ## BEGIN memory dump \n");
+        writeStr(fd, dumpMemoryAddresses(100 /* limit */));
+        dprintf(fd, "\nDumping unreachable memory:\n");
+        // TODO - should limit be an argument parameter?
+        writeStr(fd, GetUnreachableMemoryString(true /* contents */, 100 /* limit */));
+    }
+
     return NO_ERROR;
 }
 
-sp<Client> AudioFlinger::registerPid(pid_t pid)
+sp<Client> AudioFlinger::registerClient(pid_t pid, uid_t uid)
 {
     audio_utils::lock_guard _cl(clientMutex());
     // If pid is already in the mClients wp<> map, then use that entry
     // (for which promote() is always != 0), otherwise create a new entry and Client.
     sp<Client> client = mClients.valueFor(pid).promote();
     if (client == 0) {
-        client = sp<Client>::make(sp<IAfClientCallback>::fromExisting(this), pid);
+        client = sp<Client>::make(sp<IAfClientCallback>::fromExisting(this), pid, uid);
         mClients.add(pid, client);
     }
 
@@ -1052,6 +1105,7 @@
 status_t AudioFlinger::createTrack(const media::CreateTrackRequest& _input,
                                    media::CreateTrackResponse& _output)
 {
+    ATRACE_CALL();
     // Local version of VALUE_OR_RETURN, specific to this method's calling conventions.
     CreateTrackInput input = VALUE_OR_RETURN_STATUS(CreateTrackInput::fromAidl(_input));
     CreateTrackOutput output;
@@ -1065,6 +1119,7 @@
     bool isSpatialized = false;
     bool isBitPerfect = false;
     float volume;
+    bool muted;
 
     audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE;
     std::vector<int> effectIds;
@@ -1125,7 +1180,7 @@
     lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
                                             adjAttributionSource, &input.config, input.flags,
                                             &output.selectedDeviceId, &portId, &secondaryOutputs,
-                                            &isSpatialized, &isBitPerfect, &volume);
+                                            &isSpatialized, &isBitPerfect, &volume, &muted);
 
     if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
         ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus);
@@ -1162,7 +1217,7 @@
             goto Exit;
         }
 
-        client = registerPid(adjAttributionSource.pid);
+        client = registerClient(adjAttributionSource.pid, adjAttributionSource.uid);
 
         IAfPlaybackThread* effectThread = nullptr;
         sp<IAfEffectChain> effectChain = nullptr;
@@ -1182,7 +1237,7 @@
         if (effectThread == nullptr) {
             effectChain = getOrphanEffectChain_l(sessionId);
         }
-        ALOGV("createTrack() sessionId: %d volume: %f", sessionId, volume);
+        ALOGV("createTrack() sessionId: %d volume: %f muted %d", sessionId, volume, muted);
 
         output.sampleRate = input.config.sample_rate;
         output.frameCount = input.frameCount;
@@ -1197,7 +1252,7 @@
                                       input.sharedBuffer, sessionId, &output.flags,
                                       callingPid, adjAttributionSource, input.clientInfo.clientTid,
                                       &lStatus, portId, input.audioTrackCallback, isSpatialized,
-                                      isBitPerfect, &output.afTrackFlags, volume);
+                                      isBitPerfect, &output.afTrackFlags, volume, muted);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
         // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
 
@@ -1621,7 +1676,7 @@
 }
 
 status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
-        audio_io_handle_t output)
+        bool muted, audio_io_handle_t output)
 {
     // check calling permissions
     if (!settingsAllowed()) {
@@ -1643,14 +1698,14 @@
     if (volumeInterface == NULL) {
         return BAD_VALUE;
     }
-    volumeInterface->setStreamVolume(stream, value);
+    volumeInterface->setStreamVolume(stream, value, muted);
 
     return NO_ERROR;
 }
 
 status_t AudioFlinger::setPortsVolume(
-        const std::vector<audio_port_handle_t>& ports, float volume, audio_io_handle_t output)
-{
+        const std::vector<audio_port_handle_t> &ports, float volume, bool muted,
+        audio_io_handle_t output) {
     for (const auto& port : ports) {
         if (port == AUDIO_PORT_HANDLE_NONE) {
             return BAD_VALUE;
@@ -1665,12 +1720,12 @@
     audio_utils::lock_guard lock(mutex());
     IAfPlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread != nullptr) {
-        return thread->setPortsVolume(ports, volume);
+        return thread->setPortsVolume(ports, volume, muted);
     }
     const sp<IAfMmapThread> mmapThread = checkMmapThread_l(output);
     if (mmapThread != nullptr && mmapThread->isOutput()) {
         IAfMmapPlaybackThread *mmapPlaybackThread = mmapThread->asIAfMmapPlaybackThread().get();
-        return mmapPlaybackThread->setPortsVolume(ports, volume);
+        return mmapPlaybackThread->setPortsVolume(ports, volume, muted);
     }
     return BAD_VALUE;
 }
@@ -2162,24 +2217,22 @@
 
 void AudioFlinger::registerClient(const sp<media::IAudioFlingerClient>& client)
 {
-    audio_utils::lock_guard _l(mutex());
     if (client == 0) {
         return;
     }
-    pid_t pid = IPCThreadState::self()->getCallingPid();
+    const pid_t pid = IPCThreadState::self()->getCallingPid();
     const uid_t uid = IPCThreadState::self()->getCallingUid();
+
+    audio_utils::lock_guard _l(mutex());
     {
         audio_utils::lock_guard _cl(clientMutex());
-        if (mNotificationClients.indexOfKey(pid) < 0) {
-            sp<NotificationClient> notificationClient = new NotificationClient(this,
-                                                                                client,
-                                                                                pid,
-                                                                                uid);
+        if (mNotificationClients.count(pid) == 0) {
+            auto notificationClient = sp<NotificationClient>::make(
+                    this, client, pid, uid);
             ALOGV("registerClient() client %p, pid %d, uid %u",
                     notificationClient.get(), pid, uid);
 
-            mNotificationClients.add(pid, notificationClient);
-
+            mNotificationClients[pid] = notificationClient;
             sp<IBinder> binder = IInterface::asBinder(client);
             binder->linkToDeath(notificationClient);
         }
@@ -2206,7 +2259,7 @@
         audio_utils::lock_guard _l(mutex());
         {
             audio_utils::lock_guard _cl(clientMutex());
-            mNotificationClients.removeItem(pid);
+            mNotificationClients.erase(pid);
         }
 
         ALOGV("%d died, releasing its sessions", pid);
@@ -2247,11 +2300,13 @@
             legacy2aidl_AudioIoDescriptor_AudioIoDescriptor(ioDesc));
 
     audio_utils::lock_guard _l(clientMutex());
-    size_t size = mNotificationClients.size();
-    for (size_t i = 0; i < size; i++) {
-        if ((pid == 0) || (mNotificationClients.keyAt(i) == pid)) {
-            mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(eventAidl,
-                                                                                   descAidl);
+    if (pid != 0) {
+        if (auto it = mNotificationClients.find(pid); it != mNotificationClients.end()) {
+            it->second->audioFlingerClient()->ioConfigChanged(eventAidl, descAidl);
+        }
+    } else {
+        for (const auto& [ client_pid, client] : mNotificationClients) {
+            client->audioFlingerClient()->ioConfigChanged(eventAidl, descAidl);
         }
     }
 }
@@ -2265,9 +2320,8 @@
 
     audio_utils::lock_guard _l(clientMutex());
     size_t size = mNotificationClients.size();
-    for (size_t i = 0; i < size; i++) {
-        mNotificationClients.valueAt(i)->audioFlingerClient()
-                ->onSupportedLatencyModesChanged(outputAidl, modesAidl);
+    for (const auto& [_, client] : mNotificationClients) {
+        client->audioFlingerClient()->onSupportedLatencyModesChanged(outputAidl, modesAidl);
     }
 }
 
@@ -2326,6 +2380,9 @@
                                                      pid_t pid,
                                                      uid_t uid)
     : mAudioFlinger(audioFlinger), mPid(pid), mUid(uid), mAudioFlingerClient(client)
+    , mClientToken(media::psh_utils::AudioPowerManager::enabled()
+            ? media::psh_utils::createAudioClientToken(pid, uid)
+            : nullptr)
 {
 }
 
@@ -2335,7 +2392,7 @@
 
 void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who __unused)
 {
-    sp<NotificationClient> keep(this);
+    const auto keep = sp<NotificationClient>::fromExisting(this);
     mAudioFlinger->removeNotificationClient(mPid);
 }
 
@@ -2455,7 +2512,7 @@
     output.selectedDeviceId = input.selectedDeviceId;
     output.flags = input.flags;
 
-    client = registerPid(VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(adjAttributionSource.pid)));
+    client = registerClient(adjAttributionSource.pid, adjAttributionSource.uid);
 
     // Not a conventional loop, but a retry loop for at most two iterations total.
     // Try first maybe with FAST flag then try again without FAST flag if that fails.
@@ -3021,7 +3078,7 @@
                                                         audio_config_base_t *mixerConfig,
                                                         audio_devices_t deviceType,
                                                         const String8& address,
-                                                        audio_output_flags_t flags,
+                                                        audio_output_flags_t *flags,
                                                         const audio_attributes_t attributes)
 {
     AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
@@ -3056,7 +3113,7 @@
     mHardwareStatus = AUDIO_HW_IDLE;
 
     if (status == NO_ERROR) {
-        if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+        if (*flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
             const sp<IAfMmapPlaybackThread> thread = IAfMmapPlaybackThread::create(
                     this, *output, outHwDev, outputStream, mSystemReady);
             mMmapThreads.add(*output, thread);
@@ -3065,22 +3122,22 @@
             return thread;
         } else {
             sp<IAfPlaybackThread> thread;
-            if (flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+            if (*flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
                 thread = IAfPlaybackThread::createBitPerfectThread(
                         this, outputStream, *output, mSystemReady);
                 ALOGV("%s() created bit-perfect output: ID %d thread %p",
                       __func__, *output, thread.get());
-            } else if (flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
+            } else if (*flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
                 thread = IAfPlaybackThread::createSpatializerThread(this, outputStream, *output,
                                                     mSystemReady, mixerConfig);
                 ALOGV("openOutput_l() created spatializer output: ID %d thread %p",
                       *output, thread.get());
-            } else if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+            } else if (*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                 thread = IAfPlaybackThread::createOffloadThread(this, outputStream, *output,
                         mSystemReady, halConfig->offload_info);
                 ALOGV("openOutput_l() created offload output: ID %d thread %p",
                       *output, thread.get());
-            } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
+            } else if ((*flags & AUDIO_OUTPUT_FLAG_DIRECT)
                     || !IAfThreadBase::isValidPcmSinkFormat(halConfig->format)
                     || !IAfThreadBase::isValidPcmSinkChannelMask(halConfig->channel_mask)) {
                 thread = IAfPlaybackThread::createDirectOutputThread(this, outputStream, *output,
@@ -3144,7 +3201,7 @@
     audio_utils::lock_guard _l(mutex());
 
     const sp<IAfThreadBase> thread = openOutput_l(module, &output, &halConfig,
-            &mixerConfig, deviceType, address, flags, attributes);
+            &mixerConfig, deviceType, address, &flags, attributes);
     if (thread != 0) {
         uint32_t latencyMs = 0;
         if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
@@ -3602,7 +3659,7 @@
         // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
         // called from a different pid leaving a stale session reference.  Also we don't know how
         // to clear this reference if the client process dies.
-        if (mNotificationClients.indexOfKey(caller) < 0) {
+        if (mNotificationClients.count(caller) == 0) {
             ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
             return;
         }
@@ -4063,7 +4120,8 @@
                                                        0ns /* timeout */,
                                                        frameCountToBeReady,
                                                        track->getSpeed(),
-                                                       1.f /* volume */);
+                                                       1.f /* volume */,
+                                                       track->getPortMute() /* muted */);
         status = patchTrack->initCheck();
         if (status != NO_ERROR) {
             ALOGE("Secondary output patchTrack init failed: %d", status);
@@ -4378,7 +4436,7 @@
         audio_utils::lock_guard _l(mutex());
 
         if (sessionId == AUDIO_SESSION_DEVICE) {
-            sp<Client> client = registerPid(currentPid);
+            sp<Client> client = registerClient(currentPid, adjAttributionSource.uid);
             ALOGV("%s device type %#x address %s", __func__, device.mType, device.getAddress());
             handle = mDeviceEffectManager->createEffect_l(
                     &descOut, device, client, effectClient, mPatchPanel->patches_l(),
@@ -4440,7 +4498,7 @@
                     goto Exit;
                 }
                 ALOGV("%s() got io %d for effect %s", __func__, io, descOut.name);
-                sp<Client> client = registerPid(currentPid);
+                sp<Client> client = registerClient(currentPid, adjAttributionSource.uid);
                 bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
                 handle = createOrphanEffect_l(client, effectClient, priority, sessionId,
                                               &descOut, &enabledOut, &lStatus, pinned,
@@ -4502,7 +4560,7 @@
             }
         }
 
-        sp<Client> client = registerPid(currentPid);
+        sp<Client> client = registerClient(currentPid, adjAttributionSource.uid);
 
         // create effect on selected output thread
         bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 545fa36..042194f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -27,6 +27,7 @@
 #include "IAfTrack.h"
 #include "MelReporter.h"
 #include "PatchCommandThread.h"
+#include "audio_utils/clock.h"
 
 // External classes
 #include <audio_utils/mutex.h>
@@ -38,6 +39,7 @@
 #include <media/audiohal/DevicesFactoryHalInterface.h>
 #include <mediautils/ServiceUtilities.h>
 #include <mediautils/Synchronization.h>
+#include <psh_utils/AudioPowerManager.h>
 
 // not needed with the includes above, added to prevent transitive include dependency.
 #include <utils/KeyedVector.h>
@@ -64,6 +66,11 @@
 
     status_t resetReferencesForTest();
 
+    // Called by main when startup finished -- for logging purposes only
+    void startupFinished() {
+        mStartupFinishedTime.store(audio_utils_get_real_time_ns(), std::memory_order_release);
+    }
+
 private:
 
     // ---- begin IAudioFlinger interface
@@ -92,12 +99,12 @@
     status_t getMasterBalance(float* balance) const final EXCLUDES_AudioFlinger_Mutex;
 
     status_t setStreamVolume(audio_stream_type_t stream, float value,
-            audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
+            bool muted, audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
     status_t setStreamMute(audio_stream_type_t stream, bool muted) final
             EXCLUDES_AudioFlinger_Mutex;
 
     status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
-            audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
+                            bool muted, audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
 
     status_t setMode(audio_mode_t mode) final EXCLUDES_AudioFlinger_Mutex;
 
@@ -336,7 +343,7 @@
             audio_config_base_t* mixerConfig,
             audio_devices_t deviceType,
             const String8& address,
-            audio_output_flags_t flags,
+            audio_output_flags_t* flags,
             audio_attributes_t attributes) final REQUIRES(mutex());
     const DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>&
             getAudioHwDevs_l() const final REQUIRES(mutex(), hardwareMutex()) {
@@ -419,6 +426,10 @@
 
     sp<EffectsFactoryHalInterface> getEffectsFactory();
 
+    int64_t getStartupFinishedTime() {
+        return mStartupFinishedTime.load(std::memory_order_acquire);
+    }
+
 public:
     // TODO(b/292281786): Remove this when Oboeservice can get access to
     // openMmapStream through an IAudioFlinger handle directly.
@@ -468,9 +479,10 @@
     // AudioFlinger::setParameters() updates with mutex().
     std::atomic_uint32_t mScreenState{};
 
-    void dumpPermissionDenial(int fd, const Vector<String16>& args);
-    void dumpClients_ll(int fd, const Vector<String16>& args) REQUIRES(mutex(), clientMutex());
-    void dumpInternals_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
+    void dumpPermissionDenial(int fd);
+    void dumpClients_ll(int fd, bool dumpAllocators) REQUIRES(mutex(), clientMutex());
+    void dumpInternals_l(int fd) REQUIRES(mutex());
+    void dumpStats(int fd);
 
     SimpleLog mThreadLog{16}; // 16 Thread history limit
 
@@ -499,6 +511,7 @@
         const pid_t             mPid;
         const uid_t             mUid;
         const sp<media::IAudioFlingerClient> mAudioFlingerClient;
+        const std::unique_ptr<media::psh_utils::Token> mClientToken;
     };
 
     // --- MediaLogNotifier ---
@@ -698,8 +711,7 @@
 
     DefaultKeyedVector<audio_io_handle_t, sp<IAfRecordThread>> mRecordThreads GUARDED_BY(mutex());
 
-    DefaultKeyedVector<pid_t, sp<NotificationClient>> mNotificationClients
-            GUARDED_BY(clientMutex());
+    std::map<pid_t, sp<NotificationClient>> mNotificationClients GUARDED_BY(clientMutex());
 
                 // updated by atomic_fetch_add_explicit
     volatile atomic_uint_fast32_t mNextUniqueIds[AUDIO_UNIQUE_ID_USE_MAX];  // ctor init
@@ -726,7 +738,8 @@
                 // Audio data transfer is directly handled by the client creating the MMAP stream
     DefaultKeyedVector<audio_io_handle_t, sp<IAfMmapThread>> mMmapThreads GUARDED_BY(mutex());
 
-    sp<Client> registerPid(pid_t pid) EXCLUDES_AudioFlinger_ClientMutex; // always returns non-0
+    // always returns non-null
+    sp<Client> registerClient(pid_t pid, uid_t uid) EXCLUDES_AudioFlinger_ClientMutex;
 
     sp<IAfEffectHandle> createOrphanEffect_l(const sp<Client>& client,
                                           const sp<media::IEffectClient>& effectClient,
@@ -777,8 +790,6 @@
     bool mSystemReady GUARDED_BY(mutex()) = false;
     std::atomic<bool> mAudioPolicyReady = false;
 
-    mediautils::UidInfo mUidInfo GUARDED_BY(mutex());
-
     // no mutex needed.
     SimpleLog  mRejectedSetParameterLog;
     SimpleLog  mAppSetParameterLog;
@@ -802,6 +813,10 @@
 
     // Local interface to AudioPolicyService, late inited, but logically const
     mediautils::atomic_sp<media::IAudioPolicyServiceLocal> mAudioPolicyServiceLocal;
+
+    const int64_t mStartTime = audio_utils_get_real_time_ns();
+    // Late-inited from main()
+    std::atomic<int64_t> mStartupFinishedTime {};
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/audioflinger/Client.cpp b/services/audioflinger/Client.cpp
index 93599ac..4858469 100644
--- a/services/audioflinger/Client.cpp
+++ b/services/audioflinger/Client.cpp
@@ -18,9 +18,10 @@
 
 namespace android {
 
-Client::Client(const sp<IAfClientCallback>& afClientCallback, pid_t pid)
+Client::Client(const sp<IAfClientCallback>& afClientCallback, pid_t pid, uid_t uid)
     : mAfClientCallback(afClientCallback)
     , mPid(pid)
+    , mUid(uid)
     , mClientAllocator(AllocatorFactory::getClientAllocator()) {}
 
 // Client destructor must be called with AudioFlinger::mClientLock held
@@ -34,4 +35,4 @@
     return mClientAllocator;
 }
 
-}   // namespace android
\ No newline at end of file
+}   // namespace android
diff --git a/services/audioflinger/Client.h b/services/audioflinger/Client.h
index ff0d751..c2fef39 100644
--- a/services/audioflinger/Client.h
+++ b/services/audioflinger/Client.h
@@ -42,13 +42,14 @@
 
 class Client : public RefBase {
 public:
-    Client(const sp<IAfClientCallback>& audioFlinger, pid_t pid);
+    Client(const sp<IAfClientCallback>& audioFlinger, pid_t pid, uid_t uid);
 
     // TODO(b/289139675) make Client container.
     // Client destructor must be called with AudioFlinger::mClientLock held
     ~Client() override;
     AllocatorFactory::ClientAllocator& allocator();
     pid_t pid() const { return mPid; }
+    uid_t uid() const { return mUid; }
     const auto& afClientCallback() const { return mAfClientCallback; }
 
 private:
@@ -56,6 +57,7 @@
 
     const sp<IAfClientCallback> mAfClientCallback;
     const pid_t mPid;
+    const uid_t mUid;
     AllocatorFactory::ClientAllocator mClientAllocator;
 };
 
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
index 7cb9329..42c6401 100644
--- a/services/audioflinger/DeviceEffectManager.cpp
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -22,7 +22,7 @@
 
 #include "EffectConfiguration.h"
 
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
 #include <audio_utils/primitives.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 #include <utils/Log.h>
@@ -208,10 +208,9 @@
 }
 
 void DeviceEffectManager::dump(int fd)
-NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
 {
-    const bool locked = afutils::dumpTryLock(mutex());
-    if (!locked) {
+    afutils::FallibleLockGuard l{mutex()};
+    if (!l) {
         String8 result("DeviceEffectManager may be deadlocked\n");
         write(fd, result.c_str(), result.size());
     }
@@ -227,10 +226,6 @@
             effect->dump2(fd, 4);
         }
     }
-
-    if (locked) {
-        mutex().unlock();
-    }
 }
 
 size_t DeviceEffectManager::removeEffect(const sp<IAfDeviceEffectProxy>& effect)
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 84505d3..b9d3ebe 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -24,7 +24,7 @@
 #include "Client.h"
 #include "EffectConfiguration.h"
 
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
 #include <audio_utils/channels.h>
 #include <audio_utils/primitives.h>
 #include <media/AudioCommonTypes.h>
@@ -506,52 +506,50 @@
 }
 
 void EffectBase::dump(int fd, const Vector<String16>& args __unused) const
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
 {
     String8 result;
 
     result.appendFormat("\tEffect ID %d:\n", mId);
 
-    const bool locked = afutils::dumpTryLock(mutex());
-    // failed to lock - AudioFlinger is probably deadlocked
-    if (!locked) {
-        result.append("\t\tCould not lock Fx mutex:\n");
-    }
-    bool isInternal = isInternal_l();
-    result.append("\t\tSession State Registered Internal Enabled Suspended:\n");
-    result.appendFormat("\t\t%05d   %03d   %s          %s        %s       %s\n",
-            mSessionId, mState, mPolicyRegistered ? "y" : "n", isInternal ? "y" : "n",
-            ((isInternal && isEnabled()) || (!isInternal && mPolicyEnabled)) ? "y" : "n",
-            mSuspended ? "y" : "n");
-
-    result.append("\t\tDescriptor:\n");
-    char uuidStr[64];
-    AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
-    result.appendFormat("\t\t- UUID: %s\n", uuidStr);
-    AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
-    result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
-    result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
-            mDescriptor.apiVersion,
-            mDescriptor.flags,
-            effectFlagsToString(mDescriptor.flags).c_str());
-    result.appendFormat("\t\t- name: %s\n",
-            mDescriptor.name);
-
-    result.appendFormat("\t\t- implementor: %s\n",
-            mDescriptor.implementor);
-
-    result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
-    result.append("\t\t\t  Pid Priority Ctrl Locked client server\n");
-    char buffer[256];
-    for (size_t i = 0; i < mHandles.size(); ++i) {
-        IAfEffectHandle *handle = mHandles[i];
-        if (handle != NULL && !handle->disconnected()) {
-            handle->dumpToBuffer(buffer, sizeof(buffer));
-            result.append(buffer);
+    {
+        afutils::FallibleLockGuard l{mutex()};
+        // failed to lock - AudioFlinger is probably deadlocked
+        if (!l) {
+            result.append("\t\tCould not lock Fx mutex:\n");
         }
-    }
-    if (locked) {
-        mutex().unlock();
+        bool isInternal = isInternal_l();
+        result.append("\t\tSession State Registered Internal Enabled Suspended:\n");
+        result.appendFormat("\t\t%05d   %03d   %s          %s        %s       %s\n",
+                mSessionId, mState, mPolicyRegistered ? "y" : "n", isInternal ? "y" : "n",
+                ((isInternal && isEnabled()) || (!isInternal && mPolicyEnabled)) ? "y" : "n",
+                mSuspended ? "y" : "n");
+
+        result.append("\t\tDescriptor:\n");
+        char uuidStr[64];
+        AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+        result.appendFormat("\t\t- UUID: %s\n", uuidStr);
+        AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
+        result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
+        result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
+                mDescriptor.apiVersion,
+                mDescriptor.flags,
+                effectFlagsToString(mDescriptor.flags).c_str());
+        result.appendFormat("\t\t- name: %s\n",
+                mDescriptor.name);
+
+        result.appendFormat("\t\t- implementor: %s\n",
+                mDescriptor.implementor);
+
+        result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
+        result.append("\t\t\t  Pid Priority Ctrl Locked client server\n");
+        char buffer[256];
+        for (size_t i = 0; i < mHandles.size(); ++i) {
+            IAfEffectHandle *handle = mHandles[i];
+            if (handle != NULL && !handle->disconnected()) {
+                handle->dumpToBuffer(buffer, sizeof(buffer));
+                result.append(buffer);
+            }
+        }
     }
 
     write(fd, result.c_str(), result.length());
@@ -1710,13 +1708,11 @@
     return ss.str();
 }
 
-void EffectModule::dump(int fd, const Vector<String16>& args) const
-NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
-{
+void EffectModule::dump(int fd, const Vector<String16>& args) const {
     EffectBase::dump(fd, args);
 
     String8 result;
-    const bool locked = afutils::dumpTryLock(mutex());
+    afutils::FallibleLockGuard l{mutex()};
 
     result.append("\t\tStatus Engine:\n");
     result.appendFormat("\t\t%03d    %p\n",
@@ -1758,9 +1754,6 @@
         (void)mEffectInterface->dump(fd);
     }
 
-    if (locked) {
-        mutex().unlock();
-    }
 }
 
 // ----------------------------------------------------------------------------
@@ -2203,22 +2196,20 @@
 }
 
 void EffectHandle::dumpToBuffer(char* buffer, size_t size) const
-NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
 {
-    const bool locked = mCblk != nullptr && afutils::dumpTryLock(mCblk->lock);
+    std::optional<afutils::FallibleLockGuard> guard;
+    if (mCblk != nullptr) {
+        guard.emplace(mCblk->lock);
+    }
 
     snprintf(buffer, size, "\t\t\t%5d    %5d  %3s    %3s  %5u  %5u\n",
             (mClient == 0) ? getpid() : mClient->pid(),
             mPriority,
             mHasControl ? "yes" : "no",
-            locked ? "yes" : "no",
+            guard.has_value() && *guard ? "yes" : "no",
             mCblk ? mCblk->clientIndex : 0,
             mCblk ? mCblk->serverIndex : 0
             );
-
-    if (locked) {
-        mCblk->lock.unlock();
-    }
 }
 
 #undef LOG_TAG
@@ -2803,41 +2794,36 @@
 }
 
 void EffectChain::dump(int fd, const Vector<String16>& args) const
-NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
 {
     String8 result;
-
+    afutils::FallibleLockGuard l{mutex()};
     const size_t numEffects = mEffects.size();
     result.appendFormat("    %zu effects for session %d\n", numEffects, mSessionId);
-
-    if (numEffects) {
-        const bool locked = afutils::dumpTryLock(mutex());
-        // failed to lock - AudioFlinger is probably deadlocked
-        if (!locked) {
-            result.append("\tCould not lock mutex:\n");
-        }
-
-        const std::string inBufferStr = dumpInOutBuffer(true /* isInput */, mInBuffer);
-        const std::string outBufferStr = dumpInOutBuffer(false /* isInput */, mOutBuffer);
-        result.appendFormat("\t%-*s%-*s   Active tracks:\n",
-                (int)inBufferStr.size(), "In buffer    ",
-                (int)outBufferStr.size(), "Out buffer      ");
-        result.appendFormat("\t%s   %s   %d\n",
-                inBufferStr.c_str(), outBufferStr.c_str(), mActiveTrackCnt);
+    if (numEffects == 0) {
         write(fd, result.c_str(), result.size());
+        return;
+    }
 
-        for (size_t i = 0; i < numEffects; ++i) {
-            sp<IAfEffectModule> effect = mEffects[i];
-            if (effect != 0) {
-                effect->dump(fd, args);
-            }
-        }
 
-        if (locked) {
-            mutex().unlock();
+    // failed to lock - AudioFlinger is probably deadlocked
+    if (!l) {
+        result.append("\tCould not lock mutex:\n");
+    }
+
+    const std::string inBufferStr = dumpInOutBuffer(true /* isInput */, mInBuffer);
+    const std::string outBufferStr = dumpInOutBuffer(false /* isInput */, mOutBuffer);
+    result.appendFormat("\t%-*s%-*s   Active tracks:\n",
+            (int)inBufferStr.size(), "In buffer    ",
+            (int)outBufferStr.size(), "Out buffer      ");
+    result.appendFormat("\t%s   %s   %d\n",
+            inBufferStr.c_str(), outBufferStr.c_str(), mActiveTrackCnt);
+    write(fd, result.c_str(), result.size());
+
+    for (size_t i = 0; i < numEffects; ++i) {
+        sp<IAfEffectModule> effect = mEffects[i];
+        if (effect != 0) {
+            effect->dump(fd, args);
         }
-    } else {
-        write(fd, result.c_str(), result.size());
     }
 }
 
@@ -3712,13 +3698,13 @@
 }
 
 void DeviceEffectProxy::dump2(int fd, int spaces) const
-NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
 {
     const Vector<String16> args;
     EffectBase::dump(fd, args);
 
-    const bool locked = afutils::dumpTryLock(proxyMutex());
-    if (!locked) {
+    afutils::FallibleLockGuard l{proxyMutex()};
+
+    if (!l) {
         String8 result("DeviceEffectProxy may be deadlocked\n");
         write(fd, result.c_str(), result.size());
     }
@@ -3745,10 +3731,6 @@
             effect->dump(fd, args);
         }
     }
-
-    if (locked) {
-        proxyMutex().unlock();
-    }
 }
 
 #undef LOG_TAG
diff --git a/services/audioflinger/IAfEffect.h b/services/audioflinger/IAfEffect.h
index 3452e94..3a059b6 100644
--- a/services/audioflinger/IAfEffect.h
+++ b/services/audioflinger/IAfEffect.h
@@ -345,7 +345,8 @@
 
     // sendMetadata_l() must be called with thread->mLock held
     virtual void sendMetadata_l(const std::vector<playback_track_metadata_v7_t>& allMetadata,
-        const std::optional<const std::vector<playback_track_metadata_v7_t>> spatializedMetadata);
+                                const std::optional<const std::vector<playback_track_metadata_v7_t>>
+                                        spatializedMetadata) = 0;
 
     virtual void dump(int fd, const Vector<String16>& args) const = 0;
 };
diff --git a/services/audioflinger/IAfPatchPanel.h b/services/audioflinger/IAfPatchPanel.h
index 37dce3a..15b6ddf 100644
--- a/services/audioflinger/IAfPatchPanel.h
+++ b/services/audioflinger/IAfPatchPanel.h
@@ -82,7 +82,7 @@
             audio_config_base_t* mixerConfig,
             audio_devices_t deviceType,
             const String8& address,
-            audio_output_flags_t flags,
+            audio_output_flags_t* flags,
             audio_attributes_t attributes) REQUIRES(mutex()) = 0;
     virtual audio_utils::mutex& mutex() const
             RETURN_CAPABILITY(audio_utils::AudioFlinger_Mutex) = 0;
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 8596acb..a13819c 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -402,7 +402,7 @@
     // the Thread is not busy releasing the Tracks, during which the Thread mutex
     // may be temporarily unlocked.  Some Track methods will use this method to
     // avoid races.
-    virtual void waitWhileThreadBusy_l(audio_utils::unique_lock& ul)
+    virtual void waitWhileThreadBusy_l(audio_utils::unique_lock<audio_utils::mutex>& ul)
             REQUIRES(mutex()) = 0;
 
     // The ThreadloopExecutor is used to defer functors or dtors
@@ -481,7 +481,8 @@
             bool isSpatialized,
             bool isBitPerfect,
             audio_output_flags_t* afTrackFlags,
-            float volume)
+            float volume,
+            bool muted)
             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
 
     virtual status_t addTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex()) = 0;
@@ -558,8 +559,8 @@
     virtual void setTracksInternalMute(std::map<audio_port_handle_t, bool>* tracksInternalMute)
             EXCLUDES_ThreadBase_Mutex = 0;
 
-    virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
-            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t setPortsVolume(const std::vector<audio_port_handle_t> &portIds, float volume,
+                                    bool muted) EXCLUDES_ThreadBase_Mutex = 0;
 };
 
 class IAfDirectOutputThread : public virtual IAfPlaybackThread {
@@ -700,8 +701,8 @@
 
     virtual AudioStreamOut* clearOutput() EXCLUDES_ThreadBase_Mutex = 0;
 
-    virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
-            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
+                                    bool muted) EXCLUDES_ThreadBase_Mutex = 0;
 };
 
 class IAfMmapCaptureThread : public virtual IAfMmapThread {
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index ee834d6..1b10f81 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -291,7 +291,18 @@
             float speed = 1.0f,
             bool isSpatialized = false,
             bool isBitPerfect = false,
-            float volume = 0.0f);
+            float volume = 0.0f,
+            bool muted = false);
+
+    static constexpr std::string_view getLogHeader() {
+        using namespace std::literals;
+        return "Type     Id Active Client(pid/uid) Session Port Id S  Flags "
+                        "  Format Chn mask  SRate "
+                        "ST Usg CT "
+                        " G db  L dB  R dB  VS dB  PortVol dB  PortMuted"
+                        "  Server FrmCnt  FrmRdy F Underruns  Flushed BitPerfect InternalMute"
+                        "   Latency\n"sv;
+    }
 
     virtual void pause() = 0;
     virtual void flush() = 0;
@@ -466,7 +477,14 @@
             const android::content::AttributionSourceState& attributionSource,
             pid_t creatorPid,
             audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
-            float volume = 0.0f);
+            float volume = 0.0f,
+            bool muted = false);
+
+    static constexpr std::string_view getLogHeader() {
+        using namespace std::literals;
+        return "Client(pid/uid) Session Port Id"
+                "   Format Chn mask  SRate Flags Usg/Src PortVol dB PortMuted\n"sv;
+    };
 
     // protected by MMapThread::mLock
     virtual void setSilenced_l(bool silenced) = 0;
@@ -511,6 +529,13 @@
             audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
             int32_t startFrames = -1);
 
+    static constexpr std::string_view getLogHeader() {
+        using namespace std::literals;
+        return "Active     Id Client(pid/uid) Session Port Id  S  Flags  "
+                        " Format Chn mask  SRate Source  "
+                        " Server FrmCnt FrmRdy Sil   Latency\n"sv;
+    }
+
     // clear the buffer overflow flag
     virtual void clearOverflow() = 0;
     // set the buffer overflow flag and return previous value
@@ -587,7 +612,8 @@
                                              *  the lowest possible latency
                                              *  even if it might glitch. */
             float speed = 1.0f,
-            float volume = 1.0f);
+            float volume = 1.0f,
+            bool muted = false);
 };
 
 class IAfPatchRecord : public virtual IAfRecordTrack, public virtual IAfPatchTrackBase {
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index 8758bd0..30bbd5d 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -36,7 +36,8 @@
                             const android::content::AttributionSourceState& attributionSource,
                             pid_t creatorPid,
                             audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
-                            float volume = 0.0f);
+                            float volume = 0.0f,
+                            bool muted = false);
     ~MmapTrack() override;
 
     status_t initCheck() const final;
@@ -71,7 +72,11 @@
     void setPortVolume(float volume) override {
         mVolume = volume;
     }
+    void setPortMute(bool muted) override {
+        mMuteState.muteFromPortVolume = muted;
+    }
     float getPortVolume() const override { return mVolume; }
+    bool getPortMute() const override { return mMuteState.muteFromPortVolume; }
 
 private:
     DISALLOW_COPY_AND_ASSIGN(MmapTrack);
@@ -86,6 +91,7 @@
     void onTimestamp(const ExtendedTimestamp &timestamp) final;
 
     const pid_t mPid;
+    const uid_t mUid;
     bool  mSilenced;            // protected by MMapThread::mLock
     bool  mSilencedNotified;    // protected by MMapThread::mLock
 
@@ -99,4 +105,4 @@
     float mVolume = 0.0f;
 };  // end of Track
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 02d4fc2..be59299 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -268,7 +268,7 @@
                                                             &mixerConfig,
                                                             outputDevice,
                                                             outputDeviceAddress,
-                                                            flags,
+                                                            &flags,
                                                             attributes);
                     ALOGV("mAfPatchPanelCallback->openOutput_l() returned %p", thread.get());
                     if (thread == 0) {
@@ -650,7 +650,8 @@
                                            {} /*timeout*/,
                                            frameCountToBeReady,
                                            1.0f /*speed*/,
-                                           1.0f /*volume*/);
+                                           1.0f /*volume*/,
+                                           false /*muted*/);
     status = mPlayback.checkTrack(tempPatchTrack.get());
     if (status != NO_ERROR) {
         return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 84758a4..70bab6a 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -97,7 +97,8 @@
                                 float speed = 1.0f,
                                 bool isSpatialized = false,
                                 bool isBitPerfect = false,
-                                float volume = 0.0f);
+                                float volume = 0.0f,
+                                bool muted = false);
     ~Track() override;
     status_t initCheck() const final;
     void appendDumpHeader(String8& result) const final;
@@ -226,7 +227,9 @@
 
     // VolumePortInterface implementation
     void setPortVolume(float volume) override;
+    void setPortMute(bool muted) override;
     float getPortVolume() const override { return mVolume; }
+    bool getPortMute() const override { return mMuteState.load().muteFromPortVolume; }
 
 protected:
 
@@ -410,9 +413,9 @@
     // TODO: replace PersistableBundle with own struct
     // access these two variables only when holding player thread lock.
     std::unique_ptr<os::PersistableBundle> mMuteEventExtras;
-    mute_state_t        mMuteState;
-    bool                mInternalMute = false;
-    std::atomic<float> mVolume = 0.0f;
+    std::atomic<mute_state_t> mMuteState;
+    bool                      mInternalMute = false;
+    std::atomic<float>        mVolume = 0.0f;
 };  // end of Track
 
 
@@ -510,7 +513,8 @@
                                                                     *  the lowest possible latency
                                                                     *  even if it might glitch. */
                                    float speed = 1.0f,
-                                   float volume = 1.0f);
+                                   float volume = 1.0f,
+                                   bool muted = false);
     ~PatchTrack() override;
 
     size_t framesReady() const final;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 56f4e18..1c0b749 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -27,7 +27,7 @@
 #include "MelReporter.h"
 #include "ResamplerBufferProvider.h"
 
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
 #include <afutils/Permission.h>
 #include <afutils/TypedLogger.h>
 #include <afutils/Vibrator.h>
@@ -81,6 +81,7 @@
 #include <powermanager/PowerManager.h>
 #include <private/android_filesystem_config.h>
 #include <private/media/AudioTrackShared.h>
+#include <psh_utils/AudioPowerManager.h>
 #include <system/audio_effects/effect_aec.h>
 #include <system/audio_effects/effect_downmix.h>
 #include <system/audio_effects/effect_ns.h>
@@ -1041,27 +1042,25 @@
 }
 
 void ThreadBase::dump(int fd, const Vector<String16>& args)
-NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
 {
     dprintf(fd, "\n%s thread %p, name %s, tid %d, type %d (%s):\n", isOutput() ? "Output" : "Input",
             this, mThreadName, getTid(), type(), threadTypeToString(type()));
 
-    const bool locked = afutils::dumpTryLock(mutex());
-    if (!locked) {
-        dprintf(fd, "  Thread may be deadlocked\n");
-    }
-
-    dumpBase_l(fd, args);
-    dumpInternals_l(fd, args);
-    dumpTracks_l(fd, args);
-    dumpEffectChains_l(fd, args);
-
-    if (locked) {
-        mutex().unlock();
+    {
+        afutils::FallibleLockGuard l{mutex()};
+        if (!l) {
+            dprintf(fd, "  Thread may be deadlocked\n");
+        }
+        dumpBase_l(fd, args);
+        dumpInternals_l(fd, args);
+        dumpTracks_l(fd, args);
+        dumpEffectChains_l(fd, args);
     }
 
     dprintf(fd, "  Local log:\n");
-    mLocalLog.dump(fd, "   " /* prefix */, 40 /* lines */);
+    const auto logHeader = this->getLocalLogHeader();
+    write(fd, logHeader.data(), logHeader.length());
+    mLocalLog.dump(fd, "   " /* prefix */);
 
     // --all does the statistics
     bool dumpAll = false;
@@ -1196,6 +1195,8 @@
         return String16("MmapCapture");
     case SPATIALIZER:
         return String16("AudioSpatial");
+    case BIT_PERFECT:
+        return String16("AudioBitPerfect");
     default:
         ALOG_ASSERT(false);
         return String16("AudioUnknown");
@@ -1216,6 +1217,10 @@
                     {} /* historyTag */);
         if (status.isOk()) {
             mWakeLockToken = binder;
+            if (media::psh_utils::AudioPowerManager::enabled()) {
+                mThreadToken = media::psh_utils::createAudioThreadToken(
+                        getTid(), String8(getWakeLockTag()).c_str());
+            }
         }
         ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status.exceptionCode());
     }
@@ -1241,6 +1246,7 @@
         }
         mWakeLockToken.clear();
     }
+    mThreadToken.reset();
 }
 
 void ThreadBase::getPowerManager_l() {
@@ -2399,7 +2405,8 @@
         bool isSpatialized,
         bool isBitPerfect,
         audio_output_flags_t *afTrackFlags,
-        float volume)
+        float volume,
+        bool muted)
 {
     size_t frameCount = *pFrameCount;
     size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2728,7 +2735,7 @@
                           nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
                           sessionId, creatorPid, attributionSource, trackFlags,
                           IAfTrackBase::TYPE_DEFAULT, portId, SIZE_MAX /*frameCountToBeReady*/,
-                          speed, isSpatialized, isBitPerfect, volume);
+                          speed, isSpatialized, isBitPerfect, volume, muted);
 
         lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
         if (lStatus != NO_ERROR) {
@@ -2836,10 +2843,14 @@
     }
 }
 
-void PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
+void PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value, bool muted)
 {
+    ALOGV("%s: stream %d value %f muted %d", __func__, stream, value, muted);
     audio_utils::lock_guard _l(mutex());
     mStreamTypes[stream].volume = value;
+    if (com_android_media_audio_ring_my_car()) {
+        mStreamTypes[stream].mute = muted;
+    }
     broadcast_l();
 }
 
@@ -2857,13 +2868,14 @@
 }
 
 status_t PlaybackThread::setPortsVolume(
-        const std::vector<audio_port_handle_t>& portIds, float volume) {
+        const std::vector<audio_port_handle_t>& portIds, float volume, bool muted) {
     audio_utils::lock_guard _l(mutex());
     for (const auto& portId : portIds) {
         for (size_t i = 0; i < mTracks.size(); i++) {
             sp<IAfTrack> track = mTracks[i].get();
             if (portId == track->portId()) {
                 track->setPortVolume(volume);
+                track->setPortMute(muted);
                 break;
             }
         }
@@ -3248,9 +3260,9 @@
 
     // Calculate size of normal sink buffer relative to the HAL output buffer size
     double multiplier = 1.0;
-    // Note: mType == SPATIALIZER does not support FastMixer.
-    if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
-            kUseFastMixer == FastMixer_Dynamic)) {
+    // Note: mType == SPATIALIZER does not support FastMixer and DEEP is by definition not "fast"
+    if ((mType == MIXER && !(mOutput->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) &&
+            (kUseFastMixer == FastMixer_Static || kUseFastMixer == FastMixer_Dynamic)) {
         size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
         size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
 
@@ -4057,7 +4069,13 @@
     // FIXME could this be made local to while loop?
     writeFrames = 0;
 
-    cacheParameters_l();
+    {
+        audio_utils::lock_guard l(mutex());
+
+        cacheParameters_l();
+        checkSilentMode_l();
+    }
+
     mSleepTimeUs = mIdleSleepTimeUs;
 
     if (mType == MIXER || mType == SPATIALIZER) {
@@ -4082,8 +4100,6 @@
     // suspended mode (for now) to help schedule the wait time until next iteration.
     nsecs_t timeLoopNextNs = 0;
 
-    checkSilentMode_l();
-
     audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
 
     sendCheckOutputStageEffectsEvent();
@@ -5112,6 +5128,12 @@
     }
 }
 
+std::string PlaybackThread::getLocalLogHeader() const {
+    using namespace std::literals;
+    static constexpr auto indent = "                             "
+                                   "                            "sv;
+    return std::string{indent}.append(IAfTrack::getLogHeader());
+}
 // ----------------------------------------------------------------------------
 
 /* static */
@@ -5175,7 +5197,16 @@
             break;
         case FastMixer_Static:
         case FastMixer_Dynamic:
-            initFastMixer = mFrameCount < mNormalFrameCount;
+            if (mType == MIXER && (output->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+                /* Do not init fast mixer on deep buffer, warn if buffers are confed too small */
+                initFastMixer = false;
+                ALOGW_IF(mFrameCount * 1000 / mSampleRate < kMinNormalSinkBufferSizeMs,
+                         "HAL DEEP BUFFER Buffer (%zu ms) is smaller than set minimal buffer "
+                         "(%u ms), seems like a configuration error",
+                         mFrameCount * 1000 / mSampleRate, kMinNormalSinkBufferSizeMs);
+            } else {
+                initFastMixer = mFrameCount < mNormalFrameCount;
+            }
             break;
         }
         ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
@@ -5264,7 +5295,10 @@
         mFastMixerNBLogWriter = afThreadCallback->newWriter_l(kFastMixerLogSize, "FastMixer");
         state->mNBLogWriter = mFastMixerNBLogWriter.get();
         sq->end();
-        sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+        {
+            audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+            sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+        }
 
         NBLog::thread_info_t info;
         info.id = mId;
@@ -5323,8 +5357,11 @@
         }
         state->mCommand = FastMixerState::EXIT;
         sq->end();
-        sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
-        mFastMixer->join();
+        {
+            audio_utils::mutex::scoped_join_wait_check queueWaitCheck(mFastMixer->getTid());
+            sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+            mFastMixer->join();
+        }
         // Though the fast mixer thread has exited, it's state queue is still valid.
         // We'll use that extract the final state which contains one remaining fast track
         // corresponding to our sub-mix.
@@ -5404,7 +5441,10 @@
                 FastThreadDumpState::kSamplingNforLowRamDevice : FastThreadDumpState::kSamplingN);
 #endif
             sq->end();
-            sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+            {
+                audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+                sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+            }
             if (kUseFastMixer == FastMixer_Dynamic) {
                 mNormalSink = mPipeSink;
             }
@@ -5437,7 +5477,10 @@
             mFastMixerFutex = 0;
             sq->end();
             // BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now
-            sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
+            {
+                audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+                sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
+            }
             if (kUseFastMixer == FastMixer_Dynamic) {
                 mNormalSink = mOutputSink;
             }
@@ -5822,7 +5865,7 @@
                         volume = masterVolume * mStreamTypes[track->streamType()].volume;
                     }
                 } else {
-                    if (track->isPlaybackRestricted()) {
+                    if (track->isPlaybackRestricted() || track->getPortMute()) {
                         volume = 0.f;
                     } else {
                         volume = masterVolume * track->getPortVolume();
@@ -5846,7 +5889,8 @@
                                            mStreamTypes[track->streamType()].mute,
                                            track->isPlaybackRestricted(),
                                            vlf == 0.f && vrf == 0.f,
-                                           vh == 0.f});
+                                           vh == 0.f,
+                                           /*muteFromPortVolume=*/false});
                 } else {
                     track->processMuteEvent_l(mAfThreadCallback->getOrCreateAudioManager(),
                             /*muteState=*/{masterVolume == 0.f,
@@ -5854,7 +5898,8 @@
                                            /* muteFromStreamMuted= */ false,
                                            track->isPlaybackRestricted(),
                                            vlf == 0.f && vrf == 0.f,
-                                           vh == 0.f});
+                                           vh == 0.f,
+                                           track->getPortMute()});
                 }
                 vlf *= volume;
                 vrf *= volume;
@@ -6018,7 +6063,7 @@
                 }
             } else {
                 v = masterVolume * track->getPortVolume();
-                if (track->isPlaybackRestricted()) {
+                if (track->isPlaybackRestricted() || track->getPortMute()) {
                     v = 0;
                 }
             }
@@ -6048,7 +6093,8 @@
                                            mStreamTypes[track->streamType()].mute,
                                            track->isPlaybackRestricted(),
                                            vlf == 0.f && vrf == 0.f,
-                                           vh == 0.f});
+                                           vh == 0.f,
+                                           /*muteFromPortVolume=*/false});
                 } else {
                     track->processMuteEvent_l(mAfThreadCallback->getOrCreateAudioManager(),
                             /*muteState=*/{masterVolume == 0.f,
@@ -6056,7 +6102,8 @@
                                            /* muteFromStreamMuted= */ false,
                                            track->isPlaybackRestricted(),
                                            vlf == 0.f && vrf == 0.f,
-                                           vh == 0.f});
+                                           vh == 0.f,
+                                           track->getPortMute()});
                 }
                 // now apply the master volume and stream type volume and shaper volume
                 vlf *= v * vh;
@@ -6333,7 +6380,10 @@
         //
         // This occurs with BT suspend when we idle the FastMixer with
         // active tracks, which may be added or removed.
-        sq->push(coldIdle ? FastMixerStateQueue::BLOCK_NEVER : block);
+        {
+            audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+            sq->push(coldIdle ? FastMixerStateQueue::BLOCK_NEVER : block);
+        }
     }
 #ifdef AUDIO_WATCHDOG
     if (pauseAudioWatchdog && mAudioWatchdog != 0) {
@@ -6811,7 +6861,8 @@
                                mStreamTypes[track->streamType()].mute,
                                track->isPlaybackRestricted(),
                                clientVolumeMute,
-                               shaperVolume == 0.f});
+                               shaperVolume == 0.f,
+                               /*muteFromPortVolume=*/false});
     } else {
         if (mMasterMute || track->isPlaybackRestricted()) {
             left = right = 0;
@@ -6839,7 +6890,8 @@
                                /* muteFromStreamMuted= */ false,
                                track->isPlaybackRestricted(),
                                clientVolumeMute,
-                               shaperVolume == 0.f});
+                               shaperVolume == 0.f,
+                               track->getPortMute()});
     }
 
     if (lastTrack) {
@@ -7292,11 +7344,14 @@
 {
     PlaybackThread::flushHw_l();
     mOutput->flush();
-    mHwPaused = false;
     mFlushPending = false;
     mTimestampVerifier.discontinuity(discontinuityForStandbyOrFlush());
     mTimestamp.clear();
     mMonotonicFrameCounter.onFlush();
+    // We do not reset mHwPaused which is hidden from the Track client.
+    // Note: the client track in Tracks.cpp and AudioTrack.cpp
+    // has a FLUSHED state but the DirectOutputThread does not;
+    // those tracks will continue to show isStopped().
 }
 
 int64_t DirectOutputThread::computeWaitTimeNs_l() const {
@@ -7862,6 +7917,9 @@
         audio_utils::lock_guard l(mutex());
         localTracks = std::move(mOutputTracks);
         mOutputTracks.clear();
+        for (size_t i = 0; i < localTracks.size(); ++i) {
+            localTracks[i]->destroy();
+        }
     }
     localTracks.clear();
     outputTracks.clear();
@@ -7935,8 +7993,9 @@
         return;
     }
     if (!audioserver_flags::portid_volume_management()) {
-        thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
+        thread->setStreamVolume(AUDIO_STREAM_PATCH, /*volume=*/1.0f, /*muted=*/false);
     }
+
     mOutputTracks.add(outputTrack);
     ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
     updateWaitTime_l();
@@ -8303,8 +8362,10 @@
                 afThreadCallback->newWriter_l(kFastCaptureLogSize, "FastCapture");
         state->mNBLogWriter = mFastCaptureNBLogWriter.get();
         sq->end();
-        sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
-
+        {
+            audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastCapture->getTid());
+            sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+        }
         // start the fast capture
         mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastCapture->getTid();
@@ -8338,8 +8399,11 @@
         }
         state->mCommand = FastCaptureState::EXIT;
         sq->end();
-        sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
-        mFastCapture->join();
+        {
+            audio_utils::mutex::scoped_join_wait_check queueWaitCheck(mFastCapture->getTid());
+            sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+            mFastCapture->join();
+        }
         mFastCapture.clear();
     }
     mAfThreadCallback->unregisterWriter(mFastCaptureNBLogWriter);
@@ -8972,7 +9036,11 @@
             mFastCaptureFutex = 0;
             sq->end();
             // BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now
-            sq->push(FastCaptureStateQueue::BLOCK_UNTIL_ACKED);
+            {
+                audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastCapture->getTid());
+                sq->push(FastCaptureStateQueue::BLOCK_UNTIL_ACKED);
+            }
+
 #if 0
             if (kUseFastCapture == FastCapture_Dynamic) {
                 // FIXME
@@ -10205,6 +10273,13 @@
     }
 }
 
+std::string RecordThread::getLocalLogHeader() const {
+    using namespace std::literals;
+    static constexpr auto indent = "                             "
+                                   "                            "sv;
+    return std::string{indent}.append(IAfRecordTrack::getLogHeader());
+}
+
 // ----------------------------------------------------------------------------
 //      Mmap
 // ----------------------------------------------------------------------------
@@ -10424,6 +10499,7 @@
     const auto localSessionId = mSessionId;
     auto localAttr = mAttr;
     float volume = 0.0f;
+    bool muted = false;
     if (isOutput()) {
         audio_config_t config = AUDIO_CONFIG_INITIALIZER;
         config.sample_rate = mSampleRate;
@@ -10448,7 +10524,8 @@
                                             &secondaryOutputs,
                                             &isSpatialized,
                                             &isBitPerfect,
-                                            &volume);
+                                            &volume,
+                                            &muted);
         mutex().lock();
         mAttr = localAttr;
         ALOGD_IF(!secondaryOutputs.empty(),
@@ -10518,7 +10595,7 @@
                                         mChannelMask, mSessionId, isOutput(),
                                         client.attributionSource,
                                         IPCThreadState::self()->getCallingPid(), portId,
-                                        volume);
+                                        volume, muted);
     if (!isOutput()) {
         track->setSilenced_l(isClientSilenced_l(portId));
     }
@@ -11085,6 +11162,13 @@
     write(fd, result.c_str(), result.size());
 }
 
+std::string MmapThread::getLocalLogHeader() const {
+    using namespace std::literals;
+    static constexpr auto indent = "                             "
+                                   "                            "sv;
+    return std::string{indent}.append(IAfMmapTrack::getLogHeader());
+}
+
 /* static */
 sp<IAfMmapPlaybackThread> IAfMmapPlaybackThread::create(
         const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
@@ -11169,10 +11253,14 @@
     }
 }
 
-void MmapPlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
+void MmapPlaybackThread::setStreamVolume(audio_stream_type_t stream, float value, bool muted)
 {
+    ALOGV("%s: stream %d value %f muted %d", __func__, stream, value, muted);
     audio_utils::lock_guard _l(mutex());
     mStreamTypes[stream].volume = value;
+    if (com_android_media_audio_ring_my_car()) {
+        mStreamTypes[stream].mute = muted;
+    }
     if (stream == mStreamType) {
         broadcast_l();
     }
@@ -11194,12 +11282,13 @@
 }
 
 status_t MmapPlaybackThread::setPortsVolume(
-        const std::vector<audio_port_handle_t>& portIds, float volume) {
+        const std::vector<audio_port_handle_t>& portIds, float volume, bool muted) {
     audio_utils::lock_guard _l(mutex());
     for (const auto& portId : portIds) {
         for (const sp<IAfMmapTrack>& track : mActiveTracks) {
             if (portId == track->portId()) {
                 track->setPortVolume(volume);
+                track->setPortMute(muted);
                 break;
             }
         }
@@ -11257,7 +11346,11 @@
             // will be broadcasted to all tracks. Thus, take arbitrarily first track volume.
             size_t numtracks = mActiveTracks.size();
             if (numtracks) {
-                volume = mMasterVolume * mActiveTracks[0]->getPortVolume();
+                if (mActiveTracks[0]->getPortMute()) {
+                    volume = 0;
+                } else {
+                    volume = mMasterVolume * mActiveTracks[0]->getPortVolume();
+                }
             }
         }
     }
@@ -11301,7 +11394,8 @@
                         // TODO(b/241533526): adjust logic to include mute from AppOps
                         false /*muteFromPlaybackRestricted*/,
                         false /*muteFromClientVolume*/,
-                        false /*muteFromVolumeShaper*/});
+                        false /*muteFromVolumeShaper*/,
+                        false /*muteFromPortVolume*/});
             } else {
                 track->processMuteEvent_l(mAfThreadCallback->getOrCreateAudioManager(),
                     /*muteState=*/{mMasterMute,
@@ -11310,7 +11404,8 @@
                                    // TODO(b/241533526): adjust logic to include mute from AppOps
                                    false /*muteFromPlaybackRestricted*/,
                                    false /*muteFromClientVolume*/,
-                                   false /*muteFromVolumeShaper*/});
+                                   false /*muteFromVolumeShaper*/,
+                                   track->getPortMute()});
                 }
         }
     }
@@ -11598,6 +11693,7 @@
 
 void BitPerfectThread::setTracksInternalMute(
         std::map<audio_port_handle_t, bool>* tracksInternalMute) {
+    audio_utils::lock_guard _l(mutex());
     for (auto& track : mTracks) {
         if (auto it = tracksInternalMute->find(track->portId()); it != tracksInternalMute->end()) {
             track->setInternalMute(it->second);
@@ -11614,6 +11710,11 @@
         // Return the bit perfect track if all other tracks are muted
         for (const auto& track : mActiveTracks) {
             if (track->isBitPerfect()) {
+                if (track->getInternalMute()) {
+                    // There can only be one bit-perfect client active. If it is mute internally,
+                    // there is no need to stream bit-perfectly.
+                    break;
+                }
                 bitPerfectTrack = track;
             } else if (track->getFinalVolume() != 0.f) {
                 allOtherTracksMuted = false;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index a7a2630..0c5a2c3 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -33,6 +33,7 @@
 #include <fastpath/FastMixer.h>
 #include <mediautils/Synchronization.h>
 #include <mediautils/ThreadSnapshot.h>
+#include <psh_utils/Token.h>
 #include <timing/MonotonicFrameCounter.h>
 #include <utils/Log.h>
 
@@ -575,6 +576,9 @@
         return mThreadloopExecutor;
     }
 
+    // Used to print the header for the local log on a particular thread type
+    virtual std::string getLocalLogHeader() const { return {}; };
+
 protected:
 
                 // entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -622,7 +626,8 @@
      * ThreadBase_Mutex during this time.  No other mutex is held.
      */
 
-    void waitWhileThreadBusy_l(audio_utils::unique_lock& ul) final REQUIRES(mutex()) {
+    void waitWhileThreadBusy_l(audio_utils::unique_lock<audio_utils::mutex>& ul)
+            final REQUIRES(mutex()) {
         // the wait returns immediately if the predicate is satisfied.
         mThreadBusyCv.wait(ul, [&]{ return mThreadBusy == false;});
     }
@@ -725,6 +730,7 @@
                 char                    mThreadName[kThreadNameLength]; // guaranteed NUL-terminated
     sp<os::IPowerManager> mPowerManager GUARDED_BY(mutex());
     sp<IBinder> mWakeLockToken GUARDED_BY(mutex());
+    std::unique_ptr<media::psh_utils::Token> mThreadToken GUARDED_BY(mutex());
                 const sp<PMDeathRecipient> mDeathRecipient;
                 // list of suspended effects per session and per type. The first (outer) vector is
                 // keyed by session ID, the second (inner) by type UUID timeLow field
@@ -885,7 +891,7 @@
                     bool                mHasChanged = false;
                 };
 
-                SimpleLog mLocalLog;  // locked internally
+                SimpleLog mLocalLog {/* maxLogLines= */ 120};  // locked internally
 
     // mThreadloopExecutor contains deferred functors and object (dtors) to
     // be executed at the end of the processing period, without any
@@ -1014,11 +1020,12 @@
     void setMasterVolume(float value) final;
     void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex;
     void setMasterMute(bool muted) final;
-    void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
+    void setStreamVolume(audio_stream_type_t stream, float value, bool muted) final
+            EXCLUDES_ThreadBase_Mutex;
     void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
     float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;
-    status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
-            final EXCLUDES_ThreadBase_Mutex;
+    status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
+                            bool muted) final EXCLUDES_ThreadBase_Mutex;
 
     void setVolumeForOutput_l(float left, float right) const final;
 
@@ -1045,7 +1052,8 @@
                                 bool isSpatialized,
                                 bool isBitPerfect,
                                 audio_output_flags_t* afTrackFlags,
-                                float volume) final
+                                float volume,
+                                bool muted) final
             REQUIRES(audio_utils::AudioFlinger_Mutex);
 
     bool isTrackActive(const sp<IAfTrack>& track) const final {
@@ -1227,6 +1235,9 @@
             override EXCLUDES_ThreadBase_Mutex {
         // Do nothing. It is only used for bit perfect thread
     }
+
+    std::string getLocalLogHeader() const override;
+
 protected:
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -2131,6 +2142,8 @@
                             return !(mInput == nullptr || mInput->stream == nullptr);
                         }
 
+    std::string getLocalLogHeader() const override;
+
 protected:
     void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
     void dumpTracks_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
@@ -2322,6 +2335,8 @@
 
     bool isStreamInitialized() const override { return false; }
 
+    std::string getLocalLogHeader() const override;
+
     void setClientSilencedState_l(audio_port_handle_t portId, bool silenced) REQUIRES(mutex()) {
                                 mClientSilencedStates[portId] = silenced;
                             }
@@ -2392,11 +2407,13 @@
     // Needs implementation?
     void setMasterBalance(float /* value */) final EXCLUDES_ThreadBase_Mutex {}
     void setMasterMute(bool muted) final EXCLUDES_ThreadBase_Mutex;
-    void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
+
+    void setStreamVolume(audio_stream_type_t stream, float value, bool muted) final
+            EXCLUDES_ThreadBase_Mutex;
     void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
     float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;
-    status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
-            final EXCLUDES_ThreadBase_Mutex;
+    status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
+                            bool muted) final EXCLUDES_ThreadBase_Mutex;
 
     void setMasterMute_l(bool muted) REQUIRES(mutex()) { mMasterMute = muted; }
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 1342b7b..cde7fc2 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -24,6 +24,7 @@
 #include <android-base/macros.h>  // DISALLOW_COPY_AND_ASSIGN
 #include <datapath/TrackMetrics.h>
 #include <mediautils/BatteryNotifier.h>
+#include <psh_utils/AudioPowerManager.h>
 
 #include <atomic>    // avoid transitive dependency
 #include <list>      // avoid transitive dependency
@@ -240,17 +241,13 @@
      * Called when a track moves to active state to record its contribution to battery usage.
      * Track state transitions should eventually be handled within the track class.
      */
-    void beginBatteryAttribution() final {
-        mBatteryStatsHolder.emplace(uid());
-    }
+    void beginBatteryAttribution() final;
 
     /**
      * Called when a track moves out of the active state to record its contribution
      * to battery usage.
      */
-    void endBatteryAttribution() final {
-        mBatteryStatsHolder.reset();
-    }
+    void endBatteryAttribution() final;
 
 protected:
     DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -400,6 +397,7 @@
     std::atomic_flag    mChangeNotified = ATOMIC_FLAG_INIT;
     // RAII object for battery stats book-keeping
     std::optional<mediautils::BatteryStatsAudioHandle> mBatteryStatsHolder;
+    std::unique_ptr<media::psh_utils::Token> mTrackToken;
 };
 
 class PatchTrackBase : public PatchProxyBufferProvider, public virtual IAfPatchTrackBase
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5aa58a2..980ef22 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -318,13 +318,25 @@
 {
     const auto thread = mThread.promote();
     if (thread == nullptr) return;
-    thread->getThreadloopExecutor().defer(
-            [track = wp<TrackBase>::fromExisting(this)] {
-            const auto actual = track.promote();
+    auto weakTrack = wp<TrackBase>::fromExisting(this);
+    thread->getThreadloopExecutor().defer([weakTrack] {
+            const auto actual = weakTrack.promote();
             if (actual) actual->restartIfDisabled();
         });
 }
 
+void TrackBase::beginBatteryAttribution() {
+    mBatteryStatsHolder.emplace(uid());
+    if (media::psh_utils::AudioPowerManager::enabled()) {
+        mTrackToken = media::psh_utils::createAudioTrackToken(uid());
+    }
+}
+
+void TrackBase::endBatteryAttribution() {
+    mBatteryStatsHolder.reset();
+    mTrackToken.reset();
+}
+
 PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
         IAfThreadBase* thread, const Timeout& timeout)
     : mProxy(proxy)
@@ -716,7 +728,8 @@
         float speed,
         bool isSpatialized,
         bool isBitPerfect,
-        float volume) {
+        float volume,
+        bool muted) {
     return sp<Track>::make(thread,
             client,
             streamType,
@@ -738,7 +751,8 @@
             speed,
             isSpatialized,
             isBitPerfect,
-            volume);
+            volume,
+            muted);
 }
 
 // Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
@@ -764,7 +778,8 @@
             float speed,
             bool isSpatialized,
             bool isBitPerfect,
-            float volume)
+            float volume,
+            bool muted)
     :   TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
                   // TODO: Using unsecurePointer() has some associated security pitfalls
                   //       (see declaration for details).
@@ -848,11 +863,13 @@
     }
 
     populateUsageAndContentTypeFromStreamType();
+    setPortMute(muted);
 
     // Audio patch and call assistant volume are always max
     if (mAttr.usage == AUDIO_USAGE_CALL_ASSISTANT
             || mAttr.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
         mVolume = 1.0f;
+        setPortMute(false);
     }
 
     mServerLatencySupported = checkServerLatencySupported(format, flags);
@@ -988,13 +1005,8 @@
 
 void Track::appendDumpHeader(String8& result) const
 {
-    result.appendFormat("Type     Id Active Client Session Port Id S  Flags "
-                        "  Format Chn mask  SRate "
-                        "ST Usg CT "
-                        " G db  L dB  R dB  VS dB  PortVol dB "
-                        "  Server FrmCnt  FrmRdy F Underruns  Flushed BitPerfect InternalMute"
-                        "%s\n",
-                        isServerLatencySupported() ? "   Latency" : "");
+    const auto res = IAfTrack::getLogHeader();
+    result.append(res.data(), res.size());
 }
 
 void Track::appendDump(String8& result, bool active) const
@@ -1074,13 +1086,14 @@
             ? 'r' /* buffer reduced */: bufferSizeInFrames > mFrameCount
                     ? 'e' /* error */ : ' ' /* identical */;
 
-    result.appendFormat("%7s %6u %7u %7u %2s 0x%03X "
+    result.appendFormat("%7s %7u/%7u %7u %7u %2s 0x%03X "
                         "%08X %08X %6u "
                         "%2u %3x %2x "
-                        "%5.2g %5.2g %5.2g %5.2g%c %11.2g "
+                        "%5.2g %5.2g %5.2g %5.2g%c %11.2g %12s"
                         "%08X %6zu%c %6zu %c %9u%c %7u %10s %12s",
             active ? "yes" : "no",
-            (mClient == 0) ? getpid() : mClient->pid(),
+            mClient ? mClient->pid() : getpid() ,
+            mClient ? mClient->uid() : getuid(),
             mSessionId,
             mPortId,
             getTrackStateAsCodedString(),
@@ -1100,6 +1113,7 @@
             20.0 * log10(vsVolume.first), // VolumeShaper(s) total volume
             vsVolume.second ? 'A' : ' ',  // if any VolumeShapers active
             20.0 * log10(mVolume),
+            getPortMute() ? "true" : "false",
 
             mCblk->mServer,
             bufferSizeInFrames,
@@ -1606,8 +1620,25 @@
     if (mType != TYPE_PATCH) {
         // Do not recursively propagate a PatchTrack setPortVolume to
         // downstream PatchTracks.
-        forEachTeePatchTrack_l([volume](const auto& patchTrack) {
-                patchTrack->setPortVolume(volume); });
+        forEachTeePatchTrack_l([volume](const auto &patchTrack) {
+            patchTrack->setPortVolume(volume);
+        });
+    }
+}
+
+void Track::setPortMute(bool muted) {
+    mute_state_t newMuteState = mMuteState.load();
+    if (newMuteState.muteFromPortVolume == muted) {
+        return;
+    }
+    newMuteState.muteFromPortVolume = muted;
+    mMuteState.store(newMuteState);
+    if (mType != TYPE_PATCH) {
+        // Do not recursively propagate a PatchTrack setPortVolume to
+        // downstream PatchTracks.
+        forEachTeePatchTrack_l([muted](const auto &patchTrack) {
+            patchTrack->setPortMute(muted);
+        });
     }
 }
 
@@ -1712,8 +1743,8 @@
     }
 
     if (result == OK) {
-        ALOGI("%s(%d): processed mute state for port ID %d from %d to %d", __func__, id(), mPortId,
-                static_cast<int>(mMuteState), static_cast<int>(muteState));
+        ALOGI("%s(%d): processed mute state for port ID %d from %#x to %#x", __func__, id(),
+              mPortId, static_cast<int>(mMuteState.load()), static_cast<int>(muteState));
         mMuteState = muteState;
     } else {
         ALOGW("%s(%d): cannot process mute state for port ID %d, status error %d", __func__, id(),
@@ -2490,7 +2521,8 @@
                                          *  the lowest possible latency
                                          *  even if it might glitch. */
         float speed,
-        float volume)
+        float volume,
+        bool muted)
 {
     return sp<PatchTrack>::make(
             playbackThread,
@@ -2505,7 +2537,8 @@
             timeout,
             frameCountToBeReady,
             speed,
-            volume);
+            volume,
+            muted);
 }
 
 PatchTrack::PatchTrack(IAfPlaybackThread* playbackThread,
@@ -2520,14 +2553,15 @@
                                                      const Timeout& timeout,
                                                      size_t frameCountToBeReady,
                                                      float speed,
-                                                     float volume)
+                                                     float volume,
+                                                     bool muted)
     :   Track(playbackThread, NULL, streamType,
               AUDIO_ATTRIBUTES_INITIALIZER,
               sampleRate, format, channelMask, frameCount,
               buffer, bufferSize, nullptr /* sharedBuffer */,
               AUDIO_SESSION_NONE, getpid(), audioServerAttributionSource(getpid()), flags,
               TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady, speed,
-              false /*isSpatialized*/, false /*isBitPerfect*/, volume),
+              false /*isSpatialized*/, false /*isBitPerfect*/, volume, muted),
         PatchTrackBase(mCblk ? new AudioTrackClientProxy(mCblk, mBuffer, frameCount, mFrameSize,
                         true /*clientInServer*/) : nullptr,
                        playbackThread, timeout)
@@ -2977,21 +3011,20 @@
 
 void RecordTrack::appendDumpHeader(String8& result) const
 {
-    result.appendFormat("Active     Id Client Session Port Id  S  Flags  "
-                        " Format Chn mask  SRate Source  "
-                        " Server FrmCnt FrmRdy Sil%s\n",
-                        isServerLatencySupported() ? "   Latency" : "");
+    const auto res = IAfRecordTrack::getLogHeader();
+    result.append(res.data(), res.size());
 }
 
 void RecordTrack::appendDump(String8& result, bool active) const
 {
-    result.appendFormat("%c%5s %6d %6u %7u %7u  %2s 0x%03X "
+    result.appendFormat("%c%5s %6d %7u/%7u %7u %7u  %2s 0x%03X "
             "%08X %08X %6u %6X "
             "%08X %6zu %6zu %3c",
             isFastTrack() ? 'F' : ' ',
             active ? "yes" : "no",
             mId,
-            (mClient == 0) ? getpid() : mClient->pid(),
+            mClient ? mClient->pid() : getpid(),
+            mClient ? mClient->uid() : getuid(),
             mSessionId,
             mPortId,
             getTrackStateAsCodedString(),
@@ -3512,7 +3545,8 @@
           const android::content::AttributionSourceState& attributionSource,
           pid_t creatorPid,
           audio_port_handle_t portId,
-          float volume)
+          float volume,
+          bool muted)
 {
     return sp<MmapTrack>::make(
             thread,
@@ -3525,7 +3559,8 @@
             attributionSource,
             creatorPid,
             portId,
-            volume);
+            volume,
+            muted);
 }
 
 MmapTrack::MmapTrack(IAfThreadBase* thread,
@@ -3538,7 +3573,8 @@
         const AttributionSourceState& attributionSource,
         pid_t creatorPid,
         audio_port_handle_t portId,
-        float volume)
+        float volume,
+        bool muted)
     :   TrackBase(thread, NULL, attr, sampleRate, format,
                   channelMask, (size_t)0 /* frameCount */,
                   nullptr /* buffer */, (size_t)0 /* bufferSize */,
@@ -3549,14 +3585,17 @@
                   TYPE_DEFAULT, portId,
                   std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
         mPid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.pid))),
+        mUid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid))),
             mSilenced(false), mSilencedNotified(false), mVolume(volume)
 {
+    mMuteState.muteFromPortVolume = muted;
     // Once this item is logged by the server, the client can add properties.
     mTrackMetrics.logConstructor(creatorPid, uid(), id());
     if (isOut && (attr.usage == AUDIO_USAGE_CALL_ASSISTANT
             || attr.usage == AUDIO_USAGE_VIRTUAL_SOURCE)) {
         // Audio patch and call assistant volume are always max
         mVolume = 1.0f;
+        mMuteState.muteFromPortVolume = false;
     }
 }
 
@@ -3636,14 +3675,15 @@
 
 void MmapTrack::appendDumpHeader(String8& result) const
 {
-    result.appendFormat("Client Session Port Id  Format Chn mask  SRate Flags %s  %s\n",
-                        isOut() ? "Usg CT": "Source", isOut() ? "PortVol dB" : "");
+    const auto res = IAfMmapTrack::getLogHeader();
+    result.append(res.data(), res.size());
 }
 
 void MmapTrack::appendDump(String8& result, bool active __unused) const
 {
-    result.appendFormat("%6u %7u %7u %08X %08X %6u 0x%03X ",
+    result.appendFormat("%7u/%7u %7u %7u %08X %08X %6u 0x%03X ",
             mPid,
+            mUid,
             mSessionId,
             mPortId,
             mFormat,
@@ -3651,10 +3691,11 @@
             mSampleRate,
             mAttr.flags);
     if (isOut()) {
-        result.appendFormat("%3x %2x", mAttr.usage, mAttr.content_type);
+        result.appendFormat("%4x %2x", mAttr.usage, mAttr.content_type);
         result.appendFormat("%11.2g", 20.0 * log10(mVolume));
+        result.appendFormat("%12s", mMuteState.muteFromPortVolume ? "true" : "false");
     } else {
-        result.appendFormat("%6x", mAttr.source);
+        result.appendFormat("%7x", mAttr.source);
     }
     result.append("\n");
 }
diff --git a/services/audioflinger/afutils/DumpTryLock.h b/services/audioflinger/afutils/DumpTryLock.h
deleted file mode 100644
index 05e050e..0000000
--- a/services/audioflinger/afutils/DumpTryLock.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- * Copyright 2023, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <audio_utils/mutex.h>
-#include <utils/Mutex.h>
-
-namespace android::afutils {
-
-inline bool dumpTryLock(Mutex& mutex)
-{
-    static constexpr int kDumpLockTimeoutNs = 1'000'000'000;
-    const status_t err = mutex.timedLock(kDumpLockTimeoutNs);
-    return err == NO_ERROR;
-}
-
-// Note: the std::timed_mutex try_lock_for and try_lock_until methods are inefficient.
-// It is better to use std::mutex and call this method.
-//
-inline bool dumpTryLock(audio_utils::mutex& mutex) TRY_ACQUIRE(true, mutex)
-{
-    static constexpr int64_t kDumpLockTimeoutNs = 1'000'000'000;
-    return mutex.try_lock(kDumpLockTimeoutNs);
-}
-
-}  // android::afutils
diff --git a/services/audioflinger/afutils/FallibleLockGuard.h b/services/audioflinger/afutils/FallibleLockGuard.h
new file mode 100644
index 0000000..a2e66f6
--- /dev/null
+++ b/services/audioflinger/afutils/FallibleLockGuard.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <audio_utils/mutex.h>
+#include <utils/Mutex.h>
+
+#include <functional>
+
+namespace android::afutils {
+
+// Lock guard with a acquire timeout, which for the purpose of thread safety annotations acts as if
+// it has the capability (i.e. the thread annotations *lie*). Used for dump utilities, where if we
+// are deadlocked, we access without the lock since we are about to abort due to watchdog anyway.
+// If the lock was truly successfully acquired, unlock on dtor. Like all guards (if successful),
+// this guard is solely responsible for locking on ctor/unlocking on dtor, and the mutex reference
+// must be valid for the lifetime of the object
+class [[nodiscard]] SCOPED_CAPABILITY FallibleLockGuard {
+  public:
+    static constexpr int kDefaultTimeout = 1'000'000'000;
+
+    explicit FallibleLockGuard(Mutex& mutex, int64_t timeoutNs = kDefaultTimeout) ACQUIRE(mutex) {
+        if (mutex.timedLock(timeoutNs) == NO_ERROR) {
+            mUnlockFunc = [&mutex]() NO_THREAD_SAFETY_ANALYSIS { mutex.unlock(); };
+        }
+    }
+
+    explicit FallibleLockGuard(audio_utils::mutex& mutex, int64_t timeoutNs = kDefaultTimeout)
+            ACQUIRE(mutex) {
+        if (mutex.try_lock(timeoutNs)) {
+            mUnlockFunc = [&mutex]() NO_THREAD_SAFETY_ANALYSIS { mutex.unlock(); };
+        }
+    }
+
+    FallibleLockGuard(const FallibleLockGuard& other) = delete;
+
+    FallibleLockGuard(FallibleLockGuard&& other) {
+        mUnlockFunc.swap(other.mUnlockFunc);
+    }
+
+    FallibleLockGuard& operator=(const FallibleLockGuard& other) = delete;
+
+    // Return if the underlying lock was successfully locked
+    explicit operator bool() const { return static_cast<bool>(mUnlockFunc); }
+
+    ~FallibleLockGuard() RELEASE() {
+        if (mUnlockFunc) mUnlockFunc();
+    }
+
+  private:
+    std::function<void()> mUnlockFunc;
+};
+}  // android::afutils
diff --git a/services/audioflinger/datapath/AudioHwDevice.cpp b/services/audioflinger/datapath/AudioHwDevice.cpp
index 5314e9e..c2e538c 100644
--- a/services/audioflinger/datapath/AudioHwDevice.cpp
+++ b/services/audioflinger/datapath/AudioHwDevice.cpp
@@ -41,19 +41,20 @@
         AudioStreamOut **ppStreamOut,
         audio_io_handle_t handle,
         audio_devices_t deviceType,
-        audio_output_flags_t flags,
+        audio_output_flags_t *flags,
         struct audio_config *config,
         const char *address,
         const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
 {
 
     struct audio_config originalConfig = *config;
-    auto outputStream = new AudioStreamOut(this, flags);
+    auto outputStream = new AudioStreamOut(this);
 
     // Try to open the HAL first using the current format.
     ALOGV("openOutputStream(), try sampleRate %d, format %#x, channelMask %#x", config->sample_rate,
             config->format, config->channel_mask);
-    status_t status = outputStream->open(handle, deviceType, config, address, sourceMetadata);
+    status_t status = outputStream->open(handle, deviceType, config, flags, address,
+                                        sourceMetadata);
 
     if (status != NO_ERROR) {
         delete outputStream;
@@ -67,19 +68,25 @@
 
         // If the data is encoded then try again using wrapped PCM.
         const bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
-                && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
-                && ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
+                && ((*flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
+                && ((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
 
         if (wrapperNeeded) {
             if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
-                outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
-                status = outputStream->open(handle, deviceType, &originalConfig, address,
+                outputStream = new SpdifStreamOut(this, originalConfig.format);
+                status = outputStream->open(handle, deviceType, &originalConfig, flags, address,
                                             sourceMetadata);
                 if (status != NO_ERROR) {
                     ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
                         status);
                     delete outputStream;
                     outputStream = nullptr;
+                } else {
+                    // on success, we need to assign the actual HAL stream config so that clients
+                    // know and can later patch correctly.
+                    config->format = originalConfig.format;
+                    config->channel_mask = originalConfig.channel_mask;
+                    config->sample_rate = originalConfig.sample_rate;
                 }
             } else {
                 ALOGE("ERROR - openOutputStream(), SPDIFEncoder does not support format 0x%08x",
@@ -153,6 +160,12 @@
                         status);
                     delete inputStream;
                     inputStream = nullptr;
+                } else {
+                    // on success, we need to assign the actual HAL stream config so that clients
+                    // know and can later patch correctly.
+                    config->format = originalConfig.format;
+                    config->channel_mask = originalConfig.channel_mask;
+                    config->sample_rate = originalConfig.sample_rate;
                 }
             } else {
                 ALOGE("ERROR - openInputStream(), SPDIFDecoder does not support format 0x%08x",
diff --git a/services/audioflinger/datapath/AudioHwDevice.h b/services/audioflinger/datapath/AudioHwDevice.h
index e1a9018..6a35b91 100644
--- a/services/audioflinger/datapath/AudioHwDevice.h
+++ b/services/audioflinger/datapath/AudioHwDevice.h
@@ -85,7 +85,7 @@
             AudioStreamOut **ppStreamOut,
             audio_io_handle_t handle,
             audio_devices_t deviceType,
-            audio_output_flags_t flags,
+            audio_output_flags_t *flags,
             struct audio_config *config,
             const char *address,
             const std::vector<playback_track_metadata_v7_t>& sourceMetadata);
diff --git a/services/audioflinger/datapath/AudioStreamOut.cpp b/services/audioflinger/datapath/AudioStreamOut.cpp
index c65373e..7aadda3 100644
--- a/services/audioflinger/datapath/AudioStreamOut.cpp
+++ b/services/audioflinger/datapath/AudioStreamOut.cpp
@@ -30,9 +30,8 @@
 namespace android {
 
 // ----------------------------------------------------------------------------
-AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
+AudioStreamOut::AudioStreamOut(AudioHwDevice *dev)
         : audioHwDev(dev)
-        , flags(flags)
 {
 }
 
@@ -93,14 +92,16 @@
         audio_io_handle_t handle,
         audio_devices_t deviceType,
         struct audio_config *config,
+        audio_output_flags_t *flagsPtr,
         const char *address,
         const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
 {
     sp<StreamOutHalInterface> outStream;
 
-    const audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
-                ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
-                : flags;
+    audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
+                ? (audio_output_flags_t)(*flagsPtr | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+                : *flagsPtr;
+    *flagsPtr = flags = customFlags;
 
     int status = hwDev()->openOutputStream(
             handle,
diff --git a/services/audioflinger/datapath/AudioStreamOut.h b/services/audioflinger/datapath/AudioStreamOut.h
index 2bf94a1..1857099 100644
--- a/services/audioflinger/datapath/AudioStreamOut.h
+++ b/services/audioflinger/datapath/AudioStreamOut.h
@@ -37,16 +37,17 @@
 public:
     AudioHwDevice * const audioHwDev;
     sp<StreamOutHalInterface> stream;
-    const audio_output_flags_t flags;
+    audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
 
     [[nodiscard]] sp<DeviceHalInterface> hwDev() const;
 
-    AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags);
+    explicit AudioStreamOut(AudioHwDevice *dev);
 
     virtual status_t open(
             audio_io_handle_t handle,
             audio_devices_t deviceType,
             struct audio_config *config,
+            audio_output_flags_t *flagsPtr,
             const char *address,
             const std::vector<playback_track_metadata_v7_t>& sourceMetadata);
 
diff --git a/services/audioflinger/datapath/SpdifStreamIn.cpp b/services/audioflinger/datapath/SpdifStreamIn.cpp
index 98ce712..0090bc5 100644
--- a/services/audioflinger/datapath/SpdifStreamIn.cpp
+++ b/services/audioflinger/datapath/SpdifStreamIn.cpp
@@ -81,6 +81,11 @@
             outputDevice,
             outputDeviceAddress);
 
+    // reset config back to whatever is returned by HAL
+    config->sample_rate = customConfig.sample_rate;
+    config->format = customConfig.format;
+    config->channel_mask = customConfig.channel_mask;
+
     ALOGI("SpdifStreamIn::open() status = %d", status);
 
 #ifdef TEE_SINK
diff --git a/services/audioflinger/datapath/SpdifStreamOut.cpp b/services/audioflinger/datapath/SpdifStreamOut.cpp
index d3983b0..a565955 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.cpp
+++ b/services/audioflinger/datapath/SpdifStreamOut.cpp
@@ -33,10 +33,8 @@
  * PCM then we need to wrap the data in an SPDIF wrapper.
  */
 SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev,
-            audio_output_flags_t flags,
             audio_format_t format)
-        // Tell the HAL that the data will be compressed audio wrapped in a data burst.
-        : AudioStreamOut(dev, (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO))
+        : AudioStreamOut(dev)
         , mSpdifEncoder(this, format)
 {
 }
@@ -45,6 +43,7 @@
         audio_io_handle_t handle,
         audio_devices_t devices,
         struct audio_config *config,
+        audio_output_flags_t *flags,
         const char *address,
         const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
 {
@@ -63,6 +62,8 @@
 
     customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
     customConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    // Tell the HAL that the data will be compressed audio wrapped in a data burst.
+    *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
 
     // Always print this because otherwise it could be very confusing if the
     // HAL and AudioFlinger are using different formats.
@@ -76,9 +77,15 @@
             handle,
             devices,
             &customConfig,
+            flags,
             address,
             sourceMetadata);
 
+    // reset config back to whatever is returned by HAL
+    config->sample_rate = customConfig.sample_rate;
+    config->format = customConfig.format;
+    config->channel_mask = customConfig.channel_mask;
+
     ALOGI("SpdifStreamOut::open() status = %d", status);
 
 #ifdef TEE_SINK
diff --git a/services/audioflinger/datapath/SpdifStreamOut.h b/services/audioflinger/datapath/SpdifStreamOut.h
index 1cd8f65..3241d6f 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.h
+++ b/services/audioflinger/datapath/SpdifStreamOut.h
@@ -36,13 +36,13 @@
 class SpdifStreamOut : public AudioStreamOut {
 public:
 
-    SpdifStreamOut(AudioHwDevice *dev, audio_output_flags_t flags,
-            audio_format_t format);
+    SpdifStreamOut(AudioHwDevice *dev, audio_format_t format);
 
     status_t open(
             audio_io_handle_t handle,
             audio_devices_t devices,
             struct audio_config *config,
+            audio_output_flags_t *flags,
             const char *address,
             const std::vector<playback_track_metadata_v7_t>& sourceMetadata) override;
 
diff --git a/services/audioflinger/datapath/VolumeInterface.h b/services/audioflinger/datapath/VolumeInterface.h
index 1564fe1..02b6ade 100644
--- a/services/audioflinger/datapath/VolumeInterface.h
+++ b/services/audioflinger/datapath/VolumeInterface.h
@@ -25,7 +25,7 @@
     virtual void setMasterVolume(float value) = 0;
     virtual void setMasterBalance(float balance) = 0;
     virtual void setMasterMute(bool muted) = 0;
-    virtual void setStreamVolume(audio_stream_type_t stream, float value) = 0;
+    virtual void setStreamVolume(audio_stream_type_t stream, float value, bool muted) = 0;
     virtual void setStreamMute(audio_stream_type_t stream, bool muted) = 0;
     // TODO(b/290699744) add "get" prefix for getter below.
     virtual float streamVolume(audio_stream_type_t stream) const = 0;
diff --git a/services/audioflinger/datapath/VolumePortInterface.h b/services/audioflinger/datapath/VolumePortInterface.h
index fb1c463..fe3b782 100644
--- a/services/audioflinger/datapath/VolumePortInterface.h
+++ b/services/audioflinger/datapath/VolumePortInterface.h
@@ -23,7 +23,10 @@
 class VolumePortInterface : public virtual RefBase {
 public:
     virtual void setPortVolume(float volume) = 0;
+    virtual void setPortMute(bool mute) = 0;
     virtual float getPortVolume() const = 0;
+    /** Returns the muted state defined by the volume group which is playing on this port. */
+    virtual bool getPortMute() const = 0;
 };
 
 }  // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index e849bb4..3539f00 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -148,7 +148,8 @@
                                       output_type_t *outputType,
                                       bool *isSpatialized,
                                       bool *isBitPerfect,
-                                      float *volume) = 0;
+                                      float *volume,
+                                      bool *muted) = 0;
     // indicates to the audio policy manager that the output starts being used by corresponding
     // stream.
     virtual status_t startOutput(audio_port_handle_t portId) = 0;
@@ -197,6 +198,7 @@
     // setting volume for all devices
     virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
                                           int index,
+                                          bool muted,
                                           audio_devices_t device) = 0;
 
     // retrieve current volume index for the specified stream and the
@@ -208,6 +210,7 @@
 
     virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
                                                  int index,
+                                                 bool muted,
                                                  audio_devices_t device) = 0;
     virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
                                                  int &index,
@@ -478,7 +481,7 @@
                                 audio_config_base_t *mixerConfig,
                                 const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
-                                audio_output_flags_t flags,
+                                audio_output_flags_t *flags,
                                 audio_attributes_t audioAttributes) = 0;
     // creates a special output that is duplicated to the two outputs passed as arguments.
     // The duplication is performed by a special mixer thread in the AudioFlinger.
@@ -514,7 +517,7 @@
     // set a stream volume for a particular output. For the same user setting, a given stream type
     // can have different volumes
     // for each output (destination device) it is attached to.
-    virtual status_t setStreamVolume(audio_stream_type_t stream, float volume,
+    virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, bool muted,
                                      audio_io_handle_t output, int delayMs = 0) = 0;
     /**
      * Set volume for given AudioTrack port ids for a particular output.
@@ -522,12 +525,13 @@
      * can have different volumes for each output (destination device) it is attached to.
      * @param ports to consider
      * @param volume to apply
+     * @param muted to apply
      * @param output to consider
      * @param delayMs to use
      * @return NO_ERROR if successful
      */
     virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& ports, float volume,
-            audio_io_handle_t output, int delayMs = 0) = 0;
+            bool muted, audio_io_handle_t output, int delayMs = 0) = 0;
 
     // function enabling to send proprietary informations directly from audio policy manager to
     // audio hardware interface.
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index ee6af4c..d499222 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -26,6 +26,27 @@
 
 using StreamTypeVector = std::vector<audio_stream_type_t>;
 
+/**
+ * Legacy audio policy product strategies IDs. These strategies are supported by the default
+ * policy engine.
+ * IMPORTANT NOTE: the order of this enum is important as it determines the priority
+ * between active strategies for routing decisions: lower enum value => higher prioriy
+ */
+enum legacy_strategy {
+    STRATEGY_NONE = -1,
+    STRATEGY_PHONE,
+    STRATEGY_SONIFICATION,
+    STRATEGY_ENFORCED_AUDIBLE,
+    STRATEGY_ACCESSIBILITY,
+    STRATEGY_SONIFICATION_RESPECTFUL,
+    STRATEGY_MEDIA,
+    STRATEGY_DTMF,
+    STRATEGY_CALL_ASSISTANT,
+    STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
+    STRATEGY_REROUTING,
+    STRATEGY_PATCH,
+};
+
 static const audio_attributes_t defaultAttr = AUDIO_ATTRIBUTES_INITIALIZER;
 
 static const std::set<audio_usage_t > gHighPriorityUseCases = {
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index 4dedcd6..0e1d090 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -39,6 +39,7 @@
         "android.media.audiopolicy-aconfig-cc",
         "audioclient-types-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
+        "com.android.media.audio-aconfig-cc",
         "com.android.media.audioserver-aconfig-cc",
         "libaconfig_storage_read_api_cc",
         "libaudioclient_aidl_conversion",
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 3c296e7..9bceee7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -89,7 +89,9 @@
 class VolumeActivity : public ActivityTracking
 {
 public:
-    bool isMuted() const { return mMuteCount > 0; }
+    bool isMutedInternally() const { return mMuteCount > 0; }
+    bool isMutedByGroup() const { return mMutedByGroup > 0; }
+    void setMutedByGroup(bool mutedByGroup) { mMutedByGroup = mutedByGroup; }
     int getMuteCount() const { return mMuteCount; }
     int incMuteCount() { return ++mMuteCount; }
     int decMuteCount() { return mMuteCount > 0 ? --mMuteCount : -1; }
@@ -107,6 +109,7 @@
 
 private:
     int mMuteCount = 0; /**< mute request counter */
+    bool mMutedByGroup = false; /**< mute from AudioService, does not add to counter */
     float mCurVolumeDb = NAN; /**< current volume in dB. */
     bool mIsVoice = false; /** true if this volume source is used for voice call volume */
 };
@@ -209,16 +212,25 @@
         return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
                     mVolumeActivities.at(vs).getActivityCount() : 0;
     }
-    bool isMuted(VolumeSource vs) const
+    bool isMutedInternally(VolumeSource vs) const
     {
         return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
-                    mVolumeActivities.at(vs).isMuted() : false;
+                    mVolumeActivities.at(vs).isMutedInternally() : false;
     }
     int getMuteCount(VolumeSource vs) const
     {
         return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
                     mVolumeActivities.at(vs).getMuteCount() : 0;
     }
+    bool isMutedByGroup(VolumeSource vs)
+    {
+        return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
+               mVolumeActivities.at(vs).isMutedByGroup() : false;
+    }
+    bool hasVolumeSource(VolumeSource vs)
+    {
+        return mVolumeActivities.find(vs) != std::end(mVolumeActivities);
+    }
     int incMuteCount(VolumeSource vs)
     {
         return mVolumeActivities[vs].incMuteCount();
@@ -227,10 +239,11 @@
     {
         return mVolumeActivities[vs].decMuteCount();
     }
-    void setCurVolume(VolumeSource vs, float volumeDb, bool isVoiceVolSrc)
+    void setCurVolume(VolumeSource vs, float volumeDb, bool mutedByGroup, bool isVoiceVolSrc)
     {
         // Even if not activity for this source registered, need to create anyway
         mVolumeActivities[vs].setVolume(volumeDb);
+        mVolumeActivities[vs].setMutedByGroup(mutedByGroup);
         mVolumeActivities[vs].setIsVoice(isVoiceVolSrc);
     }
     float getCurVolume(VolumeSource vs) const
@@ -412,7 +425,7 @@
                       const audio_config_base_t *mixerConfig,
                       const DeviceVector &devices,
                       audio_stream_type_t stream,
-                      audio_output_flags_t flags,
+                      audio_output_flags_t *flags,
                       audio_io_handle_t *output,
                       audio_attributes_t attributes);
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 1f6002f..b193cb8 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -16,10 +16,10 @@
 
 #pragma once
 
+#include <optional>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
-#include <vector>
 
 #include <DeviceDescriptor.h>
 #include <HwModule.h>
@@ -49,6 +49,7 @@
     static const constexpr char* const kDefaultConfigSource = "AudioPolicyConfig::setDefault";
     // The suffix of the "engine default" implementation shared library name.
     static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
+    static const constexpr char* const kCapEngineLibraryNameSuffix = "configurable";
 
     // Creates the default (fallback) configuration.
     static sp<const AudioPolicyConfig> createDefault();
@@ -140,6 +141,12 @@
 
     void setDefault();
 
+    void setUseDeepBufferForMediaOverrideForTests(bool useDeepBufferForMedia)
+    {
+        mUseDeepBufferForMediaOverride = useDeepBufferForMedia;
+    }
+    bool useDeepBufferForMedia() const;
+
 private:
     friend class sp<AudioPolicyConfig>;
 
@@ -157,6 +164,7 @@
     sp<DeviceDescriptor> mDefaultOutputDevice;
     bool mIsCallScreenModeSupported = false;
     SurroundFormats mSurroundFormats;
+    std::optional<bool> mUseDeepBufferForMediaOverride;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index d206637..26bb94f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -137,6 +137,7 @@
 class HwModuleCollection : public Vector<sp<HwModule> >
 {
 public:
+    sp<HwModule> getModuleFromHandle(audio_module_handle_t handle) const;
     sp<HwModule> getModuleFromName(const char *name) const;
 
     /**
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
index fd8b81a..ebfc597 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
@@ -41,6 +41,8 @@
     virtual status_t initVolume(int indexMin, int indexMax) = 0;
     virtual std::vector<audio_attributes_t> getAttributes() const = 0;
     virtual std::vector<audio_stream_type_t> getStreamTypes() const = 0;
+    virtual void setIsMuted(bool isMuted) = 0;
+    virtual bool isMuted() const = 0;
     virtual void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const = 0;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 848051c..c417462 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -22,6 +22,7 @@
 #include <AudioPolicyInterface.h>
 #include "AudioOutputDescriptor.h"
 #include "AudioPolicyMix.h"
+#include <com_android_media_audio.h>
 #include "IOProfile.h"
 #include "Volume.h"
 #include "HwModule.h"
@@ -161,7 +162,7 @@
     return false;
 }
 
-bool AudioOutputDescriptor::setVolume(float volumeDb, bool /*muted*/,
+bool AudioOutputDescriptor::setVolume(float volumeDb, bool mutedByGroup,
                                       VolumeSource volumeSource,
                                       const StreamTypeVector &/*streams*/,
                                       const DeviceTypeSet& deviceTypes,
@@ -169,7 +170,6 @@
                                       bool force,
                                       bool isVoiceVolSrc)
 {
-
     if (!supportedDevices().containsDeviceAmongTypes(deviceTypes)) {
         ALOGV("%s output ID %d unsupported device %s",
                 __func__, getId(), toString(deviceTypes).c_str());
@@ -177,10 +177,14 @@
     }
     // We actually change the volume if:
     // - the float value returned by computeVolume() changed
+    // - the muted state changed
     // - the force flag is set
-    if (volumeDb != getCurVolume(volumeSource) || force) {
-        ALOGV("%s for volumeSrc %d, volume %f, delay %d", __func__, volumeSource, volumeDb, delayMs);
-        setCurVolume(volumeSource, volumeDb, isVoiceVolSrc);
+    const bool mutedChanged =
+            com_android_media_audio_ring_my_car() && (isMutedByGroup(volumeSource) != mutedByGroup);
+    if (volumeDb != getCurVolume(volumeSource) || mutedChanged  || force) {
+        ALOGV("%s for volumeSrc %d, volume %f, mutedByGroup %d,  delay %d", __func__, volumeSource,
+              volumeDb, mutedByGroup, delayMs);
+        setCurVolume(volumeSource, volumeDb, mutedByGroup, isVoiceVolSrc);
         return true;
     }
     return false;
@@ -497,7 +501,7 @@
 }
 
 void SwAudioOutputDescriptor::setSwMute(
-        bool muted, VolumeSource vs, const StreamTypeVector &streamTypes,
+        bool mutedByGroup, VolumeSource vs, const StreamTypeVector &streamTypes,
         const DeviceTypeSet& deviceTypes, uint32_t delayMs) {
     // volume source active and more than one volume source is active, otherwise, no-op or let
     // setVolume controlling SW and/or HW Gains
@@ -506,11 +510,11 @@
             for (const auto& devicePort : devices()) {
                 if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
                     devicePort->hasGainController(true /*canUseForVolume*/)) {
-                    float volumeAmpl = muted ? 0.0f : Volume::DbToAmpl(0);
                     ALOGV("%s: output: %d, vs: %d, muted: %d, active vs count: %zu", __func__,
-                          mIoHandle, vs, muted, getActiveVolumeSources().size());
+                          mIoHandle, vs, mutedByGroup, getActiveVolumeSources().size());
                     for (const auto &stream : streamTypes) {
-                        mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+                        mClientInterface->setStreamVolume(stream, Volume::DbToAmpl(0), mutedByGroup,
+                                                          mIoHandle, delayMs);
                     }
                     return;
                 }
@@ -521,11 +525,12 @@
             for (const auto &devicePort: devices()) {
                 if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
                     devicePort->hasGainController(true /*canUseForVolume*/)) {
-                    float volumeAmpl = muted ? 0.0f : Volume::DbToAmpl(0);
+                    float volumeAmpl = Volume::DbToAmpl(0);
                     ALOGV("%s: output: %d, vs: %d, muted: %d, active vs count: %zu", __func__,
-                          mIoHandle, vs, muted, getActiveVolumeSources().size());
+                          mIoHandle, vs, mutedByGroup, getActiveVolumeSources().size());
                     mClientInterface->setPortsVolume(
-                            getPortsForVolumeSource(vs), volumeAmpl, mIoHandle, delayMs);
+                            getPortsForVolumeSource(vs), Volume::DbToAmpl(0), mutedByGroup,
+                            mIoHandle, delayMs);
                     return;
                 }
             }
@@ -533,7 +538,7 @@
     }
 }
 
-bool SwAudioOutputDescriptor::setVolume(float volumeDb, bool muted,
+bool SwAudioOutputDescriptor::setVolume(float volumeDb, bool mutedByGroup,
                                         VolumeSource vs, const StreamTypeVector &streamTypes,
                                         const DeviceTypeSet& deviceTypes,
                                         uint32_t delayMs,
@@ -542,18 +547,22 @@
 {
     StreamTypeVector streams = streamTypes;
     if (!AudioOutputDescriptor::setVolume(
-            volumeDb, muted, vs, streamTypes, deviceTypes, delayMs, force, isVoiceVolSrc)) {
+            volumeDb, mutedByGroup, vs, streamTypes, deviceTypes, delayMs, force, isVoiceVolSrc)) {
         if (hasStream(streamTypes, AUDIO_STREAM_BLUETOOTH_SCO)) {
             VolumeSource callVolSrc = getVoiceSource();
-            if (callVolSrc != VOLUME_SOURCE_NONE && volumeDb != getCurVolume(callVolSrc)) {
-                setCurVolume(callVolSrc, volumeDb, true);
+            const bool mutedChanged =
+                    com_android_media_audio_ring_my_car() && hasVolumeSource(callVolSrc) &&
+                    (isMutedByGroup(callVolSrc) != mutedByGroup);
+            if (callVolSrc != VOLUME_SOURCE_NONE &&
+                (volumeDb != getCurVolume(callVolSrc) || mutedChanged)) {
+                setCurVolume(callVolSrc, volumeDb, mutedByGroup, true);
                 float volumeAmpl = Volume::DbToAmpl(volumeDb);
                 if (audioserver_flags::portid_volume_management()) {
                     mClientInterface->setPortsVolume(getPortsForVolumeSource(callVolSrc),
-                            volumeAmpl, mIoHandle, delayMs);
+                            volumeAmpl, mutedByGroup, mIoHandle, delayMs);
                 } else {
                     mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL,
-                            volumeAmpl, mIoHandle, delayMs);
+                            volumeAmpl, mutedByGroup, mIoHandle, delayMs);
                 }
             }
         }
@@ -580,18 +589,19 @@
                 // Allows to mute SW Gain on AudioFlinger only for volume group with explicit
                 // stream(s)
                 if (!streamTypes.empty() || (getActiveVolumeSources().size() == 1)) {
-                    const bool canMute = muted && (volumeDb != 0.0f) && !streamTypes.empty();
-                    float volumeAmpl = canMute ? 0.0f : Volume::DbToAmpl(0);
+                    const bool canMute = mutedByGroup && !streamTypes.empty();
+                    const float volumeAmpl = Volume::DbToAmpl(0);
                     for (const auto &stream: streams) {
-                        mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+                        mClientInterface->setStreamVolume(stream, volumeAmpl, canMute, mIoHandle,
+                                                          delayMs);
                     }
                 }
             } else {
-                float volumeAmpl = (muted && volumeDb != 0.0f) ? 0.0f : Volume::DbToAmpl(0);
+                float volumeAmpl = Volume::DbToAmpl(0);
                 ALOGV("%s: output: %d, vs: %d, active vs count: %zu", __func__,
                       mIoHandle, vs, getActiveVolumeSources().size());
                 mClientInterface->setPortsVolume(
-                        getPortsForVolumeSource(vs), volumeAmpl, mIoHandle, delayMs);
+                        getPortsForVolumeSource(vs), volumeAmpl, mutedByGroup, mIoHandle, delayMs);
             }
             AudioGains gains = devicePort->getGains();
             int gainMinValueInMb = gains[0]->getMinValueInMb();
@@ -615,26 +625,27 @@
         if (audioserver_flags::portid_volume_management()) {
             if (callVolSrc != VOLUME_SOURCE_NONE) {
                 mClientInterface->setPortsVolume(getPortsForVolumeSource(callVolSrc), volumeAmpl,
-                        mIoHandle, delayMs);
+                                                 mutedByGroup, mIoHandle, delayMs);
             }
         } else {
-            mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle,
-                    delayMs);
+            mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mutedByGroup,
+                                              mIoHandle, delayMs);
         }
         if (callVolSrc != VOLUME_SOURCE_NONE) {
-            setCurVolume(callVolSrc, getCurVolume(vs), true);
+            setCurVolume(callVolSrc, getCurVolume(vs), mutedByGroup, true);
         }
     }
     if (audioserver_flags::portid_volume_management()) {
-        ALOGV("%s output %d for volumeSource %d, volume %f, delay %d active=%d", __func__,
-              mIoHandle, vs, volumeDb, delayMs, isActive(vs));
-        mClientInterface->setPortsVolume(getPortsForVolumeSource(vs), volumeAmpl, mIoHandle,
-                                         delayMs);
+        ALOGV("%s output %d for volumeSource %d, volume %f, mutedByGroup %d, delay %d active=%d",
+              __func__, mIoHandle, vs, volumeDb, mutedByGroup, delayMs, isActive(vs));
+        mClientInterface->setPortsVolume(getPortsForVolumeSource(vs), volumeAmpl, mutedByGroup,
+                                         mIoHandle, delayMs);
     } else {
         for (const auto &stream : streams) {
-            ALOGV("%s output %d for volumeSource %d, volume %f, delay %d stream=%s", __func__,
-                  mIoHandle, vs, volumeDb, delayMs, toString(stream).c_str());
-            mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+            ALOGV("%s output %d for volumeSource %d, volume %f, mutedByGroup %d delay %d stream=%s",
+                  __func__, mIoHandle, vs, volumeDb, mutedByGroup, delayMs,
+                  toString(stream).c_str());
+            mClientInterface->setStreamVolume(stream, volumeAmpl, mutedByGroup, mIoHandle, delayMs);
         }
     }
     return true;
@@ -656,7 +667,7 @@
                                        const audio_config_base_t *mixerConfig,
                                        const DeviceVector &devices,
                                        audio_stream_type_t stream,
-                                       audio_output_flags_t flags,
+                                       audio_output_flags_t *flags,
                                        audio_io_handle_t *output,
                                        audio_attributes_t attributes)
 {
@@ -686,7 +697,7 @@
     // create a default one
     if ((mProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
             lHalConfig.offload_info.format == AUDIO_FORMAT_DEFAULT) {
-        flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+        *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
         lHalConfig.offload_info = AUDIO_INFO_INITIALIZER;
         lHalConfig.offload_info.sample_rate = lHalConfig.sample_rate;
         lHalConfig.offload_info.channel_mask = lHalConfig.channel_mask;
@@ -704,7 +715,7 @@
         lMixerConfig = *mixerConfig;
     }
 
-    mFlags = (audio_output_flags_t)(mFlags | flags);
+    mFlags = (audio_output_flags_t)(mFlags | *flags);
 
     // If no mixer config is specified for a spatializer output, default to 5.1 for proper
     // configuration of the final downmixer or spatializer
@@ -722,8 +733,9 @@
                                                    &lMixerConfig,
                                                    device,
                                                    &mLatency,
-                                                   mFlags,
+                                                   &mFlags,
                                                    attributes);
+    *flags = mFlags;
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index 4edd11f..723887d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "APM_Config"
 
+#include <android-base/properties.h>
 #include <AudioPolicyConfig.h>
 #include <IOProfile.h>
 #include <Serializer.h>
@@ -269,6 +270,9 @@
     mSurroundFormats = VALUE_OR_RETURN_STATUS(
             aidl2legacy_SurroundSoundConfig_SurroundFormats(aidl.surroundSoundConfig));
     mSource = kAidlConfigSource;
+    if (aidl.engineConfig.capSpecificConfig.has_value()) {
+        setEngineLibraryNameSuffix(kCapEngineLibraryNameSuffix);
+    }
     // No need to augmentData() as AIDL HAL must provide correct mic addresses.
     return NO_ERROR;
 }
@@ -338,7 +342,13 @@
                 AUDIO_FORMAT_AAC_XHE}},
         {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
         {AUDIO_FORMAT_E_AC3_JOC, {}},
-        {AUDIO_FORMAT_AC4, {}}};
+        {AUDIO_FORMAT_AC4, {}},     // L0-3
+        {AUDIO_FORMAT_AC4_L4, {}}};
+}
+
+bool AudioPolicyConfig::useDeepBufferForMedia() const {
+    if (mUseDeepBufferForMediaOverride.has_value()) return *mUseDeepBufferForMediaOverride;
+    return property_get_bool("audio.deep_buffer.media", false /* default_value */);
 }
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 6696b45..2d8231a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -283,6 +283,16 @@
     dumpAudioRouteVector(mRoutes, dst, spaces);
 }
 
+sp<HwModule> HwModuleCollection::getModuleFromHandle(audio_module_handle_t handle) const
+{
+    for (const auto& module : *this) {
+        if (module->getHandle() == handle) {
+            return module;
+        }
+    }
+    return nullptr;
+}
+
 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
 {
     for (const auto& module : *this) {
diff --git a/services/audiopolicy/config/surround_sound_configuration_5_0.xml b/services/audiopolicy/config/surround_sound_configuration_5_0.xml
index 590a181..6a268d8 100644
--- a/services/audiopolicy/config/surround_sound_configuration_5_0.xml
+++ b/services/audiopolicy/config/surround_sound_configuration_5_0.xml
@@ -27,5 +27,6 @@
     <format name="AUDIO_FORMAT_DTS_HD" />
     <format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
     <format name="AUDIO_FORMAT_AC4" />
+    <format name="AUDIO_FORMAT_AC4_L4" />
   </formats>
 </surroundSound>
diff --git a/services/audiopolicy/config/surround_sound_configuration_aidl.xml b/services/audiopolicy/config/surround_sound_configuration_aidl.xml
index cf15711..51ccaa9 100644
--- a/services/audiopolicy/config/surround_sound_configuration_aidl.xml
+++ b/services/audiopolicy/config/surround_sound_configuration_aidl.xml
@@ -30,5 +30,6 @@
     <format name="AUDIO_FORMAT_DTS_UHD_P2" />
     <format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
     <format name="AUDIO_FORMAT_AC4" />
+    <format name="AUDIO_FORMAT_AC4_L4" />
   </formats>
 </surroundSound>
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index d8aac37..7daa064 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -64,5 +64,6 @@
     ],
     defaults: [
         "aconfig_lib_cc_static_link.defaults",
+        "latest_android_media_audio_common_types_cpp_static",
     ],
 }
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index b9c94a4..edb2e29 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -129,6 +129,8 @@
 
     product_strategy_t getProductStrategyByName(const std::string &name) const;
 
+    std::string getProductStrategyName(product_strategy_t id) const;
+
     AudioPolicyManagerObserver *getApmObserver() const { return mApmObserver; }
 
     inline bool isInCall() const
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 1593be0..9b1125d 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -46,7 +46,7 @@
     using VolumeGroupAttributesVector = std::vector<VolumeGroupAttributes>;
 
 public:
-    ProductStrategy(const std::string &name);
+    ProductStrategy(const std::string &name, int id = PRODUCT_STRATEGY_NONE);
 
     void addAttributes(const VolumeGroupAttributes &volumeGroupAttributes);
 
@@ -92,6 +92,10 @@
 
     bool isDefault() const;
 
+    bool isPatchStrategy() const {
+        return getVolumeGroupForStreamType(AUDIO_STREAM_PATCH) != VOLUME_GROUP_NONE;
+    }
+
     void dump(String8 *dst, int spaces = 0) const;
 
 private:
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index 2e75ff1..e5f7a41 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -179,6 +179,12 @@
     }
     StreamTypeVector getStreamTypes() const override { return mStreams; }
 
+    void setIsMuted(bool isMuted)
+    {
+        mIsMuted = isMuted;
+    }
+    bool isMuted() const { return mIsMuted; }
+
     void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const override;
 
 private:
@@ -187,6 +193,7 @@
     int mIndexMin; /**< min volume index. */
     int mIndexMax; /**< max volume index. */
     const bool mCanBeMuted = true; /**< true is the stream can be muted. */
+    bool mIsMuted = false; /**< true if the stream is currently muted. */
 
     AttributesVector mAttributes;
     StreamTypeVector mStreams; /**< Keep it for legacy. */
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index e259e6e..fb8379e 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -116,6 +116,15 @@
     return PRODUCT_STRATEGY_NONE;
 }
 
+std::string EngineBase::getProductStrategyName(product_strategy_t id) const {
+    for (const auto &iter : mProductStrategies) {
+        if (iter.second->getId() == id) {
+            return iter.second->getName();
+        }
+    }
+    return "";
+}
+
 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(
         const media::audio::common::AudioHalEngineConfig& aidlConfig)
 {
@@ -240,7 +249,7 @@
         loadVolumeConfig(mVolumeGroups, volumeConfig);
     }
     for (auto& strategyConfig : result.parsedConfig->productStrategies) {
-        sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
+        sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name, strategyConfig.id);
         for (const auto &group : strategyConfig.attributesGroups) {
             const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
                                          [&group](const auto &volumeGroup) {
@@ -302,6 +311,9 @@
     }
     StrategyVector orderedStrategies;
     for (const auto &iter : strategies) {
+        if (iter.second->isPatchStrategy()) {
+            continue;
+        }
         orderedStrategies.push_back(iter.second->getId());
     }
     return orderedStrategies;
@@ -733,6 +745,9 @@
     auto defaultDevices = DeviceVector(getApmObserver()->getDefaultOutputDevice());
     for (const auto &iter : getProductStrategies()) {
         const auto &strategy = iter.second;
+        if (strategy->isPatchStrategy()) {
+            continue;
+        }
         mDevicesForStrategies[strategy->getId()] = defaultDevices;
         setStrategyDevices(strategy, defaultDevices);
     }
@@ -741,6 +756,9 @@
 void EngineBase::updateDeviceSelectionCache() {
     for (const auto &iter : getProductStrategies()) {
         const auto& strategy = iter.second;
+        if (strategy->isPatchStrategy()) {
+            continue;
+        }
         auto devices = getDevicesForProductStrategy(strategy->getId());
         mDevicesForStrategies[strategy->getId()] = devices;
         setStrategyDevices(strategy, devices);
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index 548a20d..c4bf64a 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -18,14 +18,17 @@
 
 #include <EngineConfig.h>
 
+#include <media/AudioProductStrategy.h>
+#include <policy.h>
 #include <system/audio.h>
 
 namespace android {
+
 /**
  * @brief AudioProductStrategies hard coded array of strategies to fill new engine API contract.
  */
 const engineConfig::ProductStrategies gOrderedStrategies = {
-    {"STRATEGY_PHONE",
+    {"STRATEGY_PHONE", STRATEGY_PHONE,
      {
          {AUDIO_STREAM_VOICE_CALL, "AUDIO_STREAM_VOICE_CALL",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_SOURCE_DEFAULT,
@@ -37,7 +40,7 @@
          }
      },
     },
-    {"STRATEGY_SONIFICATION",
+    {"STRATEGY_SONIFICATION", STRATEGY_SONIFICATION,
      {
          {AUDIO_STREAM_RING, "AUDIO_STREAM_RING",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
@@ -49,7 +52,7 @@
          }
      },
     },
-    {"STRATEGY_ENFORCED_AUDIBLE",
+    {"STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE,
      {
          {AUDIO_STREAM_ENFORCED_AUDIBLE, "AUDIO_STREAM_ENFORCED_AUDIBLE",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
@@ -57,7 +60,7 @@
          }
      },
     },
-    {"STRATEGY_ACCESSIBILITY",
+    {"STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY,
      {
          {AUDIO_STREAM_ACCESSIBILITY, "AUDIO_STREAM_ACCESSIBILITY",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
@@ -65,7 +68,7 @@
          }
      },
     },
-    {"STRATEGY_SONIFICATION_RESPECTFUL",
+    {"STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL,
      {
          {AUDIO_STREAM_NOTIFICATION, "AUDIO_STREAM_NOTIFICATION",
           {
@@ -77,7 +80,7 @@
          }
      },
     },
-    {"STRATEGY_MEDIA",
+    {"STRATEGY_MEDIA", STRATEGY_MEDIA,
      {
          {AUDIO_STREAM_ASSISTANT, "AUDIO_STREAM_ASSISTANT",
           {{AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
@@ -103,7 +106,7 @@
          }
      },
     },
-    {"STRATEGY_DTMF",
+    {"STRATEGY_DTMF", STRATEGY_DTMF,
      {
          {AUDIO_STREAM_DTMF, "AUDIO_STREAM_DTMF",
           {
@@ -113,7 +116,7 @@
          }
      },
     },
-    {"STRATEGY_CALL_ASSISTANT",
+    {"STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT,
      {
          {AUDIO_STREAM_CALL_ASSISTANT, "AUDIO_STREAM_CALL_ASSISTANT",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_CALL_ASSISTANT, AUDIO_SOURCE_DEFAULT,
@@ -121,7 +124,7 @@
          }
      },
     },
-    {"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
+    {"STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
      {
          {AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS",
           {
@@ -140,7 +143,7 @@
  * For compatibility reason why apm volume config file, volume group name is the stream type.
  */
 const engineConfig::ProductStrategies gOrderedSystemStrategies = {
-    {"STRATEGY_REROUTING",
+    {"STRATEGY_REROUTING", STRATEGY_REROUTING,
      {
          {AUDIO_STREAM_REROUTING, "AUDIO_STREAM_REROUTING",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VIRTUAL_SOURCE, AUDIO_SOURCE_DEFAULT,
@@ -148,7 +151,7 @@
          }
      },
     },
-    {"STRATEGY_PATCH",
+    {"STRATEGY_PATCH", STRATEGY_PATCH,
      {
          {AUDIO_STREAM_PATCH, "AUDIO_STREAM_PATCH",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index 0d25955..8ed7403 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -19,6 +19,7 @@
 
 #include "ProductStrategy.h"
 
+#include <android/media/audio/common/AudioHalProductStrategy.h>
 #include <media/AudioProductStrategy.h>
 #include <media/TypeConverter.h>
 #include <utils/String8.h>
@@ -30,11 +31,20 @@
 
 namespace android {
 
-ProductStrategy::ProductStrategy(const std::string &name) :
+using media::audio::common::AudioHalProductStrategy;
+
+/*
+ * Note on the id: either is provided (legacy strategies have hard coded id, aidl have
+ * own id, enforced to be started from VENDOR_STRATEGY_ID_START.
+ * REROUTING & PATCH system strategies are added.
+ * To prevent from collision, generate from VENDOR_STRATEGY_ID_START when id is not provided.
+ */
+ProductStrategy::ProductStrategy(const std::string &name, int id) :
     mName(name),
-    mId(static_cast<product_strategy_t>(HandleGenerator<uint32_t>::getNextHandle()))
-{
-}
+    mId((static_cast<product_strategy_t>(id) != PRODUCT_STRATEGY_NONE) ?
+            static_cast<product_strategy_t>(id) :
+            static_cast<product_strategy_t>(AudioHalProductStrategy::VENDOR_STRATEGY_ID_START +
+                    HandleGenerator<uint32_t>::getNextHandle())) {}
 
 void ProductStrategy::addAttributes(const VolumeGroupAttributes &volumeGroupAttributes)
 {
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
index ab2c134..d771605 100644
--- a/services/audiopolicy/engine/config/Android.bp
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -10,6 +10,9 @@
 
 cc_library {
     name: "libaudiopolicyengine_config",
+    defaults: [
+        "latest_android_media_audio_common_types_cpp_shared",
+    ],
     export_include_dirs: ["include"],
     include_dirs: [
         "external/libxml2/include",
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index 119dbd6..054bdae 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -71,6 +71,7 @@
 
 struct ProductStrategy {
     std::string name;
+    int id;
     AttributesGroups attributesGroups;
 };
 
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 3f9ae19..714ab78 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -20,7 +20,6 @@
 #include <sstream>
 #include <stdarg.h>
 #include <string>
-#include <string>
 #include <vector>
 #include <unordered_map>
 
@@ -42,6 +41,7 @@
 
 namespace android {
 
+using media::audio::common::AudioStreamType;
 using utilities::convertTo;
 
 namespace engineConfig {
@@ -66,6 +66,9 @@
                             STRATEGY_ENTRY(ACCESSIBILITY)};
 #undef STRATEGY_ENTRY
 
+    if (id >= media::audio::common::AudioHalProductStrategy::VENDOR_STRATEGY_ID_START) {
+        return std::to_string(id);
+    }
     auto it = productStrategyMap.find(id);
     if (it == productStrategyMap.end()) {
         return base::unexpected(BAD_VALUE);
@@ -76,8 +79,12 @@
 ConversionResult<AttributesGroup> aidl2legacy_AudioHalAttributeGroup_AttributesGroup(
         const media::audio::common::AudioHalAttributesGroup& aidl) {
     AttributesGroup legacy;
-    legacy.stream = VALUE_OR_RETURN(
-            aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
+    // StreamType may only be set to AudioStreamType.INVALID when using the
+    // Configurable Audio Policy (CAP) engine. An AudioHalAttributesGroup with
+    // AudioStreamType.INVALID is used when the volume group and attributes are
+    // not associated to any AudioStreamType.
+    legacy.stream = ((aidl.streamType == AudioStreamType::INVALID) ? AUDIO_STREAM_DEFAULT :
+            VALUE_OR_RETURN(aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType)));
     legacy.volumeGroup = aidl.volumeGroupName;
     legacy.attributesVect = VALUE_OR_RETURN(convertContainer<AttributesVector>(
                     aidl.attributes, aidl2legacy_AudioAttributes_audio_attributes_t));
@@ -87,8 +94,9 @@
 ConversionResult<ProductStrategy> aidl2legacy_AudioHalProductStrategy_ProductStrategy(
         const media::audio::common::AudioHalProductStrategy& aidl) {
     ProductStrategy legacy;
-    legacy.name = VALUE_OR_RETURN(
-                    aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id));
+    legacy.name = aidl.name.value_or(VALUE_OR_RETURN(
+                    aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id)));
+    legacy.id = aidl.id;
     legacy.attributesGroups = VALUE_OR_RETURN(convertContainer<AttributesGroups>(
                     aidl.attributesGroups,
                     aidl2legacy_AudioHalAttributeGroup_AttributesGroup));
@@ -148,7 +156,6 @@
                     aidl.volumeCurves, aidl2legacy_AudioHalVolumeCurve_VolumeCurve));
     return legacy;
 }
-
 }  // namespace
 
 template<typename E, typename C>
@@ -175,6 +182,7 @@
 
     struct Attributes {
         static constexpr const char *name = "name";
+        static constexpr const char *id = "id";
     };
     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &ps);
 };
@@ -533,13 +541,21 @@
         ALOGE("ProductStrategyTraits No attribute %s found", Attributes::name);
         return BAD_VALUE;
     }
+    int id = PRODUCT_STRATEGY_NONE;
+    std::string idLiteral = getXmlAttribute(child, Attributes::id);
+    if (!idLiteral.empty()) {
+        if (!convertTo(idLiteral, id)) {
+            return BAD_VALUE;
+        }
+        ALOGV("%s: %s, %s = %d", __FUNCTION__, name.c_str(), Attributes::id, id);
+    }
     ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
 
     size_t skipped = 0;
     AttributesGroups attrGroups;
     deserializeCollection<AttributesGroupTraits>(doc, child, attrGroups, skipped);
 
-    strategies.push_back({name, attrGroups});
+    strategies.push_back({name, id, attrGroups});
     return NO_ERROR;
 }
 
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index a0a4bdf..1c98faf 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -36,10 +36,10 @@
         "libbase_headers",
     ],
     static_libs: [
+        "libaudiopolicycapengine_config",
         "libaudiopolicyengine_common",
         "libaudiopolicyengine_config",
         "libaudiopolicyengineconfigurable_pfwwrapper",
-
     ],
     shared_libs: [
         "libaudio_aidl_conversion_common_cpp",
@@ -56,5 +56,13 @@
     ],
     defaults: [
         "aconfig_lib_cc_static_link.defaults",
+        "latest_android_media_audio_common_types_cpp_shared",
+    ],
+    required: [
+        "CapClass.xml",
+        "CapProductStrategies.xml",
+        "CapSubsystem-CommonTypes.xml",
+        "CapSubsystem.xml",
+        "ParameterFrameworkConfigurationCap.xml",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/config/Android.bp b/services/audiopolicy/engineconfigurable/config/Android.bp
index 8dd13e8..95a7cf8 100644
--- a/services/audiopolicy/engineconfigurable/config/Android.bp
+++ b/services/audiopolicy/engineconfigurable/config/Android.bp
@@ -38,6 +38,53 @@
 }
 
 filegroup {
+    name: "audio_policy_engine_aidl_criterion_types_template",
+    srcs: ["example/common/audio_policy_engine_criterion_types_aidl.xml.in"],
+}
+
+filegroup {
     name: "audio_policy_engine_criteria",
     srcs: ["example/common/audio_policy_engine_criteria.xml"],
 }
+
+cc_library_headers {
+    name: "libaudiopolicycapengine_config_headers",
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libaudiopolicycapengine_config",
+    defaults: [
+        "latest_android_media_audio_common_types_cpp_shared",
+    ],
+    export_header_lib_headers: [
+        "libaudiopolicycapengine_config_headers",
+    ],
+    include_dirs: [
+        "external/libxml2/include",
+    ],
+    srcs: [
+        "src/CapEngineConfig.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "libaudio_aidl_conversion_common_cpp",
+        "libaudiopolicycomponents",
+        "libaudiopolicyengine_config",
+        "libcutils",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+        "libxml2",
+    ],
+    header_libs: [
+        "libaudio_system_headers",
+        "libaudioclient_headers",
+        "libaudiopolicycapengine_config_headers",
+        "libmedia_headers",
+    ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
new file mode 100644
index 0000000..dc2517b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
@@ -0,0 +1,96 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<criterion_types>
+    <criterion_type name="OutputDevicesMaskType" type="inclusive"/>
+    <criterion_type name="InputDevicesMaskType" type="inclusive"/>
+    <criterion_type name="OutputDevicesAddressesType" type="inclusive">
+        <values>
+            <!-- legacy remote submix -->
+            <value literal="0" numerical="1"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="InputDevicesAddressesType" type="inclusive">
+        <values>
+            <!-- legacy remote submix -->
+            <value literal="0" numerical="1"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="AndroidModeType" type="exclusive"/>
+    <criterion_type name="ForceUseForCommunicationType" type="exclusive">
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="SPEAKER" numerical="1"/>
+            <value literal="BT_SCO" numerical="3"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForMediaType" type="exclusive">
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="SPEAKER" numerical="1"/>
+            <value literal="HEADPHONES" numerical="2"/>
+            <value literal="BT_A2DP" numerical="4"/>
+            <value literal="WIRED_ACCESSORY" numerical="5"/>
+            <value literal="ANALOG_DOCK" numerical="8"/>
+            <value literal="DIGITAL_DOCK" numerical="9"/>
+            <value literal="NO_BT_A2DP" numerical="10"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForRecordType" type="exclusive">
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="BT_SCO" numerical="3"/>
+            <value literal="WIRED_ACCESSORY" numerical="5"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForDockType" type="exclusive">
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="WIRED_ACCESSORY" numerical="5"/>
+            <value literal="BT_CAR_DOCK" numerical="6"/>
+            <value literal="BT_DESK_DOCK" numerical="7"/>
+            <value literal="ANALOG_DOCK" numerical="8"/>
+            <value literal="DIGITAL_DOCK" numerical="9"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForSystemType" type="exclusive" >
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="SYSTEM_ENFORCED" numerical="11"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForHdmiSystemAudioType" type="exclusive">
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="HDMI_SYSTEM_AUDIO_ENFORCED" numerical="12"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForEncodedSurroundType" type="exclusive">
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="ENCODED_SURROUND_NEVER" numerical="13"/>
+            <value literal="ENCODED_SURROUND_ALWAYS" numerical="14"/>
+            <value literal="ENCODED_SURROUND_MANUAL" numerical="15"/>
+        </values>
+    </criterion_type>
+    <criterion_type name="ForceUseForVibrateRingingType" type="exclusive">
+        <values>
+            <value literal="NONE" numerical="0"/>
+            <value literal="BT_SCO" numerical="3"/>
+        </values>
+    </criterion_type>
+</criterion_types>
+
+
diff --git a/services/audiopolicy/engineconfigurable/config/include/CapEngineConfig.h b/services/audiopolicy/engineconfigurable/config/include/CapEngineConfig.h
new file mode 100644
index 0000000..6c55a49
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/include/CapEngineConfig.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <EngineConfig.h>
+
+#include <android/media/audio/common/AudioHalEngineConfig.h>
+#include <system/audio_policy.h>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace capEngineConfig {
+
+static const char *const gCriterionTypeSuffix = "Type";
+static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
+static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
+static const char *const gPhoneStateCriterionName = "TelephonyMode";
+static const char *const gOutputDeviceAddressCriterionName = "AvailableOutputDevicesAddresses";
+static const char *const gInputDeviceAddressCriterionName = "AvailableInputDevicesAddresses";
+
+/**
+* Order MUST be aligned with definition of audio_policy_force_use_t within audio_policy.h
+*/
+static const char *const gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
+{
+    [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] =        "ForceUseForCommunication",
+    [AUDIO_POLICY_FORCE_FOR_MEDIA] =                "ForceUseForMedia",
+    [AUDIO_POLICY_FORCE_FOR_RECORD] =               "ForceUseForRecord",
+    [AUDIO_POLICY_FORCE_FOR_DOCK] =                 "ForceUseForDock",
+    [AUDIO_POLICY_FORCE_FOR_SYSTEM] =               "ForceUseForSystem",
+    [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] =    "ForceUseForHdmiSystemAudio",
+    [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] =     "ForceUseForEncodedSurround",
+    [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] =      "ForceUseForVibrateRinging"
+};
+
+using ParameterValues = std::vector<std::string>;
+
+struct ConfigurableElement {
+    std::string path;
+};
+
+struct ConfigurableElementValue {
+    ConfigurableElement configurableElement;
+    std::string value;
+};
+using ConfigurableElementValues = std::vector<ConfigurableElementValue>;
+
+struct CapSetting {
+    std::string configurationName;
+    ConfigurableElementValues configurableElementValues;
+};
+using CapSettings = std::vector<CapSetting>;
+
+struct CapConfiguration {
+    std::string name;
+    std::string rule;
+};
+
+using ConfigurableElementPaths = std::vector<std::string>;
+using CapConfigurations = std::vector<CapConfiguration>;
+
+struct CapConfigurableDomain {
+    std::string name;
+    CapConfigurations configurations;
+    CapSettings settings;
+};
+
+struct CapCriterion {
+    engineConfig::Criterion criterion;
+    engineConfig::CriterionType criterionType;
+};
+
+using CapCriteria = std::vector<CapCriterion>;
+using CapConfigurableDomains = std::vector<CapConfigurableDomain>;
+
+struct CapConfig {
+    CapCriteria capCriteria;
+    CapConfigurableDomains capConfigurableDomains;
+};
+
+/** Result of `parse(const char*)` */
+struct ParsingResult {
+    /** Parsed config, nullptr if the xml lib could not load the file */
+    std::unique_ptr<CapConfig> parsedConfig;
+    size_t nbSkippedElement; //< Number of skipped invalid product strategies
+};
+
+/** Convert the provided Cap Settings configuration.
+ * @return audio policy usage @see Config
+ */
+ParsingResult convert(const ::android::media::audio::common::AudioHalEngineConfig& aidlConfig);
+
+}
+}
diff --git a/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
new file mode 100644
index 0000000..a1b4470
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cinttypes>
+#include <cstdint>
+#include <istream>
+#include <map>
+#include <sstream>
+#include <stdarg.h>
+#include <string>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "APM::AudioPolicyEngine/CapConfig"
+//#define LOG_NDEBUG 0
+
+#include "CapEngineConfig.h"
+#include <TypeConverter.h>
+#include <Volume.h>
+#include <cutils/properties.h>
+#include <media/AidlConversion.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionUtil.h>
+#include <media/TypeConverter.h>
+#include <media/convert.h>
+#include <system/audio_config.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using utilities::convertTo;
+using media::audio::common::AudioDeviceAddress;
+using media::audio::common::AudioDeviceDescription;
+using media::audio::common::AudioHalCapCriterion;
+using media::audio::common::AudioHalCapParameter;
+using media::audio::common::AudioHalCapRule;
+using media::audio::common::AudioSource;
+using media::audio::common::AudioStreamType;
+using media::audio::common::AudioHalCapCriterionV2;
+using ::android::base::unexpected;
+
+namespace capEngineConfig {
+
+static constexpr const char *gLegacyOutputDevicePrefix = "AUDIO_DEVICE_OUT_";
+static constexpr const char *gLegacyInputDevicePrefix = "AUDIO_DEVICE_IN_";
+static constexpr const char *gLegacyStreamPrefix = "AUDIO_STREAM_";
+static constexpr const char *gLegacySourcePrefix = "AUDIO_SOURCE_";
+static constexpr const char *gPolicyParamPrefix = "/Policy/policy/";
+
+namespace {
+
+ConversionResult<std::string> truncatePrefixToLower(const std::string& legacyName,
+                                                    const std::string& legacyPrefix) {
+    std::size_t pos = legacyName.find(legacyPrefix);
+    if (pos == std::string::npos) {
+        return unexpected(BAD_VALUE);
+    }
+    std::string capName = legacyName.substr(pos + legacyPrefix.length());
+    std::transform(capName.begin(), capName.end(), capName.begin(),
+                   [](unsigned char c) { return std::tolower(c); });
+    return capName;
+}
+
+ConversionResult<std::string> truncatePrefix(const std::string& name,  const std::string& prefix) {
+    std::size_t pos = name.find(prefix);
+    if (pos == std::string::npos) {
+        return unexpected(BAD_VALUE);
+    }
+    std::string capName = name.substr(pos + prefix.length());
+    return capName;
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2_CapName(
+        const AudioHalCapCriterionV2& aidl) {
+    switch (aidl.getTag()) {
+        case AudioHalCapCriterionV2::availableInputDevices:
+            return gInputDeviceCriterionName;
+        case AudioHalCapCriterionV2::availableOutputDevices:
+            return gOutputDeviceCriterionName;
+        case AudioHalCapCriterionV2::availableInputDevicesAddresses:
+            return gInputDeviceAddressCriterionName;
+        case AudioHalCapCriterionV2::availableOutputDevicesAddresses:
+            return gOutputDeviceAddressCriterionName;
+        case AudioHalCapCriterionV2::telephonyMode:
+            return gPhoneStateCriterionName;
+        case AudioHalCapCriterionV2::forceConfigForUse: {
+            auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>();
+            return gForceUseCriterionTag[VALUE_OR_RETURN(
+                    aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
+                            aidlCriterion.forceUse))];
+        }
+        default:
+            return unexpected(BAD_VALUE);
+    }
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2TypeDevice_CapCriterionValue(
+        const AudioDeviceDescription& aidl) {
+    audio_devices_t legacyDeviceType = VALUE_OR_RETURN(
+            aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl));
+    bool isOut = audio_is_output_devices(legacyDeviceType);
+    std::string legacyTypeLiteral;
+    if (!::android::DeviceConverter::toString(legacyDeviceType, legacyTypeLiteral)) {
+        ALOGE("%s Invalid strategy device type %d", __func__, legacyDeviceType);
+        return unexpected(BAD_VALUE);
+    }
+    return truncatePrefix(legacyTypeLiteral,
+            isOut ? gLegacyOutputDevicePrefix : gLegacyInputDevicePrefix);
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2Type_CapCriterionValue(
+        const AudioHalCapCriterionV2::Type& aidl) {
+    switch (aidl.getTag()) {
+        case AudioHalCapCriterionV2::Type::availableDevicesType:
+            return aidl2legacy_AudioHalCapCriterionV2TypeDevice_CapCriterionValue(
+                    aidl.get<AudioHalCapCriterionV2::Type::availableDevicesType>());
+        case AudioHalCapCriterionV2::Type::availableDevicesAddressesType:
+            return aidl.get<AudioHalCapCriterionV2::Type::availableDevicesAddressesType>().template
+                    get<AudioDeviceAddress::id>();
+        case AudioHalCapCriterionV2::Type::telephonyModeType:
+            return toString(aidl.get<AudioHalCapCriterionV2::Type::telephonyModeType>());
+        case AudioHalCapCriterionV2::Type::forcedConfigType:
+            return toString(aidl.get<AudioHalCapCriterionV2::Type::forcedConfigType>());
+        default:
+            return unexpected(BAD_VALUE);
+    }
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapRule_CapRule(
+        const AudioHalCapRule& aidlRule) {
+    std::string rule;
+    switch (aidlRule.compoundRule) {
+        case AudioHalCapRule::CompoundRule::ANY:
+            rule += "Any";
+            break;
+        case AudioHalCapRule::CompoundRule::ALL:
+            rule += "All";
+            break;
+        default:
+            return unexpected(BAD_VALUE);
+    }
+    rule += "{";
+    if (!aidlRule.nestedRules.empty()) {
+        for (const auto& nestedRule: aidlRule.nestedRules) {
+            rule += VALUE_OR_FATAL(aidl2legacy_AudioHalCapRule_CapRule(nestedRule));
+        }
+        if (!aidlRule.criterionRules.empty()) {
+            rule += ",";
+        }
+    }
+    bool isFirstCriterionRule = true;
+    for (const auto& criterionRule: aidlRule.criterionRules) {
+        if (!isFirstCriterionRule) {
+            rule += ",";
+        }
+        isFirstCriterionRule = false;
+        std::string selectionCriterion = VALUE_OR_RETURN(
+                aidl2legacy_AudioHalCapCriterionV2_CapName(criterionRule.criterion));
+        std::string matchesWhen;
+        std::string value = VALUE_OR_RETURN(
+                aidl2legacy_AudioHalCapCriterionV2Type_CapCriterionValue(
+                        criterionRule.criterionTypeValue));
+
+        switch (criterionRule.matchingRule) {
+            case AudioHalCapRule::MatchingRule::IS:
+                matchesWhen = "Is";
+                break;
+            case AudioHalCapRule::MatchingRule::IS_NOT:
+                matchesWhen = "IsNot";
+                break;
+            case AudioHalCapRule::MatchingRule::INCLUDES:
+                matchesWhen = "Includes";
+                break;
+            case AudioHalCapRule::MatchingRule::EXCLUDES:
+                matchesWhen = "Excludes";
+                break;
+            default:
+                return unexpected(BAD_VALUE);
+        }
+        rule += selectionCriterion + " " + matchesWhen + " " + value;
+    }
+    rule += "}";
+    return rule;
+}
+
+ConversionResult<CapConfiguration> aidl2legacy_AudioHalCapConfiguration_CapConfiguration(
+        const media::audio::common::AudioHalCapConfiguration& aidl) {
+    CapConfiguration legacy;
+    legacy.name = aidl.name;
+    legacy.rule = VALUE_OR_FATAL(aidl2legacy_AudioHalCapRule_CapRule(aidl.rule));
+    return legacy;
+}
+
+ConversionResult<ConfigurableElementValue> aidl2legacy_ParameterSetting_ConfigurableElementValue(
+        const AudioHalCapParameter& aidl) {
+    ConfigurableElementValue legacy;
+    std::string literalValue;
+    switch (aidl.getTag()) {
+        case AudioHalCapParameter::selectedStrategyDevice: {
+            auto strategyDevice = aidl.get<AudioHalCapParameter::selectedStrategyDevice>();
+            literalValue = std::to_string(strategyDevice.isSelected);
+            audio_devices_t legacyType = VALUE_OR_RETURN(
+                    aidl2legacy_AudioDeviceDescription_audio_devices_t(strategyDevice.device));
+            std::string legacyTypeLiteral;
+            if (!::android::OutputDeviceConverter::toString(legacyType, legacyTypeLiteral)) {
+                ALOGE("%s Invalid device type %d", __func__, legacyType);
+                return unexpected(BAD_VALUE);
+            }
+            std::string deviceLiteral = VALUE_OR_RETURN(
+                    truncatePrefixToLower(legacyTypeLiteral, gLegacyOutputDevicePrefix));
+            if (deviceLiteral == "default") {
+                deviceLiteral = "stub";
+            }
+            legacy.configurableElement.path = std::string(gPolicyParamPrefix)
+                    + "product_strategies/vx_" + std::to_string(strategyDevice.id)
+                    + "/selected_output_devices/mask/" + deviceLiteral;
+            break;
+        }
+        case AudioHalCapParameter::strategyDeviceAddress: {
+            auto strategyAddress = aidl.get<AudioHalCapParameter::strategyDeviceAddress>();
+            legacy.configurableElement.path = std::string(gPolicyParamPrefix)
+                    + "product_strategies/vx_" + std::to_string(strategyAddress.id)
+                    + "/device_address";
+            literalValue = strategyAddress.deviceAddress.get<AudioDeviceAddress::id>();
+            break;
+        }
+        case AudioHalCapParameter::selectedInputSourceDevice: {
+            auto inputSourceDevice = aidl.get<AudioHalCapParameter::selectedInputSourceDevice>();
+            literalValue = std::to_string(inputSourceDevice.isSelected);
+            audio_devices_t legacyType = VALUE_OR_RETURN(
+                    aidl2legacy_AudioDeviceDescription_audio_devices_t(inputSourceDevice.device));
+            std::string legacyTypeLiteral;
+            if (!::android::InputDeviceConverter::toString(legacyType, legacyTypeLiteral)) {
+                ALOGE("%s Invalid input source device type %d", __func__, legacyType);
+                return unexpected(BAD_VALUE);
+            }
+            std::string deviceLiteral = VALUE_OR_RETURN(
+                    truncatePrefixToLower(legacyTypeLiteral, gLegacyInputDevicePrefix));
+            if (deviceLiteral == "default") {
+                deviceLiteral = "stub";
+            }
+            audio_source_t legacySource = VALUE_OR_RETURN(aidl2legacy_AudioSource_audio_source_t(
+                    inputSourceDevice.inputSource));
+            std::string inputSourceLiteral;
+            if (!::android::SourceTypeConverter::toString(legacySource, inputSourceLiteral)) {
+                ALOGE("%s Invalid input source  %d", __func__, legacySource);
+                return unexpected(BAD_VALUE);
+            }
+            inputSourceLiteral = VALUE_OR_RETURN(
+                    truncatePrefixToLower(inputSourceLiteral, gLegacySourcePrefix));
+            legacy.configurableElement.path = std::string(gPolicyParamPrefix) + "input_sources/"
+                    + inputSourceLiteral + "/applicable_input_device/mask/" + deviceLiteral;
+            break;
+        }
+        case AudioHalCapParameter::streamVolumeProfile: {
+            auto streamVolumeProfile = aidl.get<AudioHalCapParameter::streamVolumeProfile>();
+            audio_stream_type_t legacyStreamType = VALUE_OR_RETURN(
+                    aidl2legacy_AudioStreamType_audio_stream_type_t(streamVolumeProfile.stream));
+            std::string legacyStreamLiteral;
+            if (!::android::StreamTypeConverter::toString(legacyStreamType, legacyStreamLiteral)) {
+                ALOGE("%s Invalid stream type  %d", __func__, legacyStreamType);
+                return unexpected(BAD_VALUE);
+            }
+            legacyStreamLiteral = VALUE_OR_RETURN(
+                    truncatePrefixToLower(legacyStreamLiteral, gLegacyStreamPrefix));
+
+            audio_stream_type_t legacyProfile = VALUE_OR_RETURN(
+                    aidl2legacy_AudioStreamType_audio_stream_type_t(streamVolumeProfile.profile));
+            std::string legacyProfileLiteral;
+            if (!::android::StreamTypeConverter::toString(legacyProfile, legacyProfileLiteral)) {
+                ALOGE("%s Invalid profile %d", __func__, legacyProfile);
+                return unexpected(BAD_VALUE);
+            }
+            literalValue = VALUE_OR_RETURN(
+                    truncatePrefixToLower(legacyProfileLiteral, gLegacyStreamPrefix));
+            legacy.configurableElement.path = std::string(gPolicyParamPrefix) + "streams/"
+                    + legacyStreamLiteral + "/applicable_volume_profile/volume_profile";
+            break;
+        }
+        default:
+            return unexpected(BAD_VALUE);
+    }
+    legacy.value = literalValue;
+    return legacy;
+}
+
+ConversionResult<CapSetting> aidl2legacy_AudioHalCapConfiguration_CapSetting(
+        const media::audio::common::AudioHalCapConfiguration& aidl) {
+    CapSetting legacy;
+    legacy.configurationName = aidl.name;
+    legacy.configurableElementValues = VALUE_OR_RETURN(convertContainer<ConfigurableElementValues>(
+            aidl.parameterSettings, aidl2legacy_ParameterSetting_ConfigurableElementValue));
+    return legacy;
+}
+
+ConversionResult<CapConfigurableDomain> aidl2legacy_AudioHalCapDomain_CapConfigurableDomain(
+        const media::audio::common::AudioHalCapDomain& aidl) {
+    CapConfigurableDomain legacy;
+    legacy.name = aidl.name;
+    legacy.configurations = VALUE_OR_RETURN(convertContainer<CapConfigurations>(
+            aidl.configurations,
+            aidl2legacy_AudioHalCapConfiguration_CapConfiguration));
+    legacy.settings = VALUE_OR_RETURN(convertContainer<CapSettings>(
+            aidl.configurations,
+            aidl2legacy_AudioHalCapConfiguration_CapSetting));
+    return legacy;
+}
+
+ConversionResult<CapCriterion> aidl2legacy_AudioHalCapCriterionV2_Criterion(
+            const AudioHalCapCriterionV2& aidl) {
+    CapCriterion capCriterion;
+    engineConfig::Criterion& criterion = capCriterion.criterion;
+    engineConfig::CriterionType& criterionType = capCriterion.criterionType;
+
+    auto loadForceUseCriterion = [](const auto &aidlCriterion, auto &criterion,
+            auto &criterionType) -> status_t {
+        uint32_t legacyForceUse = VALUE_OR_RETURN_STATUS(
+                aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
+                        aidlCriterion.forceUse));
+        criterion.typeName = criterionType.name;
+        criterionType.name = criterion.typeName + gCriterionTypeSuffix;
+        criterionType.isInclusive =
+                (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+        criterion.name = gForceUseCriterionTag[legacyForceUse];
+        criterion.defaultLiteralValue = toString(aidlCriterion.defaultValue);
+        if (aidlCriterion.values.empty()) {
+            return BAD_VALUE;
+        }
+        for (auto &value : aidlCriterion.values) {
+            uint32_t legacyForcedConfig = VALUE_OR_RETURN_STATUS(
+                    aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(value));
+            criterionType.valuePairs.push_back({legacyForcedConfig, 0, toString(value)});
+        }
+        return NO_ERROR;
+    };
+
+    auto loadDevicesCriterion = [](const auto &aidlCriterion, auto &criterion,
+            auto &criterionType) -> status_t {
+        criterionType.name = criterion.name + gCriterionTypeSuffix;
+        criterionType.isInclusive =
+                (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+        criterion.typeName = criterionType.name;
+        int shift = 0;
+        if (aidlCriterion.values.empty()) {
+            return BAD_VALUE;
+        }
+        for (const auto &value : aidlCriterion.values) {
+            audio_devices_t legacyDeviceType = VALUE_OR_RETURN_STATUS(
+                    aidl2legacy_AudioDeviceDescription_audio_devices_t(value));
+            bool isOut = audio_is_output_devices(legacyDeviceType);
+            std::string legacyTypeLiteral;
+            if (!::android::DeviceConverter::toString(legacyDeviceType, legacyTypeLiteral)) {
+                ALOGE("%s Invalid device type %d", __func__, legacyDeviceType);
+                return BAD_VALUE;
+            }
+            std::string deviceLiteral = VALUE_OR_RETURN_STATUS(truncatePrefix(legacyTypeLiteral,
+                    isOut ? gLegacyOutputDevicePrefix : gLegacyInputDevicePrefix));
+            uint64_t pfwCriterionValue = 1 << shift++;
+            criterionType.valuePairs.push_back(
+                    {pfwCriterionValue, static_cast<int32_t>(legacyDeviceType), deviceLiteral});
+            ALOGV("%s: adding %" PRIu64 " %d %s %s", __func__, pfwCriterionValue, legacyDeviceType,
+                    toString(value.type).c_str(), deviceLiteral.c_str());
+        }
+        return NO_ERROR;
+    };
+
+    auto loadDeviceAddressesCriterion = [](const auto &aidlCriterion, auto &criterion,
+            auto &criterionType) -> status_t {
+        criterionType.name = criterion.name + gCriterionTypeSuffix;
+        criterionType.isInclusive =
+                (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+        criterion.typeName = criterionType.name;
+        int shift = 0;
+        for (auto &value : aidlCriterion.values) {
+            uint64_t pfwCriterionValue = 1 << shift++;
+            if (value.getTag() != AudioDeviceAddress::id) {
+                return BAD_VALUE;
+            }
+            std::string address = value.template get<AudioDeviceAddress::id>();
+            criterionType.valuePairs.push_back({pfwCriterionValue, 0, address});
+        }
+        return NO_ERROR;
+    };
+
+    switch (aidl.getTag()) {
+        case AudioHalCapCriterionV2::availableInputDevices: {
+            auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::availableInputDevices>();
+            criterion.name = gInputDeviceCriterionName;
+            if (loadDevicesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+                return unexpected(BAD_VALUE);
+            }
+            break;
+        }
+        case AudioHalCapCriterionV2::availableOutputDevices: {
+            auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::availableOutputDevices>();
+            criterion.name = gOutputDeviceCriterionName;
+            if (loadDevicesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+                return unexpected(BAD_VALUE);
+            }
+            break;
+        }
+        case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
+            auto aidlCriterion =
+                    aidl.get<AudioHalCapCriterionV2::availableInputDevicesAddresses>();
+            criterion.name = gInputDeviceAddressCriterionName;
+            if (loadDeviceAddressesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+                return unexpected(BAD_VALUE);
+            }
+            break;
+        }
+        case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
+            auto aidlCriterion =
+                    aidl.get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>();
+            criterion.name = gOutputDeviceAddressCriterionName;
+            if (loadDeviceAddressesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+                return unexpected(BAD_VALUE);
+            }
+            break;
+        }
+        case AudioHalCapCriterionV2::telephonyMode: {
+            auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::telephonyMode>();
+            criterion.name = gPhoneStateCriterionName;
+            criterionType.name = criterion.name  + gCriterionTypeSuffix;
+            criterionType.isInclusive =
+                    (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+            criterion.typeName = criterionType.name;
+            criterion.defaultLiteralValue = toString( aidlCriterion.defaultValue);
+            if (aidlCriterion.values.empty()) {
+                return unexpected(BAD_VALUE);
+            }
+            for (auto &value : aidlCriterion.values) {
+                uint32_t legacyMode =
+                        VALUE_OR_RETURN(aidl2legacy_AudioMode_audio_mode_t(value));
+                criterionType.valuePairs.push_back({legacyMode, 0, toString(value)});
+            }
+            break;
+        }
+        case AudioHalCapCriterionV2::forceConfigForUse: {
+            auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>();
+            if (loadForceUseCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+                return unexpected(BAD_VALUE);
+            }
+            break;
+        }
+        default:
+            return unexpected(BAD_VALUE);
+    }
+    return capCriterion;
+}
+
+}  // namespace
+
+ParsingResult convert(const ::android::media::audio::common::AudioHalEngineConfig& aidlConfig) {
+    auto config = std::make_unique<capEngineConfig::CapConfig>();
+
+    if (!aidlConfig.capSpecificConfig.has_value() ||
+            !aidlConfig.capSpecificConfig.value().domains.has_value()) {
+        ALOGE("%s: no Cap Engine config", __func__);
+        return ParsingResult{};
+    }
+    for (auto& aidlCriteria: aidlConfig.capSpecificConfig.value().criteriaV2.value()) {
+        if (aidlCriteria.has_value()) {
+            if (auto conv = aidl2legacy_AudioHalCapCriterionV2_Criterion(aidlCriteria.value());
+                    conv.ok()) {
+                config->capCriteria.push_back(std::move(conv.value()));
+            } else {
+                return ParsingResult{};
+            }
+        }
+    }
+    size_t skippedElement = 0;
+    for (auto& aidlDomain: aidlConfig.capSpecificConfig.value().domains.value()) {
+        if (aidlDomain.has_value()) {
+            if (auto conv = aidl2legacy_AudioHalCapDomain_CapConfigurableDomain(aidlDomain.value());
+                    conv.ok()) {
+                config->capConfigurableDomains.push_back(std::move(conv.value()));
+            } else {
+                return ParsingResult{};
+            }
+        } else {
+            skippedElement += 1;
+        }
+    }
+    return {.parsedConfig=std::move(config), .nbSkippedElement=skippedElement};
+}
+} // namespace capEngineConfig
+} // namespace android
diff --git a/services/audiopolicy/engineconfigurable/data/Android.bp b/services/audiopolicy/engineconfigurable/data/Android.bp
new file mode 100644
index 0000000..303cabc
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/Android.bp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_av_license"],
+}
+
+prebuilt_etc {
+    name: "CapClass.xml",
+    src: ":CapClass",
+    sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+    name: "CapSubsystem.xml",
+    src: ":CapSubsystem",
+    sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+    name: "CapSubsystem-CommonTypes.xml",
+    src: ":buildaidlcommontypesstructure_gen",
+    sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+    name: "CapProductStrategies.xml",
+    src: ":cap_product_strategies_structure",
+    sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+    name: "ParameterFrameworkConfigurationCap.xml",
+    src: ":ParameterFrameworkConfigurationCapSrc_gen",
+    sub_dir: "parameter-framework",
+}
+
+genrule {
+    name: "ParameterFrameworkConfigurationCapSrc_gen",
+    out: ["ParameterFrameworkConfigurationCap.xml"],
+    srcs: [":ParameterFrameworkConfigurationCapSrc"],
+    product_variables: {
+        debuggable: {
+            cmd: "sed -e 's|TuningAllowed=\"false\"|TuningAllowed=\"true\" ServerPort=\"unix:///dev/socket/audioserver/policy_debug\"|g' <$(in) > $(out)",
+        },
+    },
+    cmd: "cp -f $(in) $(out)",
+}
+
+genrule {
+    name: "buildaidlcommontypesstructure_gen",
+    defaults: ["buildcommontypesstructurerule"],
+    out: ["CapSubsystem-CommonTypes.xml"],
+}
+
+filegroup {
+    name: "ParameterFrameworkConfigurationCapSrc",
+    srcs: ["etc/ParameterFrameworkConfigurationCap.xml"],
+}
+
+filegroup {
+    name: "cap_product_strategies_structure",
+    srcs: ["etc/Structure/CapProductStrategies.xml"],
+}
+
+filegroup {
+    name: "CapSubsystem",
+    srcs: ["etc/Structure/CapSubsystem.xml"],
+}
+
+filegroup {
+    name: "aidl_common_types_structure_template",
+    srcs: ["etc/Structure/CapSubsystem-CommonTypes.xml.in"],
+}
+
+filegroup {
+    name: "CapClass",
+    srcs: ["etc/Structure/CapClass.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/data/etc/ParameterFrameworkConfigurationCap.xml b/services/audiopolicy/engineconfigurable/data/etc/ParameterFrameworkConfigurationCap.xml
new file mode 100644
index 0000000..bac7a25
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/ParameterFrameworkConfigurationCap.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    SystemClassName="Policy" TuningAllowed="false">
+
+    <SubsystemPlugins>
+        <Location Folder="">
+            <Plugin Name="libpolicy-subsystem.so"/>
+        </Location>
+    </SubsystemPlugins>
+    <StructureDescriptionFileLocation Path="Structure/Policy/CapClass.xml"/>
+</ParameterFrameworkConfiguration>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapClass.xml b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapClass.xml
new file mode 100644
index 0000000..e233673
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapClass.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SystemClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="../../Schemas/SystemClass.xsd" Name="Policy">
+    <SubsystemInclude Path="CapSubsystem.xml"/>
+</SystemClass>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapProductStrategies.xml b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapProductStrategies.xml
new file mode 100644
index 0000000..61f056a
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapProductStrategies.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xi="http://www.w3.org/2001/XInclude"
+              xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+  <!-- This structure is expected to be in the system partition and provisionned a maximum
+       allowed strategies to be used by vendor. -->
+  <ComponentType Name="ProductStrategies" Description="">
+    <Component Name="vx_1000" Type="ProductStrategy" Mapping="Identifier:1000,Name:vx_1000"/>
+    <Component Name="vx_1001" Type="ProductStrategy" Mapping="Identifier:1001,Name:vx_1001"/>
+    <Component Name="vx_1002" Type="ProductStrategy" Mapping="Identifier:1002,Name:vx_1002"/>
+    <Component Name="vx_1003" Type="ProductStrategy" Mapping="Identifier:1003,Name:vx_1003"/>
+    <Component Name="vx_1004" Type="ProductStrategy" Mapping="Identifier:1004,Name:vx_1004"/>
+    <Component Name="vx_1005" Type="ProductStrategy" Mapping="Identifier:1005,Name:vx_1005"/>
+    <Component Name="vx_1006" Type="ProductStrategy" Mapping="Identifier:1006,Name:vx_1006"/>
+    <Component Name="vx_1007" Type="ProductStrategy" Mapping="Identifier:1007,Name:vx_1007"/>
+    <Component Name="vx_1008" Type="ProductStrategy" Mapping="Identifier:1008,Name:vx_1008"/>
+    <Component Name="vx_1009" Type="ProductStrategy" Mapping="Identifier:1009,Name:vx_1009"/>
+    <Component Name="vx_1010" Type="ProductStrategy" Mapping="Identifier:1010,Name:vx_1010"/>
+    <Component Name="vx_1011" Type="ProductStrategy" Mapping="Identifier:1011,Name:vx_1011"/>
+    <Component Name="vx_1012" Type="ProductStrategy" Mapping="Identifier:1012,Name:vx_1012"/>
+    <Component Name="vx_1013" Type="ProductStrategy" Mapping="Identifier:1013,Name:vx_1013"/>
+    <Component Name="vx_1014" Type="ProductStrategy" Mapping="Identifier:1014,Name:vx_1014"/>
+    <Component Name="vx_1015" Type="ProductStrategy" Mapping="Identifier:1015,Name:vx_1015"/>
+    <Component Name="vx_1016" Type="ProductStrategy" Mapping="Identifier:1016,Name:vx_1016"/>
+    <Component Name="vx_1017" Type="ProductStrategy" Mapping="Identifier:1017,Name:vx_1017"/>
+    <Component Name="vx_1018" Type="ProductStrategy" Mapping="Identifier:1018,Name:vx_1018"/>
+    <Component Name="vx_1019" Type="ProductStrategy" Mapping="Identifier:1019,Name:vx_1019"/>
+    <Component Name="vx_1020" Type="ProductStrategy" Mapping="Identifier:1020,Name:vx_1020"/>
+    <Component Name="vx_1021" Type="ProductStrategy" Mapping="Identifier:1021,Name:vx_1021"/>
+    <Component Name="vx_1022" Type="ProductStrategy" Mapping="Identifier:1022,Name:vx_1022"/>
+    <Component Name="vx_1023" Type="ProductStrategy" Mapping="Identifier:1023,Name:vx_1023"/>
+    <Component Name="vx_1024" Type="ProductStrategy" Mapping="Identifier:1024,Name:vx_1024"/>
+    <Component Name="vx_1025" Type="ProductStrategy" Mapping="Identifier:1025,Name:vx_1025"/>
+    <Component Name="vx_1026" Type="ProductStrategy" Mapping="Identifier:1026,Name:vx_1026"/>
+    <Component Name="vx_1027" Type="ProductStrategy" Mapping="Identifier:1027,Name:vx_1027"/>
+    <Component Name="vx_1028" Type="ProductStrategy" Mapping="Identifier:1028,Name:vx_1028"/>
+    <Component Name="vx_1029" Type="ProductStrategy" Mapping="Identifier:1029,Name:vx_1029"/>
+    <Component Name="vx_1030" Type="ProductStrategy" Mapping="Identifier:1030,Name:vx_1030"/>
+    <Component Name="vx_1031" Type="ProductStrategy" Mapping="Identifier:1031,Name:vx_1031"/>
+    <Component Name="vx_1032" Type="ProductStrategy" Mapping="Identifier:1032,Name:vx_1032"/>
+    <Component Name="vx_1033" Type="ProductStrategy" Mapping="Identifier:1033,Name:vx_1033"/>
+    <Component Name="vx_1034" Type="ProductStrategy" Mapping="Identifier:1034,Name:vx_1034"/>
+    <Component Name="vx_1035" Type="ProductStrategy" Mapping="Identifier:1035,Name:vx_1035"/>
+    <Component Name="vx_1036" Type="ProductStrategy" Mapping="Identifier:1036,Name:vx_1036"/>
+    <Component Name="vx_1037" Type="ProductStrategy" Mapping="Identifier:1037,Name:vx_1037"/>
+    <Component Name="vx_1038" Type="ProductStrategy" Mapping="Identifier:1038,Name:vx_1038"/>
+    <Component Name="vx_1039" Type="ProductStrategy" Mapping="Identifier:1039,Name:vx_1039"/>
+  </ComponentType>
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem-CommonTypes.xml.in b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem-CommonTypes.xml.in
new file mode 100644
index 0000000..2c4c7b5
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem-CommonTypes.xml.in
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xi="http://www.w3.org/2001/XInclude"
+              xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+    <!-- Output devices definition as a bitfield for the supported devices per output
+    profile. It must match with the output device enum parameter.
+    -->
+     <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
+
+     <!--#################### GLOBAL COMPONENTS END ####################-->
+
+    <!-- Automatically filled from audio-base.h file -->
+    <ComponentType Name="OutputDevicesMask" Description="64bit representation of devices">
+        <BitParameterBlock Name="mask" Size="64">
+        </BitParameterBlock>
+    </ComponentType>
+
+    <!-- Input devices definition as a bitfield for the supported devices per Input
+    profile. It must match with the Input device enum parameter.
+    -->
+    <!-- Automatically filled from audio-base.h file -->
+    <ComponentType Name="InputDevicesMask" Description="64bit representation of devices">
+        <BitParameterBlock Name="mask" Size="64">
+        </BitParameterBlock>
+    </ComponentType>
+
+    <!--#################### STREAM COMMON TYPES BEGIN ####################-->
+    <!-- Automatically filled from audio-base.h file. VolumeProfileType is associated to stream type -->
+    <ComponentType Name="VolumeProfileType">
+        <EnumParameter Name="volume_profile" Size="32">
+        </EnumParameter>
+    </ComponentType>
+
+    <ComponentType Name="Stream"  Mapping="Stream">
+        <Component Name="applicable_volume_profile" Type="VolumeProfileType"
+                   Description="Volume profile followed by a given stream type."/>
+    </ComponentType>
+
+    <!--#################### STREAM COMMON TYPES END ####################-->
+
+    <!--#################### INPUT SOURCE COMMON TYPES BEGIN ####################-->
+
+    <ComponentType Name="InputSource">
+        <Component Name="applicable_input_device" Type="InputDevicesMask"
+                   Mapping="InputSource" Description="Selected Input device"/>
+    </ComponentType>
+
+    <!--#################### INPUT SOURCE COMMON TYPES END ####################-->
+
+    <!--#################### PRODUCT STRATEGY COMMON TYPES BEGIN ####################-->
+
+    <ComponentType Name="ProductStrategy" Mapping="ProductStrategy">
+        <Component Name="selected_output_devices" Type="OutputDevicesMask"/>
+        <StringParameter Name="device_address" MaxLength="256"
+                         Description="if any, device address associated"/>
+    </ComponentType>
+
+    <!--#################### PRODUCT STRATEGY COMMON TYPES END ####################-->
+
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem.xml b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem.xml
new file mode 100644
index 0000000..45a0bd4
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<Subsystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xmlns:xi="http://www.w3.org/2001/XInclude"
+           xsi:noNamespaceSchemaLocation="Schemas/Subsystem.xsd"
+           Name="policy" Type="Policy">
+
+    <ComponentLibrary>
+        <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
+        <!-- Common Types definition -->
+        <xi:include href="CapSubsystem-CommonTypes.xml"/>
+        <xi:include href="CapProductStrategies.xml"/>
+
+
+        <!--#################### GLOBAL COMPONENTS END ####################-->
+
+        <!--#################### STREAM BEGIN ####################-->
+
+        <ComponentType Name="Streams" Description="associated to audio_stream_type_t definition">
+            <Component Name="voice_call" Type="Stream" Mapping="Name:AUDIO_STREAM_VOICE_CALL"/>
+            <Component Name="system" Type="Stream" Mapping="Name:AUDIO_STREAM_SYSTEM"/>
+            <Component Name="ring" Type="Stream" Mapping="Name:AUDIO_STREAM_RING"/>
+            <Component Name="music" Type="Stream" Mapping="Name:AUDIO_STREAM_MUSIC"/>
+            <Component Name="alarm" Type="Stream" Mapping="Name:AUDIO_STREAM_ALARM"/>
+            <Component Name="notification" Type="Stream" Mapping="Name:AUDIO_STREAM_NOTIFICATION"/>
+            <Component Name="bluetooth_sco" Type="Stream" Mapping="Name:AUDIO_STREAM_BLUETOOTH_SCO"/>
+            <Component Name="enforced_audible" Type="Stream" Mapping="Name:AUDIO_STREAM_ENFORCED_AUDIBLE"
+                       Description="Sounds that cannot be muted by user and must be routed to speaker"/>
+            <Component Name="dtmf" Type="Stream" Mapping="Name:AUDIO_STREAM_DTMF"/>
+            <Component Name="tts" Type="Stream" Mapping="Name:AUDIO_STREAM_TTS"
+                             Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
+            <Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
+                             Description="For accessibility talk back prompts"/>
+            <Component Name="assistant" Type="Stream" Mapping="Name:AUDIO_STREAM_ASSISTANT"
+                             Description="used by a virtual assistant like Google Assistant, Bixby, etc."/>
+            <Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
+                             Description="For dynamic policy output mixes"/>
+            <Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
+                             Description="For internal audio flinger tracks. Fixed volume"/>
+        </ComponentType>
+
+        <!--#################### STREAM END ####################-->
+
+        <!--#################### INPUT SOURCE BEGIN ####################-->
+
+        <ComponentType Name="InputSources" Description="associated to audio_source_t definition,
+                             identifier mapping must match the value of the enum">
+            <Component Name="default" Type="InputSource" Mapping="Name:AUDIO_SOURCE_DEFAULT"/>
+            <Component Name="mic" Type="InputSource" Mapping="Name:AUDIO_SOURCE_MIC"/>
+            <Component Name="voice_uplink" Type="InputSource"
+                                           Mapping="Name:AUDIO_SOURCE_VOICE_UPLINK"/>
+            <Component Name="voice_downlink" Type="InputSource"
+                                             Mapping="Name:AUDIO_SOURCE_VOICE_DOWNLINK"/>
+            <Component Name="voice_call" Type="InputSource"
+                                         Mapping="Name:AUDIO_SOURCE_VOICE_CALL"/>
+            <Component Name="camcorder" Type="InputSource" Mapping="Name:AUDIO_SOURCE_CAMCORDER"/>
+            <Component Name="voice_recognition" Type="InputSource"
+                                                Mapping="Name:AUDIO_SOURCE_VOICE_RECOGNITION"/>
+            <Component Name="voice_communication" Type="InputSource"
+                                                  Mapping="Name:AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+            <Component Name="remote_submix" Type="InputSource"
+                                            Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
+            <Component Name="unprocessed" Type="InputSource"
+                                            Mapping="Name:AUDIO_SOURCE_UNPROCESSED"/>
+            <Component Name="voice_performance" Type="InputSource"
+                                            Mapping="Name:AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+            <Component Name="echo_reference" Type="InputSource"
+                                            Mapping="Name:AUDIO_SOURCE_ECHO_REFERENCE"/>
+            <Component Name="fm_tuner" Type="InputSource" Mapping="Name:AUDIO_SOURCE_FM_TUNER"/>
+            <Component Name="hotword" Type="InputSource" Mapping="Name:AUDIO_SOURCE_HOTWORD"/>
+        </ComponentType>
+        <!--#################### INPUT SOURCE END ####################-->
+    </ComponentLibrary>
+
+    <InstanceDefinition>
+        <Component Name="streams" Type="Streams"/>
+        <Component Name="input_sources" Type="InputSources"/>
+        <Component Name="product_strategies" Type="ProductStrategies"/>
+    </InstanceDefinition>
+</Subsystem>
diff --git a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
index 9fd8b8e..e0b7210 100644
--- a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
+++ b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
@@ -98,7 +98,8 @@
     virtual bool setDeviceTypesForProductStrategy(product_strategy_t strategy,
                                                   uint64_t devices) = 0;
 
-    virtual product_strategy_t getProductStrategyByName(const std::string &address) = 0;
+    virtual product_strategy_t getProductStrategyByName(const std::string &name) = 0;
+    virtual std::string getProductStrategyName(product_strategy_t id) const = 0;
 
 protected:
     virtual ~AudioPolicyPluginInterface() {}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
index 7fe111f..e4f44d5 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
@@ -50,6 +50,7 @@
 genrule {
     name: "buildcommontypesstructure_gen",
     defaults: ["buildcommontypesstructurerule"],
+    out: ["PolicySubsystem-CommonTypes.xml"],
 }
 
 filegroup {
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
index c9a77a4..27a290f 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
@@ -45,4 +45,7 @@
         "libparameter",
         "libutils",
     ],
+    defaults: [
+        "aconfig_lib_cc_shared_link.defaults",
+    ],
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
index 8bd7f66..bf5767d 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
@@ -72,7 +72,7 @@
         );
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<ProductStrategy>(
-            mProductStrategyComponentName, (1 << MappingKeyName))
+            mProductStrategyComponentName, (1 << MappingKeyName) | (1 << MappingKeyIdentifier))
         );
 }
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
index ebd9456..06efbf28 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
@@ -18,10 +18,7 @@
 #include "PolicyMappingKeys.h"
 #include "PolicySubsystem.h"
 
-using std::string;
-using android::product_strategy_t;
-
-ProductStrategy::ProductStrategy(const string &mappingValue,
+ProductStrategy::ProductStrategy(const std::string &mappingValue,
                    CInstanceConfigurableElement *instanceConfigurableElement,
                    const CMappingContext &context,
                    core::log::Logger& logger)
@@ -30,26 +27,32 @@
                                 mappingValue,
                                 MappingKeyAmend1,
                                 (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
-                                context)
-{
-    std::string name(context.getItem(MappingKeyName));
+                                context) {
+
+    size_t id = context.getItemAsInteger(MappingKeyIdentifier);
+    std::string nameFromStructure(context.getItem(MappingKeyName));
 
     ALOG_ASSERT(instanceConfigurableElement != nullptr, "Invalid Configurable Element");
     mPolicySubsystem = static_cast<const PolicySubsystem *>(
-                instanceConfigurableElement->getBelongingSubsystem());
+            instanceConfigurableElement->getBelongingSubsystem());
     ALOG_ASSERT(mPolicySubsystem != nullptr, "Invalid Policy Subsystem");
 
     mPolicyPluginInterface = mPolicySubsystem->getPolicyPluginInterface();
     ALOG_ASSERT(mPolicyPluginInterface != nullptr, "Invalid Policy Plugin Interface");
 
-    mId = mPolicyPluginInterface->getProductStrategyByName(name);
+    mId = static_cast<android::product_strategy_t>(id);
+    std::string name = mPolicyPluginInterface->getProductStrategyName(mId);
+    if (name.empty()) {
+        name = nameFromStructure;
+        mId = mPolicyPluginInterface->getProductStrategyByName(name);
+    }
 
     ALOG_ASSERT(mId != PRODUCT_STRATEGY_INVALID, "Product Strategy %s not found", name.c_str());
 
     ALOGE("Product Strategy %s added", name.c_str());
 }
 
-bool ProductStrategy::sendToHW(string & /*error*/)
+bool ProductStrategy::sendToHW(std::string & /*error*/)
 {
     Device deviceParams;
     blackboardRead(&deviceParams, sizeof(deviceParams));
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index ccd4316..45da7b0 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -71,27 +71,75 @@
 }
 
 status_t Engine::loadFromHalConfigWithFallback(
-        const media::audio::common::AudioHalEngineConfig& config __unused) {
-    // b/242678729. Need to implement for the configurable engine.
-    return INVALID_OPERATION;
-}
+        const media::audio::common::AudioHalEngineConfig& aidlConfig) {
 
-status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
-{
-    status_t loadResult = loadAudioPolicyEngineConfig(xmlFilePath);
-    if (loadResult < 0) {
-        ALOGE("Policy Engine configuration is invalid.");
+    auto capResult = capEngineConfig::convert(aidlConfig);
+    if (capResult.parsedConfig == nullptr) {
+        ALOGE("%s CapEngine Config invalid", __func__);
+        return BAD_VALUE;
     }
-    return loadResult;
-}
-
-status_t Engine::initCheck()
-{
+    status_t ret = loadWithFallback(aidlConfig);
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+    auto loadCriteria= [this](const auto& capCriteria) {
+        for (auto& capCriterion : capCriteria) {
+            mPolicyParameterMgr->addCriterion(capCriterion.criterion.name,
+                    capCriterion.criterionType.isInclusive,
+                    capCriterion.criterionType.valuePairs,
+                    capCriterion.criterion.defaultLiteralValue);
+        }
+    };
+    loadCriteria(capResult.parsedConfig->capCriteria);
     std::string error;
     if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
         ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
         return NO_INIT;
     }
+    return mPolicyParameterMgr->setConfiguration(capResult);
+}
+
+status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
+{
+    status_t status = loadWithFallback(xmlFilePath);
+    std::string error;
+    if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
+        ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
+        return NO_INIT;
+    }
+    return status;
+}
+
+template<typename T>
+status_t Engine::loadWithFallback(const T& configSource) {
+    auto result = EngineBase::loadAudioPolicyEngineConfig(configSource);
+    ALOGE_IF(result.nbSkippedElement != 0,
+             "Policy Engine configuration is partially invalid, skipped %zu elements",
+             result.nbSkippedElement);
+
+    auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
+        for (auto& criterion : configCriteria) {
+            engineConfig::CriterionType criterionType;
+            for (auto &configCriterionType : configCriterionTypes) {
+                if (configCriterionType.name == criterion.typeName) {
+                    criterionType = configCriterionType;
+                    break;
+                }
+            }
+            ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
+                        criterion.name.c_str());
+            mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
+                                              criterionType.valuePairs,
+                                              criterion.defaultLiteralValue);
+        }
+    };
+
+    loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
+    return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
+}
+
+status_t Engine::initCheck()
+{
     return EngineBase::initCheck();
 }
 
@@ -199,32 +247,6 @@
     return EngineBase::setDeviceConnectionState(device, state);
 }
 
-status_t Engine::loadAudioPolicyEngineConfig(const std::string& xmlFilePath)
-{
-    auto result = EngineBase::loadAudioPolicyEngineConfig(xmlFilePath);
-
-    // Custom XML Parsing
-    auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
-        for (auto& criterion : configCriteria) {
-            engineConfig::CriterionType criterionType;
-            for (auto &configCriterionType : configCriterionTypes) {
-                if (configCriterionType.name == criterion.typeName) {
-                    criterionType = configCriterionType;
-                    break;
-                }
-            }
-            ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
-                        criterion.name.c_str());
-            mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
-                                              criterionType.valuePairs,
-                                              criterion.defaultLiteralValue);
-        }
-    };
-
-    loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
-    return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
-}
-
 status_t Engine::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
                                            const AudioDeviceTypeAddrVector &devices)
 {
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 4f3e620..d9ebbe7 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -16,10 +16,11 @@
 
 #pragma once
 
-#include "EngineBase.h"
-#include <EngineInterface.h>
-#include <AudioPolicyPluginInterface.h>
 #include "Collection.h"
+#include "EngineBase.h"
+#include <AudioPolicyPluginInterface.h>
+#include <CapEngineConfig.h>
+#include <EngineInterface.h>
 
 namespace android {
 class AudioPolicyManagerObserver;
@@ -107,8 +108,14 @@
     {
         return EngineBase::getProductStrategyByName(name);
     }
+    std::string getProductStrategyName(product_strategy_t id) const override {
+        return EngineBase::getProductStrategyName(id);
+    }
 
 private:
+    template<typename T>
+    status_t loadWithFallback(const T& configSource);
+
     android::status_t disableDevicesForStrategy(product_strategy_t strategy,
             const DeviceVector &devicesToDisable);
     void enableDevicesForStrategy(product_strategy_t strategy, const DeviceVector &devicesToEnable);
@@ -140,8 +147,6 @@
     template <typename Property, typename Key>
     bool setPropertyForKey(const Property &property, const Key &key);
 
-    status_t loadAudioPolicyEngineConfig(const std::string& xmlFilePath);
-
     DeviceVector getCachedDevices(product_strategy_t ps) const;
 
     ///
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index d1fb2fb..7ae124c 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -23,7 +23,7 @@
 }
 
 //##################################################################################################
-// Tools for audio policy engine criterion type configuration file
+// Legacy tools for audio policy engine criterion type configuration file
 //
 python_binary_host {
     name: "buildPolicyCriterionTypes",
@@ -57,6 +57,40 @@
 }
 
 //##################################################################################################
+// Tools for audio policy engine criterion type configuration file
+//
+python_binary_host {
+    name: "capBuildPolicyCriterionTypes",
+    main: "capBuildPolicyCriterionTypes.py",
+    srcs: [
+        "capBuildPolicyCriterionTypes.py",
+    ],
+}
+
+genrule_defaults {
+    name: "capbuildpolicycriteriontypesrule",
+    tools: ["capBuildPolicyCriterionTypes"],
+    cmd: "cp $(locations :audio_policy_configuration_files) $(genDir)/. && " +
+        "cp $(location :audio_policy_configuration_top_file) $(genDir)/audio_policy_configuration.xml && " +
+        "$(location capBuildPolicyCriterionTypes) " +
+        " --androidaudiobaseheader $(location :libaudio_system_audio_base) " +
+        " --androidaudiocommonbaseheader $(location :libaudio_system_audio_common_base) " +
+        "--audiopolicyconfigurationfile $(genDir)/audio_policy_configuration.xml " +
+        "--criteriontypes $(location :audio_policy_engine_aidl_criterion_types_template) " +
+        "--outputfile $(out)",
+    srcs: [
+        // The commented inputs must be provided to use this genrule_defaults
+        // @todo uncomment if 1428659 is merged":android_audio_base_header_file",
+        ":audio_policy_engine_aidl_criterion_types_template",
+        ":libaudio_system_audio_base",
+        ":libaudio_system_audio_common_base",
+        // ":audio_policy_configuration_top_file",
+        // ":audio_policy_configuration_files",
+    ],
+    out: ["audio_policy_engine_criterion_types.xml"],
+}
+
+//##################################################################################################
 // Tools for audio policy engine parameter framework configurable domains
 //
 python_binary_host {
@@ -84,6 +118,7 @@
     cmd: "mkdir -p $(genDir)/Structure/Policy && " +
         "cp $(locations :audio_policy_pfw_structure_files) $(genDir)/Structure/Policy && " +
         "cp $(location :audio_policy_pfw_toplevel) $(genDir)/top_level && " +
+        "sed -i -e 's|TuningAllowed=\"false\"|TuningAllowed=\"true\" ServerPort=\"unix:///dev/socket/audioserver/policy_debug\"|g' $(genDir)/top_level &&" +
         "$(location domainGeneratorPolicy) " +
         "--validate " +
         "--domain-generator-tool $(location domainGeneratorConnector) " +
@@ -106,7 +141,7 @@
 }
 
 //##################################################################################################
-// Tools for policy parameter-framework product strategies structure file generation
+// Legacy tools for policy parameter-framework product strategies structure file generation
 //
 python_binary_host {
     name: "buildStrategiesStructureFile",
@@ -154,5 +189,4 @@
         ":common_types_structure_template",
         ":libaudio_system_audio_base",
     ],
-    out: ["PolicySubsystem-CommonTypes.xml"],
 }
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
index f69d346..6eabc57 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -75,7 +75,7 @@
     strategy_components = strategies_root.find('ComponentType')
 
     for strategy_name in strategies:
-        context_mapping = "".join(map(str, ["Name:", strategy_name]))
+        context_mapping = "".join(map(str, ["Identifier:-1,Name:", strategy_name]))
         strategy_pfw_name = strategy_name.replace('STRATEGY_', '').lower()
         ET.SubElement(strategy_components, "Component",
                       Name=strategy_pfw_name, Type="ProductStrategy",
diff --git a/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
new file mode 100755
index 0000000..b873830
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
@@ -0,0 +1,368 @@
+#!/usr/bin/python3
+
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import argparse
+import re
+import sys
+import os
+import logging
+import xml.etree.ElementTree as ET
+import xml.etree.ElementInclude as EI
+import xml.dom.minidom as MINIDOM
+from collections import OrderedDict
+
+#
+# Helper script that helps to feed at build time the XML criterion types file used by
+# the engineconfigurable to start the parameter-framework.
+# It prevents to fill them manually and avoid divergences with android.
+#
+# The Device Types criterion types are fed from audio-base.h file with the option
+#           --androidaudiobaseheader <path/to/android/audio/base/file/audio-base.h>
+#
+# The Device Addresses criterion types are fed from the audio policy configuration file
+# in order to discover all the devices for which the address matter.
+#           --audiopolicyconfigurationfile <path/to/audio_policy_configuration.xml>
+#
+# The reference file of criterion types must also be set as an input of the script:
+#           --criteriontypes <path/to/criterion/file/audio_criterion_types.xml.in>
+#
+# At last, the output of the script shall be set also:
+#           --outputfile <path/to/out/vendor/etc/audio_criterion_types.xml>
+#
+
+def parseArgs():
+    argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+                                        audio criterion type file generator.\n\
+                                        Exit with the number of (recoverable or not) \
+                                        error that occurred.")
+    argparser.add_argument('--androidaudiobaseheader',
+                           help="Android Audio Base C header file, Mandatory.",
+                           metavar="ANDROID_AUDIO_BASE_HEADER",
+                           type=argparse.FileType('r'),
+                           required=True)
+    argparser.add_argument('--androidaudiocommonbaseheader',
+                           help="Android Audio CommonBase C header file, Mandatory.",
+                           metavar="ANDROID_AUDIO_COMMON_BASE_HEADER",
+                           type=argparse.FileType('r'),
+                           required=True)
+    argparser.add_argument('--audiopolicyconfigurationfile',
+                           help="Android Audio Policy Configuration file, Mandatory.",
+                           metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
+                           type=argparse.FileType('r'),
+                           required=True)
+    argparser.add_argument('--criteriontypes',
+                           help="Criterion types XML base file, in \
+                           '<criterion_types> \
+                               <criterion_type name="" type=<inclusive|exclusive> \
+                               values=<value1,value2,...>/>' \
+                           format. Mandatory.",
+                           metavar="CRITERION_TYPE_FILE",
+                           type=argparse.FileType('r'),
+                           required=True)
+    argparser.add_argument('--outputfile',
+                           help="Criterion types outputfile file. Mandatory.",
+                           metavar="CRITERION_TYPE_OUTPUT_FILE",
+                           type=argparse.FileType('w'),
+                           required=True)
+    argparser.add_argument('--verbose',
+                           action='store_true')
+
+    return argparser.parse_args()
+
+
+output_devices_type_value = {}
+input_devices_type_value = {}
+
+def generateXmlCriterionTypesFile(criterionTypes, addressCriteria, criterionTypesFile, outputFile):
+
+    logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
+    criterion_types_in_tree = ET.parse(criterionTypesFile)
+
+    criterion_types_root = criterion_types_in_tree.getroot()
+
+    for criterion_name, values_dict in criterionTypes.items():
+        for criterion_type in criterion_types_root.findall('criterion_type'):
+            if criterion_type.get('name') == criterion_name:
+                values_node = ET.SubElement(criterion_type, "values")
+                ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
+                for key, value in ordered_values.items():
+                    value_node = ET.SubElement(values_node, "value")
+                    value_node.set('numerical', str(value))
+                    value_node.set('literal', key)
+
+                    if criterion_type.get('name') == "OutputDevicesMaskType":
+                        value_node.set('android_type', output_devices_type_value[key])
+                    if criterion_type.get('name') == "InputDevicesMaskType":
+                        value_node.set('android_type', input_devices_type_value[key])
+
+    if addressCriteria:
+        for criterion_name, values_list in addressCriteria.items():
+            for criterion_type in criterion_types_root.findall('criterion_type'):
+                if criterion_type.get('name') == criterion_name:
+                    index = 0
+                    existing_values_node = criterion_type.find("values")
+                    if existing_values_node is not None:
+                        for existing_value in existing_values_node.findall('value'):
+                            if existing_value.get('numerical') == str(1 << index):
+                                index += 1
+                        values_node = existing_values_node
+                    else:
+                        values_node = ET.SubElement(criterion_type, "values")
+
+                    for value in values_list:
+                        value_node = ET.SubElement(values_node, "value", literal=value)
+                        value_node.set('numerical', str(1 << index))
+                        index += 1
+
+    xmlstr = ET.tostring(criterion_types_root, encoding='utf8', method='xml')
+    reparsed = MINIDOM.parseString(xmlstr)
+    prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
+    prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
+    outputFile.write(prettyXmlStr)
+
+def capitalizeLine(line):
+    return ' '.join((w.capitalize() for w in line.split(' ')))
+
+
+#
+# Parse the audio policy configuration file and output a dictionary of device criteria addresses
+#
+def parseAndroidAudioPolicyConfigurationFile(audiopolicyconfigurationfile):
+
+    logging.info("Checking Audio Policy Configuration file {}".format(audiopolicyconfigurationfile))
+    #
+    # extract all devices addresses from audio policy configuration file
+    #
+    address_criteria_mapping_table = {
+        'sink' : "OutputDevicesAddressesType",
+        'source' : "InputDevicesAddressesType"}
+
+    address_criteria = {
+        'OutputDevicesAddressesType' : [],
+        'InputDevicesAddressesType' : []}
+
+    old_working_dir = os.getcwd()
+    print("Current working directory %s" % old_working_dir)
+
+    new_dir = os.path.join(old_working_dir, audiopolicyconfigurationfile.name)
+
+    policy_in_tree = ET.parse(audiopolicyconfigurationfile)
+    os.chdir(os.path.dirname(os.path.normpath(new_dir)))
+
+    print("new working directory %s" % os.getcwd())
+
+    policy_root = policy_in_tree.getroot()
+    EI.include(policy_root)
+
+    os.chdir(old_working_dir)
+
+    for device in policy_root.iter('devicePort'):
+        for key in address_criteria_mapping_table.keys():
+            if device.get('role') == key and device.get('address'):
+                logging.info("{}: <{}>".format(key, device.get('address')))
+                address_criteria[address_criteria_mapping_table[key]].append(device.get('address'))
+
+    for criteria in address_criteria:
+        values = ','.join(address_criteria[criteria])
+        logging.info("{}: <{}>".format(criteria, values))
+
+    return address_criteria
+
+#
+# Parse the audio-base.h file and output a dictionary of android dependent criterion types:
+#   -Android Mode
+#   -Output devices type
+#   -Input devices type
+#
+def parseAndroidAudioFile(androidaudiobaseheaderFile, androidaudiocommonbaseheaderFile):
+    #
+    # Adaptation table between Android Enumeration prefix and Audio PFW Criterion type names
+    #
+    criterion_mapping_table = {
+        'HAL_AUDIO_MODE' : "AndroidModeType",
+        'AUDIO_DEVICE_OUT' : "OutputDevicesMaskType",
+        'AUDIO_DEVICE_IN' : "InputDevicesMaskType"}
+
+    all_criteria = {
+        'AndroidModeType' : {},
+        'OutputDevicesMaskType' : {},
+        'InputDevicesMaskType' : {}}
+
+    #
+    # _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
+    #
+    ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
+
+    multi_bit_outputdevice_shift = 32
+    multi_bit_inputdevice_shift = 32
+
+    criteria_pattern = re.compile(
+        r"\s*V\((?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
+        r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*,\s*" \
+        r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])?[0-9a-fA-F]+|[0-9]+)")
+
+    logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
+
+    for line_number, line in enumerate(androidaudiobaseheaderFile):
+        match = criteria_pattern.match(line)
+        if match:
+            logging.debug("The following line is VALID: {}:{}\n{}".format(
+                androidaudiobaseheaderFile.name, line_number, line))
+
+            criterion_name = criterion_mapping_table[match.groupdict()['type']]
+            criterion_literal = ''.join(match.groupdict()['literal'])
+            criterion_numerical_value = match.groupdict()['values']
+
+            if criterion_name == "InputDevicesMaskType":
+                # Remove ambient and in_communication since they were deprecated
+                logging.info("Remove deprecated device {}".format(criterion_literal))
+                if criterion_literal == "AMBIENT" or criterion_literal == "COMMUNICATION":
+                    logging.info("Remove deprecated device {}".format(criterion_literal))
+                    continue
+                # for AUDIO_DEVICE_IN: rename default to stub
+                elif criterion_literal == "DEFAULT":
+                    criterion_numerical_value = str(int("0x40000000", 0))
+                    input_devices_type_value[criterion_literal] = "0xC0000000"
+                else:
+                    try:
+                        string_int = int(criterion_numerical_value, 0)
+                        # Append AUDIO_DEVICE_IN for android type tag
+                        input_devices_type_value[criterion_literal] = hex(string_int | 2147483648)
+
+                        num_bits = bin(string_int).count("1")
+                        if num_bits > 1:
+                            logging.info("The value {}:{} is for criterion {} binary rep {} has {} bits sets"
+                                .format(criterion_numerical_value, criterion_literal, criterion_name, bin(string_int), num_bits))
+                            string_int = 2**multi_bit_inputdevice_shift
+                            logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+                            multi_bit_inputdevice_shift += 1
+                            criterion_numerical_value = str(string_int)
+
+                    except ValueError:
+                        # Handle the exception
+                        logging.info("value {}:{} for criterion {} is not a number, ignoring"
+                            .format(criterion_numerical_value, criterion_literal, criterion_name))
+                        continue
+
+            if criterion_name == "OutputDevicesMaskType":
+                if criterion_literal == "DEFAULT":
+                    criterion_numerical_value = str(int("0x40000000", 0))
+                    output_devices_type_value[criterion_literal] = "0x40000000"
+                else:
+                    try:
+                        string_int = int(criterion_numerical_value, 0)
+                        output_devices_type_value[criterion_literal] = criterion_numerical_value
+
+                        num_bits = bin(string_int).count("1")
+                        if num_bits > 1:
+                            logging.info("The value {}:{} is for criterion {} binary rep {} has {} bits sets"
+                                .format(criterion_numerical_value, criterion_literal, criterion_name, bin(string_int), num_bits))
+                            string_int = 2**multi_bit_outputdevice_shift
+                            logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+                            multi_bit_outputdevice_shift += 1
+                            criterion_numerical_value = str(string_int)
+
+                    except ValueError:
+                        # Handle the exception
+                        logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+                            .format(criterion_numerical_value, criterion_literal, criterion_name))
+                        continue
+
+            try:
+                string_int = int(criterion_numerical_value, 0)
+
+            except ValueError:
+                # Handle the exception
+                logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+                    .format(criterion_numerical_value, criterion_literal, criterion_name))
+                continue
+
+            # Remove duplicated numerical values
+            if int(criterion_numerical_value, 0) in all_criteria[criterion_name].values():
+                logging.info("criterion {} duplicated values:".format(criterion_name))
+                logging.info("{}:{}".format(criterion_numerical_value, criterion_literal))
+                logging.info("KEEPING LATEST")
+                for key in list(all_criteria[criterion_name]):
+                    if all_criteria[criterion_name][key] == int(criterion_numerical_value, 0):
+                        del all_criteria[criterion_name][key]
+
+            all_criteria[criterion_name][criterion_literal] = int(criterion_numerical_value, 0)
+
+            logging.debug("type:{},".format(criterion_name))
+            logging.debug("iteral:{},".format(criterion_literal))
+            logging.debug("values:{}.".format(criterion_numerical_value))
+
+    logging.info("Checking Android Common Header file {}".format(androidaudiocommonbaseheaderFile))
+
+    criteria_pattern = re.compile(
+        r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
+        r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
+        r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])?[0-9a-fA-F]+|[0-9]+)")
+
+    for line_number, line in enumerate(androidaudiocommonbaseheaderFile):
+        match = criteria_pattern.match(line)
+        if match:
+            logging.debug("The following line is VALID: {}:{}\n{}".format(
+                androidaudiocommonbaseheaderFile.name, line_number, line))
+
+            criterion_name = criterion_mapping_table[match.groupdict()['type']]
+            criterion_literal = ''.join(match.groupdict()['literal'])
+            criterion_numerical_value = match.groupdict()['values']
+
+            try:
+                string_int = int(criterion_numerical_value, 0)
+            except ValueError:
+                # Handle the exception
+                logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+                    .format(criterion_numerical_value, criterion_literal, criterion_name))
+                continue
+
+            # Remove duplicated numerical values
+            if int(criterion_numerical_value, 0) in all_criteria[criterion_name].values():
+                logging.info("criterion {} duplicated values:".format(criterion_name))
+                logging.info("{}:{}".format(criterion_numerical_value, criterion_literal))
+                logging.info("KEEPING LATEST")
+                for key in list(all_criteria[criterion_name]):
+                    if all_criteria[criterion_name][key] == int(criterion_numerical_value, 0):
+                        del all_criteria[criterion_name][key]
+
+            all_criteria[criterion_name][criterion_literal] = int(criterion_numerical_value, 0)
+
+            logging.debug("type:{},".format(criterion_name))
+            logging.debug("iteral:{},".format(criterion_literal))
+            logging.debug("values:{}.".format(criterion_numerical_value))
+
+    return all_criteria
+
+
+def main():
+    logging.root.setLevel(logging.INFO)
+    args = parseArgs()
+
+    all_criteria = parseAndroidAudioFile(args.androidaudiobaseheader,
+                                         args.androidaudiocommonbaseheader)
+
+    address_criteria = parseAndroidAudioPolicyConfigurationFile(args.audiopolicyconfigurationfile)
+
+    criterion_types = args.criteriontypes
+
+    generateXmlCriterionTypesFile(all_criteria, address_criteria, criterion_types, args.outputfile)
+
+# If this file is directly executed
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.bp b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
index 78d5fa3..506b19b 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.bp
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
@@ -19,10 +19,12 @@
     ],
     header_libs: [
         "libaudiofoundation_headers",
+        "libaudiopolicycapengine_config_headers",
         "libaudiopolicycommon",
         "libbase_headers",
     ],
     shared_libs: [
+        "libaudiopolicyengine_config",
         "liblog",
         "libmedia_helper",
         "libparameter",
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 099d55d..0bcde8d 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -18,13 +18,13 @@
 //#define LOG_NDEBUG 0
 
 #include "ParameterManagerWrapper.h"
+#include <ParameterMgrFullConnector.h>
 #include <ParameterMgrPlatformConnector.h>
 #include <SelectionCriterionTypeInterface.h>
 #include <SelectionCriterionInterface.h>
 #include <media/convert.h>
 #include <algorithm>
 #include <cutils/bitops.h>
-#include <cutils/config_utils.h>
 #include <cutils/misc.h>
 #include <fstream>
 #include <limits>
@@ -64,31 +64,10 @@
 namespace audio_policy {
 
 const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
-    "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
+    "/etc/parameter-framework/ParameterFrameworkConfigurationCap.xml";
 const char *const ParameterManagerWrapper::mPolicyPfwVendorConfFileName =
     "/vendor/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
 
-static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
-static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
-static const char *const gPhoneStateCriterionName = "TelephonyMode";
-static const char *const gOutputDeviceAddressCriterionName = "AvailableOutputDevicesAddresses";
-static const char *const gInputDeviceAddressCriterionName = "AvailableInputDevicesAddresses";
-
-/**
- * Order MUST be align with defintiion of audio_policy_force_use_t within audio_policy.h
- */
-static const char *const gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
-{
-    [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] =        "ForceUseForCommunication",
-    [AUDIO_POLICY_FORCE_FOR_MEDIA] =                "ForceUseForMedia",
-    [AUDIO_POLICY_FORCE_FOR_RECORD] =               "ForceUseForRecord",
-    [AUDIO_POLICY_FORCE_FOR_DOCK] =                 "ForceUseForDock",
-    [AUDIO_POLICY_FORCE_FOR_SYSTEM] =               "ForceUseForSystem",
-    [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] =    "ForceUseForHdmiSystemAudio",
-    [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] =     "ForceUseForEncodedSurround",
-    [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] =      "ForceUseForVibrateRinging"
-};
-
 template <>
 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
 template <>
@@ -100,9 +79,9 @@
 {
     // Connector
     if (access(mPolicyPfwVendorConfFileName, R_OK) == 0) {
-        mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwVendorConfFileName);
+        mPfwConnector = new CParameterMgrFullConnector(mPolicyPfwVendorConfFileName);
     } else {
-        mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
+        mPfwConnector = new CParameterMgrFullConnector(mPolicyPfwDefaultConfFileName);
     }
 
     // Logger
@@ -130,13 +109,13 @@
               std::get<2>(pair).c_str(), name.c_str());
         criterionType->addValuePair(std::get<0>(pair), std::get<2>(pair), error);
 
-        if (name == gOutputDeviceCriterionName) {
+        if (name == capEngineConfig::gOutputDeviceCriterionName) {
             ALOGV("%s: Adding mOutputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
                   __func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
             audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
             mOutputDeviceToCriterionTypeMap[androidType] = std::get<0>(pair);
         }
-        if (name == gInputDeviceCriterionName) {
+        if (name == capEngineConfig::gInputDeviceCriterionName) {
             ALOGV("%s: Adding mInputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
                   __func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
             audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
@@ -207,10 +186,11 @@
 
 status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
 {
-    ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
+    ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+            capEngineConfig::gPhoneStateCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
+        ALOGE("%s: no criterion found for %s", __FUNCTION__,
+              capEngineConfig::gPhoneStateCriterionName);
         return BAD_VALUE;
     }
     if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
@@ -223,10 +203,11 @@
 
 audio_mode_t ParameterManagerWrapper::getPhoneState() const
 {
-    const ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
+    const ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+            capEngineConfig::gPhoneStateCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
+        ALOGE("%s: no criterion found for %s", __FUNCTION__,
+              capEngineConfig::gPhoneStateCriterionName);
         return AUDIO_MODE_NORMAL;
     }
     return static_cast<audio_mode_t>(criterion->getCriterionState());
@@ -240,10 +221,11 @@
         return BAD_VALUE;
     }
 
-    ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+    ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+            capEngineConfig::gForceUseCriterionTag[usage], mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
+        ALOGE("%s: no criterion found for %s", __FUNCTION__,
+              capEngineConfig::gForceUseCriterionTag[usage]);
         return BAD_VALUE;
     }
     if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
@@ -260,10 +242,11 @@
     if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
         return AUDIO_POLICY_FORCE_NONE;
     }
-    const ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+    const ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+            capEngineConfig::gForceUseCriterionTag[usage], mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
+        ALOGE("%s: no criterion found for %s", __FUNCTION__,
+              capEngineConfig::gForceUseCriterionTag[usage]);
         return AUDIO_POLICY_FORCE_NONE;
     }
     return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
@@ -281,8 +264,8 @@
         audio_devices_t type, const std::string &address, audio_policy_dev_state_t state)
 {
     std::string criterionName = audio_is_output_device(type) ?
-                gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
-
+            capEngineConfig::gOutputDeviceAddressCriterionName :
+            capEngineConfig::gInputDeviceAddressCriterionName;
     ALOGV("%s: device with address %s %s", __FUNCTION__, address.c_str(),
           state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
     ISelectionCriterionInterface *criterion =
@@ -311,12 +294,12 @@
     return NO_ERROR;
 }
 
-status_t ParameterManagerWrapper::setAvailableInputDevices(const DeviceTypeSet &types)
-{
-    ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gInputDeviceCriterionName, mPolicyCriteria);
+status_t ParameterManagerWrapper::setAvailableInputDevices(const DeviceTypeSet &types) {
+    ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+            capEngineConfig::gInputDeviceCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __func__, gInputDeviceCriterionName);
+        ALOGE("%s: no criterion found for %s", __func__,
+              capEngineConfig::gInputDeviceCriterionName);
         return DEAD_OBJECT;
     }
     criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
@@ -324,12 +307,12 @@
     return NO_ERROR;
 }
 
-status_t ParameterManagerWrapper::setAvailableOutputDevices(const DeviceTypeSet &types)
-{
-    ISelectionCriterionInterface *criterion =
-            getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionName, mPolicyCriteria);
+status_t ParameterManagerWrapper::setAvailableOutputDevices(const DeviceTypeSet &types) {
+    ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+            capEngineConfig::gOutputDeviceCriterionName, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for %s", __func__, gOutputDeviceCriterionName);
+        ALOGE("%s: no criterion found for %s", __func__,
+              capEngineConfig::gOutputDeviceCriterionName);
         return DEAD_OBJECT;
     }
     criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
@@ -344,21 +327,15 @@
 
 uint64_t ParameterManagerWrapper::convertDeviceTypeToCriterionValue(audio_devices_t type) const {
     bool isOut = audio_is_output_devices(type);
-    uint32_t typeMask = isOut ? type : (type & ~AUDIO_DEVICE_BIT_IN);
-
     const auto &adapters = isOut ? mOutputDeviceToCriterionTypeMap : mInputDeviceToCriterionTypeMap;
-    // Only multibit devices need adaptation.
-    if (popcount(typeMask) > 1) {
-        const auto &adapter = adapters.find(type);
-        if (adapter != adapters.end()) {
-            ALOGV("%s: multibit device %d converted to criterion %" PRIu64, __func__, type,
-                  adapter->second);
-            return adapter->second;
-        }
-        ALOGE("%s: failed to find map for multibit device %d", __func__, type);
-        return 0;
+    const auto &adapter = adapters.find(type);
+    if (adapter != adapters.end()) {
+        ALOGV("%s: multibit device %d converted to criterion %" PRIu64, __func__, type,
+              adapter->second);
+        return adapter->second;
     }
-    return typeMask;
+    ALOGE("%s: failed to find map for multibit device %d", __func__, type);
+    return 0;
 }
 
 uint64_t ParameterManagerWrapper::convertDeviceTypesToCriterionValue(
@@ -382,5 +359,88 @@
     return deviceTypes;
 }
 
+void ParameterManagerWrapper::createDomain(const std::string &domain)
+{
+    std::string error;
+    bool ret = mPfwConnector->createDomain(domain, error);
+    if (!ret) {
+        ALOGD("%s: failed to create domain %s (error=%s)", __func__, domain.c_str(),
+        error.c_str());
+    }
+}
+
+void ParameterManagerWrapper::addConfigurableElementToDomain(const std::string &domain,
+        const std::string &elementPath)
+{
+    std::string error;
+    bool ret = mPfwConnector->addConfigurableElementToDomain(domain, elementPath, error);
+    ALOGE_IF(!ret, "%s: failed to add parameter %s for domain %s (error=%s)",
+              __func__, elementPath.c_str(), domain.c_str(), error.c_str());
+}
+
+void ParameterManagerWrapper::createConfiguration(const std::string &domain,
+        const std::string &configurationName)
+{
+    std::string error;
+    bool ret = mPfwConnector->createConfiguration(domain, configurationName, error);
+    ALOGE_IF(!ret, "%s: failed to create configuration %s for domain %s (error=%s)",
+              __func__, configurationName.c_str(), domain.c_str(), error.c_str());
+}
+
+void ParameterManagerWrapper::setApplicationRule(
+        const std::string &domain, const std::string &configurationName, const std::string &rule)
+{
+    std::string error;
+    bool ret = mPfwConnector->setApplicationRule(domain, configurationName, rule, error);
+    ALOGE_IF(!ret, "%s: failed to set rule %s for domain %s and configuration %s (error=%s)",
+              __func__, rule.c_str(), domain.c_str(), configurationName.c_str(), error.c_str());
+}
+
+void ParameterManagerWrapper::accessConfigurationValue(const std::string &domain,
+        const std::string &configurationName, const std::string &elementPath,
+        std::string &value)
+{
+    std::string error;
+    bool ret = mPfwConnector->accessConfigurationValue(domain, configurationName, elementPath,
+            value, /*set=*/ true, error);
+    ALOGE_IF(!ret, "%s: failed to set value %s for parameter %s on domain %s and configuration %s "
+          "(error=%s)", __func__, value.c_str(), elementPath.c_str(),  domain.c_str(),
+          configurationName.c_str(), error.c_str());
+}
+
+status_t ParameterManagerWrapper::setConfiguration(
+        const android::capEngineConfig::ParsingResult& capSettings)
+{
+    if (!isStarted()) {
+        return NO_INIT;
+    }
+    std::string error;
+    if (!mPfwConnector->setTuningMode(/* bOn= */ true, error)) {
+        ALOGD("%s: failed to set Tuning Mode error=%s", __FUNCTION__, error.c_str());
+        return DEAD_OBJECT;
+    }
+    for (auto &domain: capSettings.parsedConfig->capConfigurableDomains) {
+        createDomain(domain.name);
+        for (const auto &configurableElementValue : domain.settings[0].configurableElementValues) {
+            addConfigurableElementToDomain(domain.name,
+                    configurableElementValue.configurableElement.path);
+        }
+        for (const auto &configuration : domain.configurations) {
+            createConfiguration(domain.name, configuration.name);
+            setApplicationRule(domain.name, configuration.name, configuration.rule);
+        }
+        for (const auto &setting : domain.settings) {
+            for (const auto &configurableElementValue : setting.configurableElementValues) {
+                std::string value = configurableElementValue.value;
+                accessConfigurationValue(domain.name, setting.configurationName,
+                        configurableElementValue.configurableElement.path, value);
+            }
+
+        }
+    }
+    mPfwConnector->setTuningMode(/* bOn= */ false, error);
+    return OK;
+}
+
 } // namespace audio_policy
 } // namespace android
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index fa4ae1e..0c45a60 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <CapEngineConfig.h>
 #include <media/AudioContainers.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
@@ -27,7 +28,7 @@
 #include <string>
 #include <vector>
 
-class CParameterMgrPlatformConnector;
+class CParameterMgrFullConnector;
 class ISelectionCriterionInterface;
 struct cnode;
 
@@ -59,6 +60,9 @@
      */
     status_t start(std::string &error);
 
+    status_t setConfiguration(const android::capEngineConfig::ParsingResult& capSettings);
+
+
     /**
      * The following API wrap policy action to criteria
      */
@@ -148,6 +152,14 @@
             uint64_t criterionValue, bool isOut) const;
 
 private:
+    void createDomain(const std::string &domain);
+    void addConfigurableElementToDomain(const std::string &domain, const std::string &elementPath);
+    void createConfiguration(const std::string &domain, const std::string &configurationName);
+    void setApplicationRule(const std::string &domain, const std::string &configurationName,
+            const std::string &rule);
+    void accessConfigurationValue(const std::string &domain, const std::string &configurationName,
+                                  const std::string &elementPath, std::string &value);
+
     /**
      * Apply the configuration of the platform on the policy parameter manager.
      * Once all the criteria have been set, the client of the platform state must call
@@ -206,7 +218,7 @@
 
     Criteria mPolicyCriteria; /**< Policy Criterion Map. */
 
-    CParameterMgrPlatformConnector *mPfwConnector; /**< Policy Parameter Manager connector. */
+    CParameterMgrFullConnector *mPfwConnector; /**< Policy Parameter Manager connector. */
     ParameterMgrPlatformConnectorLogger *mPfwConnectorLogger; /**< Policy PFW logger. */
 
 
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index daef691..7de6939 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -51,7 +51,7 @@
         { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
         { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
         { "STRATEGY_REROUTING", STRATEGY_REROUTING },
-        { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
+        { "STRATEGY_PATCH", STRATEGY_PATCH }, // boiler to manage stream patch volume
         { "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
     };
     return legacyStrategy;
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index a6090cf..862b5fd 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -28,20 +28,6 @@
 namespace audio_policy
 {
 
-enum legacy_strategy {
-    STRATEGY_NONE = -1,
-    STRATEGY_MEDIA,
-    STRATEGY_PHONE,
-    STRATEGY_SONIFICATION,
-    STRATEGY_SONIFICATION_RESPECTFUL,
-    STRATEGY_DTMF,
-    STRATEGY_ENFORCED_AUDIBLE,
-    STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
-    STRATEGY_ACCESSIBILITY,
-    STRATEGY_REROUTING,
-    STRATEGY_CALL_ASSISTANT,
-};
-
 class Engine : public EngineBase
 {
 public:
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index fd40c04..a5f37b0 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -266,6 +266,7 @@
     bool isSpatialized;
     bool isBitPerfect;
     float volume;
+    bool muted;
 
     // TODO b/182392769: use attribution source util
     AttributionSourceState attributionSource;
@@ -273,7 +274,7 @@
     attributionSource.token = sp<BBinder>::make();
     if (mManager->getOutputForAttr(&attr, output, AUDIO_SESSION_NONE, &stream, attributionSource,
             &config, &flags, selectedDeviceId, portId, {}, &outputType, &isSpatialized,
-            &isBitPerfect, &volume) != OK) {
+            &isBitPerfect, &volume, &muted) != OK) {
         return false;
     }
     if (*output == AUDIO_IO_HANDLE_NONE || *portId == AUDIO_PORT_HANDLE_NONE) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 718f958..13db5b3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -123,17 +123,16 @@
     }
 }
 
-void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+status_t AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
                                                         media::DeviceConnectedState state)
 {
     audio_port_v7 devicePort;
     device->toAudioPort(&devicePort);
-    if (status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
-            status != OK) {
-        ALOGE("Error %d while setting connected state %d for device %s",
-                status, static_cast<int>(state),
-                device->getDeviceTypeAddr().toString(false).c_str());
-    }
+    status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
+    ALOGE_IF(status != OK, "Error %d while setting connected state %d for device %s", status,
+             static_cast<int>(state), device->getDeviceTypeAddr().toString(false).c_str());
+
+    return status;
 }
 
 status_t AudioPolicyManager::setDeviceConnectionStateInt(
@@ -214,7 +213,14 @@
 
             // Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
             // parameters on newly connected devices (instead of opening the outputs...)
-            broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
+            if (broadcastDeviceConnectionState(
+                        device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
+                mAvailableOutputDevices.remove(device);
+                mHwModules.cleanUpForDevice(device);
+                ALOGE("%s() device %s format %x connection failed", __func__,
+                      device->toString().c_str(), device->getEncodedFormat());
+                return INVALID_OPERATION;
+            }
 
             if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
                 mAvailableOutputDevices.remove(device);
@@ -399,7 +405,14 @@
 
             // Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
             // parameters on newly connected devices (instead of opening the inputs...)
-            broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
+            if (broadcastDeviceConnectionState(
+                        device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
+                mAvailableInputDevices.remove(device);
+                mHwModules.cleanUpForDevice(device);
+                ALOGE("%s() device %s format %x connection failed", __func__,
+                      device->toString().c_str(), device->getEncodedFormat());
+                return INVALID_OPERATION;
+            }
             // Propagate device availability to Engine
             setEngineDeviceConnectionState(device, state);
 
@@ -1194,8 +1207,7 @@
 
     SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
-    if (stream == AUDIO_STREAM_MUSIC &&
-        property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+    if (stream == AUDIO_STREAM_MUSIC && mConfig->useDeepBufferForMedia()) {
         flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
     }
     const audio_io_handle_t output = selectOutput(outputs, flags);
@@ -1408,6 +1420,16 @@
                 (!info->isBitPerfect() || info->getActiveClientCount() == 0)) {
                 info = nullptr;
             }
+
+            if (info != nullptr && info->isBitPerfect() &&
+                (*flags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+                        AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) != 0) {
+                // Reject direct request if a preferred mixer config in use is bit-perfect.
+                ALOGD("%s reject direct request as bit-perfect mixer attributes is active",
+                      __func__);
+                return BAD_VALUE;
+            }
+
             if (com::android::media::audioserver::
                     fix_concurrent_playback_behavior_with_bit_perfect_client()) {
                 if (info != nullptr && info->getUid() == uid &&
@@ -1490,7 +1512,8 @@
                                               output_type_t *outputType,
                                               bool *isSpatialized,
                                               bool *isBitPerfect,
-                                              float *volume)
+                                              float *volume,
+                                              bool *muted)
 {
     // The supplied portId must be AUDIO_PORT_HANDLE_NONE
     if (*portId != AUDIO_PORT_HANDLE_NONE) {
@@ -1547,6 +1570,7 @@
     outputDesc->addClient(clientDesc);
 
     *volume = Volume::DbToAmpl(outputDesc->getCurVolume(toVolumeSource(resultAttr)));
+    *muted = outputDesc->isMutedByGroup(toVolumeSource(resultAttr));
 
     ALOGV("%s() returns output %d requestedPortId %d selectedDeviceId %d for port ID %d", __func__,
           *output, requestedPortId, *selectedDeviceId, *portId);
@@ -1572,6 +1596,13 @@
         return NAME_NOT_FOUND;
     }
 
+    // Reject flag combinations that do not make sense. Note that the requested flags might not
+    // have the 'DIRECT' flag set, however once a direct-capable profile is found, it will
+    // combine the requested flags with its own flags, yielding an unsupported combination.
+    if ((flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+        return NAME_NOT_FOUND;
+    }
+
     // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
     // This prevents creating an offloaded track and tearing it down immediately after start
     // when audioflinger detects there is an active non offloadable effect.
@@ -1648,14 +1679,19 @@
     releaseMsdOutputPatches(devices);
 
     status_t status =
-            outputDesc->open(config, nullptr /* mixerConfig */, devices, stream, flags, output,
+            outputDesc->open(config, nullptr /* mixerConfig */, devices, stream, &flags, output,
                              attributes);
 
-    // only accept an output with the requested parameters
+    // only accept an output with the requested parameters, unless the format can be IEC61937
+    // encapsulated and opened by AudioFlinger as wrapped IEC61937.
+    const bool ignoreRequestedParametersCheck = audio_is_iec61937_compatible(config->format)
+            && (flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+            && audio_has_proportional_frames(outputDesc->getFormat());
     if (status != NO_ERROR ||
-        (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
-        (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
-        (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())) {
+        (!ignoreRequestedParametersCheck &&
+        ((config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+         (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+         (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())))) {
         ALOGV("%s failed opening direct output: output %d sample rate %d %d,"
                 "format %d %d, channel mask %04x %04x", __func__, *output, config->sample_rate,
                 outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
@@ -1675,11 +1711,11 @@
     outputDesc->mDirectClientSession = session;
 
     addOutput(*output, outputDesc);
-    setOutputDevices(__func__, outputDesc,
-                     devices,
-                     true,
-                     0,
-                     NULL);
+    // The version check is essentially to avoid making this call in the case of the HIDL HAL.
+    if (auto hwModule = mHwModules.getModuleFromHandle(mPrimaryModuleHandle); hwModule &&
+            hwModule->getHalVersionMajor() >= 3) {
+        setOutputDevices(__func__, outputDesc, devices, true, 0, NULL);
+    }
     mPreviousOutputs = mOutputs;
     ALOGV("%s returns new direct output %d", __func__, *output);
     mpClientInterface->onAudioPortListUpdate();
@@ -1720,8 +1756,7 @@
     if (stream != AUDIO_STREAM_MUSIC) {
         *flags = (audio_output_flags_t)(*flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
     } else if (/* stream == AUDIO_STREAM_MUSIC && */
-            *flags == AUDIO_OUTPUT_FLAG_NONE &&
-            property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+            *flags == AUDIO_OUTPUT_FLAG_NONE && mConfig->useDeepBufferForMedia()) {
         // use DEEP_BUFFER as default output for music stream type
         *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
     }
@@ -2373,11 +2408,15 @@
                 // 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;
+                std::vector<sp<SwAudioOutputDescriptor>> outputsToResetDevice;
                 for (size_t i = 0; i < mOutputs.size(); i++) {
-                    if (mOutputs[i] == outputDesc ||
-                        mOutputs[i]->devices().filter(outputDesc->devices()).isEmpty()) {
+                    if (mOutputs[i] == outputDesc || (!mOutputs[i]->devices().isEmpty() &&
+                        mOutputs[i]->devices().filter(outputDesc->devices()).isEmpty())) {
                         continue;
                     }
+                    if (mOutputs[i]->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
+                        outputsToResetDevice.push_back(mOutputs[i]);
+                    }
                     for (const auto& c : mOutputs[i]->getClientIterable()) {
                         clientsToInvalidate.push_back(c->portId());
                     }
@@ -2387,6 +2426,9 @@
                           __func__);
                     mpClientInterface->invalidateTracks(clientsToInvalidate);
                 }
+                for (const auto& output : outputsToResetDevice) {
+                    resetOutputDevice(output, 0 /*delayMs*/, nullptr /*patchHandle*/);
+                }
             }
         }
     }
@@ -2577,8 +2619,7 @@
         auto &curves = getVolumeCurves(client->attributes());
         if (NO_ERROR != checkAndSetVolume(curves, client->volumeSource(),
                           curves.getVolumeIndex(outputDesc->devices().types()),
-                          outputDesc,
-                          outputDesc->devices().types(), 0 /*delay*/,
+                          outputDesc, outputDesc->devices().types(), 0 /*delay*/,
                           outputDesc->useHwGain() /*force*/)) {
             // request AudioService to reinitialize the volume curves asynchronously
             ALOGE("checkAndSetVolume failed, requesting volume range init");
@@ -3551,6 +3592,7 @@
 
 status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
                                                   int index,
+                                                  bool muted,
                                                   audio_devices_t device)
 {
     auto attributes = mEngine->getAttributesForStreamType(stream);
@@ -3560,7 +3602,7 @@
     }
     ALOGV("%s: stream %s attributes=%s, index %d , device 0x%X", __func__,
           toString(stream).c_str(), toString(attributes).c_str(), index, device);
-    return setVolumeIndexForAttributes(attributes, index, device);
+    return setVolumeIndexForAttributes(attributes, index, muted, device);
 }
 
 status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream,
@@ -3579,6 +3621,7 @@
 
 status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
                                                          int index,
+                                                         bool muted,
                                                          audio_devices_t device)
 {
     // Get Volume group matching the Audio Attributes
@@ -3589,6 +3632,11 @@
     }
     ALOGV("%s: group %d matching with %s index %d",
             __FUNCTION__, group, toString(attributes).c_str(), index);
+    if (mEngine->getStreamTypeForAttributes(attributes) == AUDIO_STREAM_PATCH) {
+        ALOGV("%s: cannot change volume for PATCH stream, attrs: %s",
+                __FUNCTION__, toString(attributes).c_str());
+        return NO_ERROR;
+    }
     status_t status = NO_ERROR;
     IVolumeCurves &curves = getVolumeCurves(attributes);
     VolumeSource vs = toVolumeSource(group);
@@ -3598,7 +3646,8 @@
             toVolumeSource(AUDIO_STREAM_VOICE_CALL, false) : vs;
     product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes);
 
-    status = setVolumeCurveIndex(index, device, curves);
+
+    status = setVolumeCurveIndex(index, muted, device, curves);
     if (status != NO_ERROR) {
         ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device);
         return status;
@@ -3660,8 +3709,9 @@
         // HW Gain management, do not change the volume
         if (desc->useHwGain()) {
             applyVolume = false;
+            bool swMute = com_android_media_audio_ring_my_car() ? curves.isMuted() : (index == 0);
             // If the volume source is active with higher priority source, ensure at least Sw Muted
-            desc->setSwMute((index == 0), vs, curves.getStreamTypes(), curDevices, 0 /*delayMs*/);
+            desc->setSwMute(swMute, vs, curves.getStreamTypes(), curDevices, 0 /*delayMs*/);
             for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
                 auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
                                                        false /*preferredDevice*/);
@@ -3699,8 +3749,7 @@
         //FIXME: workaround for truncated touch sounds
         // delayed volume change for system stream to be removed when the problem is
         // handled by system UI
-        status_t volStatus = checkAndSetVolume(
-                    curves, vs, index, desc, curDevices,
+        status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevices,
                     ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM, false))?
                          TOUCH_SOUND_FIXED_DELAY_MS : 0));
         if (volStatus != NO_ERROR) {
@@ -3729,6 +3778,7 @@
 }
 
 status_t AudioPolicyManager::setVolumeCurveIndex(int index,
+                                                 bool muted,
                                                  audio_devices_t device,
                                                  IVolumeCurves &volumeCurves)
 {
@@ -3748,8 +3798,9 @@
     // Force max volume if stream cannot be muted
     if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax();
 
-    ALOGV("%s device %08x, index %d", __FUNCTION__ , device, index);
+    ALOGV("%s device %08x, index %d, muted %d", __FUNCTION__ , device, index, muted);
     volumeCurves.addCurrentVolumeIndex(device, index);
+    volumeCurves.setIsMuted(muted);
     return NO_ERROR;
 }
 
@@ -4374,8 +4425,9 @@
             // As done in setDeviceConnectionState, we could also fix default device issue by
             // preventing the force re-routing in case of default dev that distinguishes on address.
             // Let's give back to engine full device choice decision however.
-            bool forceRouting = !newDevices.isEmpty();
-            if (outputDesc->mPreferredAttrInfo != nullptr && newDevices != outputDesc->devices()) {
+            bool newDevicesNotEmpty = !newDevices.isEmpty();
+            if (outputDesc->mPreferredAttrInfo != nullptr && newDevices != outputDesc->devices()
+                && newDevicesNotEmpty) {
                 // If the device is using preferred mixer attributes, the output need to reopen
                 // with default configuration when the new selected devices are different from
                 // current routing devices.
@@ -4383,9 +4435,10 @@
                 continue;
             }
 
-            waitMs = setOutputDevices(__func__, outputDesc, newDevices, forceRouting, delayMs,
-                                       nullptr, !skipDelays /*requiresMuteCheck*/,
-                                      !forceRouting /*requiresVolumeCheck*/, skipDelays);
+            waitMs = setOutputDevices(__func__, outputDesc, newDevices,
+                                      newDevicesNotEmpty /*force*/, delayMs,
+                                      nullptr /*patchHandle*/, !skipDelays /*requiresMuteCheck*/,
+                                      !newDevicesNotEmpty /*requiresVolumeCheck*/, skipDelays);
             // Only apply special touch sound delay once
             delayMs = 0;
         }
@@ -4496,6 +4549,9 @@
             "Engine could not set preferred devices %s for audio source %d role %d",
             dumpAudioDeviceTypeAddrVector(devices).c_str(), audioSource, role);
 
+    if (status == NO_ERROR) {
+        updateInputRouting();
+    }
     return status;
 }
 
@@ -4827,6 +4883,17 @@
     flags = (audio_output_flags_t)((flags & relevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
 
     DeviceVector engineOutputDevices = mEngine->getOutputDevicesForAttributes(*attr);
+    if (std::any_of(engineOutputDevices.begin(), engineOutputDevices.end(),
+            [this, attr](sp<DeviceDescriptor> device) {
+                    return getPreferredMixerAttributesInfo(
+                            device->getId(),
+                            mEngine->getProductStrategyForAttributes(*attr),
+                            true /*activeBitPerfectPreferred*/) != nullptr;
+            })) {
+        // Bit-perfect playback is active on one of the selected devices, direct output will
+        // be rejected at this instant.
+        return AUDIO_DIRECT_NOT_SUPPORTED;
+    }
     for (const auto& hwModule : mHwModules) {
         DeviceVector outputDevices = engineOutputDevices;
         // the MSD module checks for different conditions and output devices
@@ -6106,7 +6173,8 @@
         audio_devices_t deviceType = device->type();
         // Enabling/disabling formats are applied to only HDMI devices. So, this function
         // returns formats reported by HDMI devices.
-        if (deviceType != AUDIO_DEVICE_OUT_HDMI) {
+        if (deviceType != AUDIO_DEVICE_OUT_HDMI &&
+            deviceType != AUDIO_DEVICE_OUT_HDMI_ARC && deviceType != AUDIO_DEVICE_OUT_HDMI_EARC) {
             continue;
         }
         // Formats reported by sink devices
@@ -6175,13 +6243,13 @@
 
     sp<SwAudioOutputDescriptor> outputDesc;
     bool profileUpdated = false;
-    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
-        AUDIO_DEVICE_OUT_HDMI);
+    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypes(
+        {AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_HDMI_EARC});
     for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
         // Simulate reconnection to update enabled surround sound formats.
         String8 address = String8(hdmiOutputDevices[i]->address().c_str());
         std::string name = hdmiOutputDevices[i]->getName();
-        status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+        status_t status = setDeviceConnectionStateInt(hdmiOutputDevices[i]->type(),
                                                       AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                                       address.c_str(),
                                                       name.c_str(),
@@ -6189,7 +6257,7 @@
         if (status != NO_ERROR) {
             continue;
         }
-        status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+        status = setDeviceConnectionStateInt(hdmiOutputDevices[i]->type(),
                                              AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                              address.c_str(),
                                              name.c_str(),
@@ -6727,11 +6795,12 @@
             sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
                                                                                  mpClientInterface);
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+            audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
             audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
             status_t status = outputDesc->open(nullptr /* halConfig */, nullptr /* mixerConfig */,
                                                DeviceVector(supportedDevice),
                                                AUDIO_STREAM_DEFAULT,
-                                               AUDIO_OUTPUT_FLAG_NONE, &output, attributes);
+                                               &flags, &output, attributes);
             if (status != NO_ERROR) {
                 ALOGW("Cannot open output stream for devices %s on hw module %s",
                       supportedDevice->toString().c_str(), hwModule->getName());
@@ -7840,7 +7909,8 @@
         }
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-            setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet());
+            setVolumeSourceMutedInternally(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/,
+                                           DeviceTypeSet());
             const uint32_t latency = desc->latency() * 2;
             if (desc->isActive(latency * 2) && latency > maxLatency) {
                 maxLatency = latency;
@@ -7934,9 +8004,10 @@
         for (const auto &activeVs : outputDesc->getActiveVolumeSources()) {
             // make sure that we do not start the temporary mute period too early in case of
             // delayed device change
-            setVolumeSourceMute(activeVs, true, outputDesc, delayMs);
-            setVolumeSourceMute(activeVs, false, outputDesc, delayMs + tempMuteDurationMs,
-                                devices.types());
+            setVolumeSourceMutedInternally(activeVs, true, outputDesc, delayMs);
+            setVolumeSourceMutedInternally(activeVs, false, outputDesc,
+                                           delayMs + tempMuteDurationMs,
+                                           devices.types());
         }
     }
 
@@ -8101,9 +8172,21 @@
                         if (result.source == AUDIO_SOURCE_HOTWORD && !inputDesc->isSoundTrigger()) {
                             result.source = AUDIO_SOURCE_VOICE_RECOGNITION;
                         }
-                        return result; }).
+                        return result; });
             //only one input device for now
-                    addSource(device);
+            if (audio_is_remote_submix_device(device->type())) {
+                // remote submix HAL does not support audio conversion, need source device
+                // audio config to match the sink input descriptor audio config, otherwise AIDL
+                // HAL patching will fail
+                audio_port_config srcDevicePortConfig = {};
+                device->toAudioPortConfig(&srcDevicePortConfig, nullptr);
+                srcDevicePortConfig.sample_rate = inputDesc->getSamplingRate();
+                srcDevicePortConfig.channel_mask = inputDesc->getChannelMask();
+                srcDevicePortConfig.format = inputDesc->getFormat();
+                patchBuilder.addSource(srcDevicePortConfig);
+            } else {
+                patchBuilder.addSource(device);
+            }
             status = installPatch(__func__, patchHandle, inputDesc.get(), patchBuilder.patch(), 0);
         }
     }
@@ -8151,6 +8234,9 @@
 
     for (;;) {
         sp<IOProfile> firstInexact = nullptr;
+        uint32_t inexactSamplingRate = 0;
+        audio_format_t inexactFormat = AUDIO_FORMAT_INVALID;
+        audio_channel_mask_t inexactChannelMask = AUDIO_CHANNEL_INVALID;
         uint32_t updatedSamplingRate = 0;
         audio_format_t updatedFormat = AUDIO_FORMAT_INVALID;
         audio_channel_mask_t updatedChannelMask = AUDIO_CHANNEL_INVALID;
@@ -8188,14 +8274,17 @@
                                 false /*exactMatchRequiredForInputFlags*/)
                                 != IOProfile::NO_MATCH) {
                     firstInexact = profile;
+                    inexactSamplingRate = updatedSamplingRate;
+                    inexactFormat = updatedFormat;
+                    inexactChannelMask = updatedChannelMask;
                 }
             }
         }
 
         if (firstInexact != nullptr) {
-            samplingRate = updatedSamplingRate;
-            format = updatedFormat;
-            channelMask = updatedChannelMask;
+            samplingRate = inexactSamplingRate;
+            format = inexactFormat;
+            channelMask = inexactChannelMask;
             return firstInexact;
         } else if (flags & AUDIO_INPUT_FLAG_RAW) {
             flags = (audio_input_flags_t) (flags & ~AUDIO_INPUT_FLAG_RAW); // retry
@@ -8427,8 +8516,11 @@
                                                int delayMs,
                                                bool force)
 {
+    // APM is single threaded, and single instance.
+    static std::set<IVolumeCurves*> invalidCurvesReported;
+
     // do not change actual attributes volume if the attributes is muted
-    if (outputDesc->isMuted(volumeSource)) {
+    if (!com_android_media_audio_ring_my_car() && outputDesc->isMutedInternally(volumeSource)) {
         ALOGVV("%s: volume source %d muted count %d active=%d", __func__, volumeSource,
                outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
         return NO_ERROR;
@@ -8451,19 +8543,32 @@
     }
 
     if (curves.getVolumeIndexMin() < 0 || curves.getVolumeIndexMax() < 0) {
-        ALOGE("invalid volume index range");
+        if (!invalidCurvesReported.count(&curves)) {
+            invalidCurvesReported.insert(&curves);
+            String8 dump;
+            curves.dump(&dump);
+            ALOGE("invalid volume index range in the curve:\n%s", dump.c_str());
+        }
         return BAD_VALUE;
     }
 
     float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
+    const VolumeSource dtmfVolSrc = toVolumeSource(AUDIO_STREAM_DTMF, false);
     if (outputDesc->isFixedVolume(deviceTypes) ||
             // Force VoIP volume to max for bluetooth SCO/BLE device except if muted
-            (index != 0 && (isVoiceVolSrc || isBtScoVolSrc) &&
+            (index != 0 && (isVoiceVolSrc || isBtScoVolSrc
+                        || (isInCall() && (dtmfVolSrc == volumeSource))) &&
                     (isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device)
                     || isSingleDeviceType(deviceTypes, audio_is_ble_out_device)))) {
         volumeDb = 0.0f;
     }
-    const bool muted = (index == 0) && (volumeDb != 0.0f);
+
+    bool muted;
+    if (!com_android_media_audio_ring_my_car()) {
+        muted = (index == 0) && (volumeDb != 0.0f);
+    } else {
+        muted = curves.isMuted();
+    }
     outputDesc->setVolume(volumeDb, muted, volumeSource, curves.getStreamTypes(),
             deviceTypes, delayMs, force, isVoiceVolSrc);
 
@@ -8478,6 +8583,11 @@
 void AudioPolicyManager::setVoiceVolume(
         int index, IVolumeCurves &curves, bool voiceVolumeManagedByHost, int delayMs) {
     float voiceVolume;
+
+    if (com_android_media_audio_ring_my_car() && curves.isMuted()) {
+        index = 0;
+    }
+
     // Force voice volume to max or mute for Bluetooth SCO/BLE as other attenuations are managed
     // by the headset
     if (voiceVolumeManagedByHost) {
@@ -8531,8 +8641,7 @@
     ALOGVV("applyStreamVolumes() for device %s", dumpDeviceTypes(deviceTypes).c_str());
     for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
         auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
-        checkAndSetVolume(curves, toVolumeSource(volumeGroup),
-                          curves.getVolumeIndex(deviceTypes),
+        checkAndSetVolume(curves, toVolumeSource(volumeGroup), curves.getVolumeIndex(deviceTypes),
                           outputDesc, deviceTypes, delayMs, force);
     }
 }
@@ -8555,23 +8664,23 @@
         }
     }
     for (auto source : sourcesToMute) {
-        setVolumeSourceMute(source, on, outputDesc, delayMs, deviceTypes);
+        setVolumeSourceMutedInternally(source, on, outputDesc, delayMs, deviceTypes);
     }
 
 }
 
-void AudioPolicyManager::setVolumeSourceMute(VolumeSource volumeSource,
-                                             bool on,
-                                             const sp<AudioOutputDescriptor>& outputDesc,
-                                             int delayMs,
-                                             DeviceTypeSet deviceTypes)
+void AudioPolicyManager::setVolumeSourceMutedInternally(VolumeSource volumeSource,
+                                                        bool on,
+                                                        const sp<AudioOutputDescriptor>& outputDesc,
+                                                        int delayMs,
+                                                        DeviceTypeSet deviceTypes)
 {
     if (deviceTypes.empty()) {
         deviceTypes = outputDesc->devices().types();
     }
     auto &curves = getVolumeCurves(volumeSource);
     if (on) {
-        if (!outputDesc->isMuted(volumeSource)) {
+        if (!outputDesc->isMutedInternally(volumeSource)) {
             if (curves.canBeMuted() &&
                     (volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE, false) ||
                      (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
@@ -8583,7 +8692,7 @@
         // ignored
         outputDesc->incMuteCount(volumeSource);
     } else {
-        if (!outputDesc->isMuted(volumeSource)) {
+        if (!outputDesc->isMutedInternally(volumeSource)) {
             ALOGV("%s unmuting non muted attributes!", __func__);
             return;
         }
@@ -8820,6 +8929,8 @@
     mReportedFormatsMap[devDesc] = formats;
 
     if (devDesc->type() == AUDIO_DEVICE_OUT_HDMI ||
+        devDesc->type() == AUDIO_DEVICE_OUT_HDMI_ARC ||
+        devDesc->type() == AUDIO_DEVICE_OUT_HDMI_EARC ||
         isDeviceOfModule(devDesc,AUDIO_HARDWARE_MODULE_ID_MSD)) {
         modifySurroundFormats(devDesc, &formats);
         size_t modifiedNumProfiles = 0;
@@ -8954,7 +9065,7 @@
     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
     audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
     status_t status = desc->open(halConfig, mixerConfig, devices,
-            AUDIO_STREAM_DEFAULT, flags, &output, attributes);
+            AUDIO_STREAM_DEFAULT, &flags, &output, attributes);
     if (status != NO_ERROR) {
         ALOGE("%s failed to open output %d", __func__, status);
         return nullptr;
@@ -8992,7 +9103,7 @@
         config.offload_info.channel_mask = config.channel_mask;
         config.offload_info.format = config.format;
 
-        status = desc->open(&config, mixerConfig, devices, AUDIO_STREAM_DEFAULT, flags, &output,
+        status = desc->open(&config, mixerConfig, devices, AUDIO_STREAM_DEFAULT, &flags, &output,
                             attributes);
         if (status != NO_ERROR) {
             return nullptr;
@@ -9000,11 +9111,11 @@
     }
 
     addOutput(output, desc);
-    setOutputDevices(__func__, desc,
-                     devices,
-                     true,
-                     0,
-                     NULL);
+    // The version check is essentially to avoid making this call in the case of the HIDL HAL.
+    if (auto hwModule = mHwModules.getModuleFromHandle(mPrimaryModuleHandle); hwModule &&
+            hwModule->getHalVersionMajor() >= 3) {
+        setOutputDevices(__func__, desc, devices, true, 0, NULL);
+    }
     sp<DeviceDescriptor> speaker = mAvailableOutputDevices.getDevice(
             AUDIO_DEVICE_OUT_SPEAKER, String8(""), AUDIO_FORMAT_DEFAULT);
 
@@ -9055,6 +9166,13 @@
 
 status_t AudioPolicyManager::getDevicesForAttributes(
         const audio_attributes_t &attr, DeviceVector &devices, bool forVolume) {
+    // attr containing source set by AudioAttributes.Builder.setCapturePreset() has precedence
+    // over any usage or content type also present in attr.
+    if (com::android::media::audioserver::enable_audio_input_device_routing() &&
+        attr.source != AUDIO_SOURCE_INVALID) {
+        return getInputDevicesForAttributes(attr, devices);
+    }
+
     // Devices are determined in the following precedence:
     //
     // 1) Devices associated with a dynamic policy matching the attributes.  This is often
@@ -9118,6 +9236,15 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyManager::getInputDevicesForAttributes(
+        const audio_attributes_t &attr, DeviceVector &devices) {
+    devices = DeviceVector(
+            mEngine->getInputDeviceForAttributes(attr, 0 /*uid unknown here*/,
+                                                 AUDIO_SESSION_NONE,
+                                                 nullptr /* mix */));
+    return NO_ERROR;
+}
+
 status_t AudioPolicyManager::getProfilesForDevices(const DeviceVector& devices,
                                                    AudioProfileVector& audioProfiles,
                                                    uint32_t flags,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 4736980..20f7b12 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -129,7 +129,8 @@
                                   output_type_t *outputType,
                                   bool *isSpatialized,
                                   bool *isBitPerfect,
-                                  float *volume) override;
+                                  float *volume,
+                                  bool *muted) override;
         virtual status_t startOutput(audio_port_handle_t portId);
         virtual status_t stopOutput(audio_port_handle_t portId);
         virtual bool releaseOutput(audio_port_handle_t portId);
@@ -169,6 +170,7 @@
         virtual void initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
         virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
                                               int index,
+                                              bool muted,
                                               audio_devices_t device);
         virtual status_t getStreamVolumeIndex(audio_stream_type_t stream,
                                               int *index,
@@ -176,6 +178,7 @@
 
         virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
                                                      int index,
+                                                     bool muted,
                                                      audio_devices_t device);
         virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
                                                      int &index,
@@ -185,6 +188,7 @@
         virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
 
         status_t setVolumeCurveIndex(int index,
+                                     bool muted,
                                      audio_devices_t device,
                                      IVolumeCurves &volumeCurves);
 
@@ -650,7 +654,8 @@
                              DeviceTypeSet deviceTypes = DeviceTypeSet());
 
         /**
-         * @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
+         * @brief setVolumeSourceMutedInternally Mute or unmute the volume source on the specified
+         * output
          * @param volumeSource to be muted/unmute (may host legacy streams or by extension set of
          * audio attributes)
          * @param on true to mute, false to umute
@@ -658,11 +663,11 @@
          * @param delayMs
          * @param device
          */
-        void setVolumeSourceMute(VolumeSource volumeSource,
-                                 bool on,
-                                 const sp<AudioOutputDescriptor>& outputDesc,
-                                 int delayMs = 0,
-                                 DeviceTypeSet deviceTypes = DeviceTypeSet());
+        void setVolumeSourceMutedInternally(VolumeSource volumeSource,
+                                            bool on,
+                                            const sp<AudioOutputDescriptor>& outputDesc,
+                                            int delayMs = 0,
+                                            DeviceTypeSet deviceTypes = DeviceTypeSet());
 
         audio_mode_t getPhoneState();
 
@@ -1109,8 +1114,8 @@
         // It can give a chance to HAL implementer to retrieve dynamic capabilities associated
         // to this device for example.
         // TODO avoid opening stream to retrieve capabilities of a profile.
-        void broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
-                                            media::DeviceConnectedState state);
+        status_t broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+                                                media::DeviceConnectedState state);
 
         // updates device caching and output for streams that can influence the
         //    routing of notifications
@@ -1366,6 +1371,11 @@
                                          DeviceVector &devices,
                                          bool forVolume);
 
+        // A helper method used by getDevicesForAttributes to retrieve input devices when
+        // capture preset is available in the given audio attributes parameter.
+        status_t getInputDevicesForAttributes(const audio_attributes_t &attr,
+                                              DeviceVector &devices);
+
         status_t getProfilesForDevices(const DeviceVector& devices,
                                        AudioProfileVector& audioProfiles,
                                        uint32_t flags,
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 9a5365c..3ed247b 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -56,7 +56,7 @@
                                                            audio_config_base_t *mixerConfig,
                                                            const sp<DeviceDescriptorBase>& device,
                                                            uint32_t *latencyMs,
-                                                           audio_output_flags_t flags,
+                                                           audio_output_flags_t *flags,
                                                            audio_attributes_t attributes)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
@@ -74,7 +74,7 @@
     request.mixerConfig = VALUE_OR_RETURN_STATUS(
             legacy2aidl_audio_config_base_t_AudioConfigBase(*mixerConfig, false /*isInput*/));
     request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_DeviceDescriptorBase(device));
-    request.flags = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
+    request.flags = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_output_flags_t_int32_t_mask(*flags));
     request.attributes = VALUE_OR_RETURN_STATUS(
             legacy2aidl_audio_attributes_t_AudioAttributes(attributes));
 
@@ -89,7 +89,9 @@
             .channel_mask = halConfig->channel_mask,
             .format = halConfig->format,
         };
-        mAudioPolicyService->registerOutput(*output, config, flags);
+        *flags = VALUE_OR_RETURN_STATUS(
+                aidl2legacy_int32_t_audio_output_flags_t_mask(response.flags));
+        mAudioPolicyService->registerOutput(*output, config, *flags);
     }
     return status;
 }
@@ -184,21 +186,19 @@
 }
 
 status_t AudioPolicyService::AudioPolicyClient::setStreamVolume(audio_stream_type_t stream,
-                     float volume, audio_io_handle_t output,
-                     int delay_ms)
+                     float volume, bool muted, audio_io_handle_t output, int delay_ms)
 {
-    return mAudioPolicyService->setStreamVolume(stream, volume, output,
-                                               delay_ms);
+    return mAudioPolicyService->setStreamVolume(stream, volume, muted, output, delay_ms);
 }
 
 status_t AudioPolicyService::AudioPolicyClient::setPortsVolume(
-        const std::vector<audio_port_handle_t> &ports, float volume, audio_io_handle_t output,
-        int delayMs)
+        const std::vector<audio_port_handle_t> &ports, float volume, bool muted,
+        audio_io_handle_t output, int delayMs)
 {
     if (ports.empty()) {
         return NO_ERROR;
     }
-    return mAudioPolicyService->setPortsVolume(ports, volume, output, delayMs);
+    return mAudioPolicyService->setPortsVolume(ports, volume, muted, output, delayMs);
 }
 
 void AudioPolicyService::AudioPolicyClient::setParameters(audio_io_handle_t io_handle,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index bb41d00..8fbe1cc 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -79,6 +79,8 @@
 using media::audio::common::AudioFormatDescription;
 using media::audio::common::AudioMode;
 using media::audio::common::AudioOffloadInfo;
+using media::audio::common::AudioPolicyForceUse;
+using media::audio::common::AudioPolicyForcedConfig;
 using media::audio::common::AudioSource;
 using media::audio::common::AudioStreamType;
 using media::audio::common::AudioUsage;
@@ -86,6 +88,10 @@
 using media::audio::common::Int;
 
 constexpr int kDefaultVirtualDeviceId = 0;
+namespace {
+constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED;
+constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED;
+}
 
 const std::vector<audio_usage_t>& SYSTEM_USAGES = {
     AUDIO_USAGE_CALL_ASSISTANT,
@@ -284,8 +290,8 @@
     return Status::ok();
 }
 
-Status AudioPolicyService::setForceUse(media::AudioPolicyForceUse usageAidl,
-                                       media::AudioPolicyForcedConfig configAidl)
+Status AudioPolicyService::setForceUse(AudioPolicyForceUse usageAidl,
+                                       AudioPolicyForcedConfig configAidl)
 {
     audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
@@ -316,8 +322,8 @@
     return Status::ok();
 }
 
-Status AudioPolicyService::getForceUse(media::AudioPolicyForceUse usageAidl,
-                                       media::AudioPolicyForcedConfig* _aidl_return) {
+Status AudioPolicyService::getForceUse(AudioPolicyForceUse usageAidl,
+                                       AudioPolicyForcedConfig* _aidl_return) {
     audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
 
@@ -424,6 +430,7 @@
     bool isSpatialized = false;
     bool isBitPerfect = false;
     float volume;
+    bool muted;
     status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
                                                             &stream,
                                                             attributionSource,
@@ -433,7 +440,8 @@
                                                             &outputType,
                                                             &isSpatialized,
                                                             &isBitPerfect,
-                                                            &volume);
+                                                            &volume,
+                                                            &muted);
 
     // FIXME: Introduce a way to check for the the telephony device before opening the output
     if (result == NO_ERROR) {
@@ -498,6 +506,7 @@
         _aidl_return->attr = VALUE_OR_RETURN_BINDER_STATUS(
                 legacy2aidl_audio_attributes_t_AudioAttributes(attr));
         _aidl_return->volume = volume;
+        _aidl_return->muted = muted;
     } else {
         _aidl_return->configBase.format = VALUE_OR_RETURN_BINDER_STATUS(
                 legacy2aidl_audio_format_t_AudioFormatDescription(config.format));
@@ -900,13 +909,13 @@
 
     std::stringstream msg;
     msg << "Audio recording on session " << client->session;
+    const auto permitted = startRecording(client->attributionSource, client->virtualDeviceId,
+            String16(msg.str().c_str()), client->attributes.source);
 
     // check calling permissions
-    if (!(startRecording(client->attributionSource, client->virtualDeviceId,
-                         String16(msg.str().c_str()), client->attributes.source)
-            || client->attributes.source == AUDIO_SOURCE_FM_TUNER
-            || client->attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX
-            || client->attributes.source == AUDIO_SOURCE_ECHO_REFERENCE)) {
+    if (permitted == PERMISSION_HARD_DENIED && client->attributes.source != AUDIO_SOURCE_FM_TUNER
+            && client->attributes.source != AUDIO_SOURCE_REMOTE_SUBMIX
+            && client->attributes.source != AUDIO_SOURCE_ECHO_REFERENCE) {
         ALOGE("%s permission denied: recording not allowed for attribution source %s",
                 __func__, client->attributionSource.toString().c_str());
         return binderStatusFromStatusT(PERMISSION_DENIED);
@@ -926,13 +935,17 @@
         return binderStatusFromStatusT(INVALID_OPERATION);
     }
 
-    // Force the possibly silenced client to be unsilenced since we just called
-    // startRecording (i.e. we have assumed it is unsilenced).
-    // At this point in time, the client is inactive, so no calls to appops are sent in
-    // setAppState_l.
-    // This ensures existing clients have the same behavior as new clients (starting unsilenced).
+    // Force the possibly silenced client to match the state on the appops side
+    // following the call to startRecording (i.e. unsilenced iff call succeeded)
+    // At this point in time, the client is inactive, so no calls to appops are
+    // sent in setAppState_l. This ensures existing clients have the same
+    // behavior as new clients.
     // TODO(b/282076713)
-    setAppState_l(client, APP_STATE_TOP);
+    if (permitted == PERMISSION_GRANTED) {
+        setAppState_l(client, APP_STATE_TOP);
+    } else {
+        setAppState_l(client, APP_STATE_IDLE);
+    }
 
     client->active = true;
     client->startTimeNs = systemTime();
@@ -1018,8 +1031,10 @@
         client->active = false;
         client->startTimeNs = 0;
         updateUidStates_l();
-        finishRecording(client->attributionSource, client->virtualDeviceId,
-                        client->attributes.source);
+        if (!client->silenced) {
+            finishRecording(client->attributionSource, client->virtualDeviceId,
+                    client->attributes.source);
+        }
     }
 
     return binderStatusFromStatusT(status);
@@ -1048,7 +1063,11 @@
     updateUidStates_l();
 
     // finish the recording app op
-    finishRecording(client->attributionSource, client->virtualDeviceId, client->attributes.source);
+    if (!client->silenced) {
+        finishRecording(client->attributionSource, client->virtualDeviceId,
+                client->attributes.source);
+    }
+
     AutoCallerClear acc;
     return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId));
 }
@@ -1154,7 +1173,7 @@
 
 Status AudioPolicyService::setStreamVolumeIndex(AudioStreamType streamAidl,
                                                 const AudioDeviceDescription& deviceAidl,
-                                                int32_t indexAidl) {
+                                                int32_t indexAidl, bool muted) {
     audio_stream_type_t stream = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioStreamType_audio_stream_type_t(streamAidl));
     int index = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int>(indexAidl));
@@ -1176,6 +1195,7 @@
     AutoCallerClear acc;
     return binderStatusFromStatusT(mAudioPolicyManager->setStreamVolumeIndex(stream,
                                                                              index,
+                                                                             muted,
                                                                              device));
 }
 
@@ -1204,7 +1224,7 @@
 
 Status AudioPolicyService::setVolumeIndexForAttributes(
         const media::audio::common::AudioAttributes& attrAidl,
-        const AudioDeviceDescription& deviceAidl, int32_t indexAidl) {
+        const AudioDeviceDescription& deviceAidl, int32_t indexAidl, bool muted) {
     audio_attributes_t attributes = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioAttributes_audio_attributes_t(attrAidl));
     int index = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int>(indexAidl));
@@ -1224,7 +1244,7 @@
     audio_utils::lock_guard _l(mMutex);
     AutoCallerClear acc;
     return binderStatusFromStatusT(
-            mAudioPolicyManager->setVolumeIndexForAttributes(attributes, index, device));
+            mAudioPolicyManager->setVolumeIndexForAttributes(attributes, index, muted, device));
 }
 
 Status AudioPolicyService::getVolumeIndexForAttributes(
@@ -1671,6 +1691,19 @@
     return Status::ok();
 }
 
+template <typename Port>
+void anonymizePortBluetoothAddress(Port& port) {
+    if (port.type != AUDIO_PORT_TYPE_DEVICE) {
+        return;
+    }
+    if (!(audio_is_a2dp_device(port.ext.device.type)
+            || audio_is_ble_device(port.ext.device.type)
+            || audio_is_bluetooth_sco_device(port.ext.device.type)
+            || audio_is_hearing_aid_out_device(port.ext.device.type))) {
+        return;
+    }
+    anonymizeBluetoothAddress(port.ext.device.address);
+}
 
 Status AudioPolicyService::listAudioPorts(media::AudioPortRole roleAidl,
                                           media::AudioPortType typeAidl, Int* count,
@@ -1689,14 +1722,27 @@
     std::unique_ptr<audio_port_v7[]> ports(new audio_port_v7[num_ports]);
     unsigned int generation;
 
-    audio_utils::lock_guard _l(mMutex);
-    if (mAudioPolicyManager == NULL) {
-        return binderStatusFromStatusT(NO_INIT);
-    }
+    const AttributionSourceState attributionSource = getCallingAttributionSource();
     AutoCallerClear acc;
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
-            mAudioPolicyManager->listAudioPorts(role, type, &num_ports, ports.get(), &generation)));
-    numPortsReq = std::min(numPortsReq, num_ports);
+    {
+        audio_utils::lock_guard _l(mMutex);
+        if (mAudioPolicyManager == NULL) {
+            return binderStatusFromStatusT(NO_INIT);
+        }
+        // AudioPolicyManager->listAudioPorts makes a deep copy of port structs into ports
+        // so it is safe to access after releasing the mutex
+        RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+                mAudioPolicyManager->listAudioPorts(
+                        role, type, &num_ports, ports.get(), &generation)));
+        numPortsReq = std::min(numPortsReq, num_ports);
+    }
+
+    if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
+        for (size_t i = 0; i < numPortsReq; ++i) {
+            anonymizePortBluetoothAddress(ports[i]);
+        }
+    }
+
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
             convertRange(ports.get(), ports.get() + numPortsReq, std::back_inserter(*portsAidl),
                          legacy2aidl_audio_port_v7_AudioPortFw)));
@@ -1719,12 +1765,24 @@
 Status AudioPolicyService::getAudioPort(int portId,
                                         media::AudioPortFw* _aidl_return) {
     audio_port_v7 port{ .id = portId };
-    audio_utils::lock_guard _l(mMutex);
-    if (mAudioPolicyManager == NULL) {
-        return binderStatusFromStatusT(NO_INIT);
-    }
+
+    const AttributionSourceState attributionSource = getCallingAttributionSource();
     AutoCallerClear acc;
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
+
+    {
+        audio_utils::lock_guard _l(mMutex);
+        if (mAudioPolicyManager == NULL) {
+            return binderStatusFromStatusT(NO_INIT);
+        }
+        // AudioPolicyManager->getAudioPort makes a deep copy of the port struct into port
+        // so it is safe to access after releasing the mutex
+        RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
+    }
+
+    if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
+        anonymizePortBluetoothAddress(port);
+    }
+
     *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_port_v7_AudioPortFw(port));
     return Status::ok();
 }
@@ -1786,14 +1844,32 @@
     std::unique_ptr<audio_patch[]> patches(new audio_patch[num_patches]);
     unsigned int generation;
 
-    audio_utils::lock_guard _l(mMutex);
-    if (mAudioPolicyManager == NULL) {
-        return binderStatusFromStatusT(NO_INIT);
-    }
+    const AttributionSourceState attributionSource = getCallingAttributionSource();
     AutoCallerClear acc;
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
-            mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
-    numPatchesReq = std::min(numPatchesReq, num_patches);
+
+    {
+        audio_utils::lock_guard _l(mMutex);
+        if (mAudioPolicyManager == NULL) {
+            return binderStatusFromStatusT(NO_INIT);
+        }
+        // AudioPolicyManager->listAudioPatches makes a deep copy of patches structs into patches
+        // so it is safe to access after releasing the mutex
+        RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+                mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
+        numPatchesReq = std::min(numPatchesReq, num_patches);
+    }
+
+    if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
+        for (size_t i = 0; i < numPatchesReq; ++i) {
+            for (size_t j = 0; j < patches[i].num_sources; ++j) {
+                anonymizePortBluetoothAddress(patches[i].sources[j]);
+            }
+            for (size_t j = 0; j < patches[i].num_sinks; ++j) {
+                anonymizePortBluetoothAddress(patches[i].sinks[j]);
+            }
+        }
+    }
+
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
             convertRange(patches.get(), patches.get() + numPatchesReq,
                          std::back_inserter(*patchesAidl), legacy2aidl_audio_patch_AudioPatchFw)));
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 29a3f8a..290a036 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -61,6 +61,10 @@
 
 static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY");
 
+namespace {
+constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED;
+}
+
 // Creates an association between Binder code to name for IAudioPolicyService.
 #define IAUDIOPOLICYSERVICE_BINDER_METHOD_MACRO_LIST \
 BINDER_METHOD_ENTRY(onNewAudioModulesAvailable) \
@@ -193,9 +197,7 @@
     media::AudioPolicyConfig apmConfig;
     if (status_t status = clientInterface->getAudioPolicyConfig(&apmConfig); status == OK) {
         auto config = AudioPolicyConfig::loadFromApmAidlConfigWithFallback(apmConfig);
-        LOG_ALWAYS_FATAL_IF(config->getEngineLibraryNameSuffix() !=
-                AudioPolicyConfig::kDefaultEngineLibraryNameSuffix,
-                "Only default engine is currently supported with the AIDL HAL");
+        ALOGD("%s loading APM engine %s", __func__, config->getEngineLibraryNameSuffix().c_str());
         apm = new AudioPolicyManager(config,
                 loadApmEngineLibraryAndCreateEngine(
                         config->getEngineLibraryNameSuffix(), apmConfig.engineConfig),
@@ -1221,9 +1223,10 @@
                 } else {
                     std::stringstream msg;
                     msg << "Audio recording un-silenced on session " << client->session;
-                    if (!startRecording(client->attributionSource, client->virtualDeviceId,
-                                        String16(msg.str().c_str()), client->attributes.source)) {
-                        silenced = true;
+                    if (startRecording(client->attributionSource, client->virtualDeviceId,
+                                String16(msg.str().c_str()), client->attributes.source)
+                                != PERMISSION_GRANTED) {
+                        return;
                     }
                 }
             }
@@ -1807,6 +1810,7 @@
                   ++numTimesBecameEmpty;
                 }
                 mLastCommand = command;
+                status_t createAudioPatchStatus;
 
                 switch (command->mCommand) {
                 case SET_VOLUME: {
@@ -1816,6 +1820,7 @@
                     ul.unlock();
                     command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                                                                     data->mVolume,
+                                                                    data->mIsMuted,
                                                                     data->mIO);
                     ul.lock();
                     }break;
@@ -1826,6 +1831,7 @@
                     ul.unlock();
                     command->mStatus = AudioSystem::setPortsVolume(data->mPorts,
                                                                    data->mVolume,
+                                                                   data->mMuted,
                                                                    data->mIO);
                     ul.lock();
                     } break;
@@ -1874,10 +1880,11 @@
                     ALOGV("AudioCommandThread() processing create audio patch");
                     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
                     if (af == 0) {
-                        command->mStatus = PERMISSION_DENIED;
+                        createAudioPatchStatus = PERMISSION_DENIED;
                     } else {
                         ul.unlock();
-                        command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+                        createAudioPatchStatus = af->createAudioPatch(&data->mPatch,
+                                                                      &data->mHandle);
                         ul.lock();
                     }
                     } break;
@@ -2046,8 +2053,28 @@
                 {
                     audio_utils::lock_guard _l(command->mMutex);
                     if (command->mWaitStatus) {
+                        if (command->mCommand == CREATE_AUDIO_PATCH) {
+                            command->mStatus = createAudioPatchStatus;
+                        }
                         command->mWaitStatus = false;
                         command->mCond.notify_one();
+                    } else if (command->mCommand == CREATE_AUDIO_PATCH &&
+                               command->mStatus == TIMED_OUT &&
+                               createAudioPatchStatus == NO_ERROR) {
+                        // Because of special handling in insertCommand_l() the CREATE_AUDIO_PATCH
+                        // command wait status can be only false in case timeout (see TIMED_OUT)
+                        // happened.
+                        CreateAudioPatchData *createData =
+                                (CreateAudioPatchData *)command->mParam.get();
+                        ALOGW("AudioCommandThread() no caller awaiting for handle(%d) after \
+                                processing create audio patch, going to release it",
+                                createData->mHandle);
+                        sp<AudioCommand> releaseCommand = new AudioCommand();
+                        releaseCommand->mCommand = RELEASE_AUDIO_PATCH;
+                        ReleaseAudioPatchData *releaseData = new ReleaseAudioPatchData();
+                        releaseData->mHandle = createData->mHandle;
+                        releaseCommand->mParam = releaseData;
+                        insertCommand_l(releaseCommand, 0);
                     }
                 }
                 waitTime = -1;
@@ -2125,6 +2152,7 @@
 
 status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
                                                                float volume,
+                                                               bool muted,
                                                                audio_io_handle_t output,
                                                                int delayMs)
 {
@@ -2133,6 +2161,7 @@
     sp<VolumeData> data = new VolumeData();
     data->mStream = stream;
     data->mVolume = volume;
+    data->mIsMuted = muted;
     data->mIO = output;
     command->mParam = data;
     command->mWaitStatus = true;
@@ -2142,14 +2171,15 @@
 }
 
 status_t AudioPolicyService::AudioCommandThread::volumePortsCommand(
-        const std::vector<audio_port_handle_t> &ports, float volume, audio_io_handle_t output,
-        int delayMs)
+        const std::vector<audio_port_handle_t> &ports, float volume, bool muted,
+        audio_io_handle_t output, int delayMs)
 {
     sp<AudioCommand> command = new AudioCommand();
     command->mCommand = SET_PORTS_VOLUME;
     sp<VolumePortsData> data = new VolumePortsData();
     data->mPorts = ports;
     data->mVolume = volume;
+    data->mMuted = muted;
     data->mIO = output;
     command->mParam = data;
     command->mWaitStatus = true;
@@ -2607,7 +2637,8 @@
 
     // Disable wait for status if delay is not 0.
     // Except for create audio patch command because the returned patch handle
-    // is needed by audio policy manager
+    // is needed by audio policy manager. Audio patch created after timeout
+    // (see TIMED_OUT) will be released from threadLoop().
     if (delayMs != 0 && command->mCommand != CREATE_AUDIO_PATCH) {
         command->mWaitStatus = false;
     }
@@ -2652,17 +2683,18 @@
 
 int AudioPolicyService::setStreamVolume(audio_stream_type_t stream,
                                         float volume,
+                                        bool muted,
                                         audio_io_handle_t output,
                                         int delayMs)
 {
-    return (int)mAudioCommandThread->volumeCommand(stream, volume,
+    return (int)mAudioCommandThread->volumeCommand(stream, volume, muted,
                                                    output, delayMs);
 }
 
 int AudioPolicyService::setPortsVolume(const std::vector<audio_port_handle_t> &ports, float volume,
-                                       audio_io_handle_t output, int delayMs)
+                                       bool muted, audio_io_handle_t output, int delayMs)
 {
-    return (int)mAudioCommandThread->volumePortsCommand(ports, volume, output, delayMs);
+    return (int)mAudioCommandThread->volumePortsCommand(ports, volume, muted, output, delayMs);
 }
 
 int AudioPolicyService::setVoiceVolume(float volume, int delayMs)
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d5d4f97..2ce82c0 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -106,10 +106,10 @@
             const std::string& deviceName,
             const AudioFormatDescription& encodedFormat) override;
     binder::Status setPhoneState(AudioMode state, int32_t uid) override;
-    binder::Status setForceUse(media::AudioPolicyForceUse usage,
-                               media::AudioPolicyForcedConfig config) override;
-    binder::Status getForceUse(media::AudioPolicyForceUse usage,
-                               media::AudioPolicyForcedConfig* _aidl_return) override;
+    binder::Status setForceUse(android::media::audio::common::AudioPolicyForceUse usage,
+            android::media::audio::common::AudioPolicyForcedConfig config) override;
+    binder::Status getForceUse(android::media::audio::common::AudioPolicyForceUse usage,
+            android::media::audio::common::AudioPolicyForcedConfig* _aidl_return) override;
     binder::Status getOutput(AudioStreamType stream, int32_t* _aidl_return) override;
     binder::Status getOutputForAttr(const media::audio::common::AudioAttributes& attr,
                                     int32_t session,
@@ -136,13 +136,13 @@
                                     int32_t indexMax) override;
     binder::Status setStreamVolumeIndex(AudioStreamType stream,
                                         const AudioDeviceDescription& device,
-                                        int32_t index) override;
+                                        int32_t index, bool muted) override;
     binder::Status getStreamVolumeIndex(AudioStreamType stream,
                                         const AudioDeviceDescription& device,
                                         int32_t* _aidl_return) override;
     binder::Status setVolumeIndexForAttributes(const media::audio::common::AudioAttributes& attr,
                                                const AudioDeviceDescription& device,
-                                               int32_t index) override;
+                                               int32_t index, bool muted) override;
     binder::Status getVolumeIndexForAttributes(const media::audio::common::AudioAttributes& attr,
                                                const AudioDeviceDescription& device,
                                                int32_t* _aidl_return) override;
@@ -353,6 +353,7 @@
 
     virtual status_t setStreamVolume(audio_stream_type_t stream,
                                      float volume,
+                                     bool muted,
                                      audio_io_handle_t output,
                                      int delayMs = 0);
 
@@ -364,12 +365,13 @@
      *
      * @param ports to consider
      * @param volume to set
+     * @param muted to set
      * @param output to consider
      * @param delayMs to use
      * @return NO_ERROR if successful
      */
     virtual status_t setPortsVolume(const std::vector<audio_port_handle_t> &ports, float volume,
-            audio_io_handle_t output, int delayMs = 0);
+            bool muted, audio_io_handle_t output, int delayMs = 0);
     virtual status_t setVoiceVolume(float volume, int delayMs = 0);
 
     void doOnNewAudioModulesAvailable();
@@ -625,10 +627,10 @@
         virtual     bool        threadLoop();
 
                     void        exit();
-                    status_t    volumeCommand(audio_stream_type_t stream, float volume,
+                    status_t    volumeCommand(audio_stream_type_t stream, float volume, bool muted,
                                             audio_io_handle_t output, int delayMs = 0);
                     status_t    volumePortsCommand(const std::vector<audio_port_handle_t> &ports,
-                            float volume, audio_io_handle_t output, int delayMs = 0);
+                            float volume, bool muted, audio_io_handle_t output, int delayMs = 0);
                     status_t    parametersCommand(audio_io_handle_t ioHandle,
                                             const char *keyValuePairs, int delayMs = 0);
                     status_t    voiceVolumeCommand(float volume, int delayMs = 0);
@@ -700,6 +702,7 @@
         public:
             audio_stream_type_t mStream;
             float mVolume;
+            bool mIsMuted;
             audio_io_handle_t mIO;
         };
 
@@ -707,13 +710,15 @@
         public:
             std::vector<audio_port_handle_t> mPorts;
             float mVolume;
+            bool mMuted;
             audio_io_handle_t mIO;
             std::string dumpPorts() {
-                return std::string("volume ") + std::to_string(mVolume) + " on IO " +
-                        std::to_string(mIO) + " and ports " +
-                        std::accumulate(std::begin(mPorts), std::end(mPorts), std::string{},
-                                       [] (const std::string& ls, int rs) {
-                                return ls + std::to_string(rs) + " "; });
+                return std::string("volume ") + std::to_string(mVolume) + std::string("muted ") +
+                       std::to_string(mMuted) + " on IO " + std::to_string(mIO) + " and ports " +
+                       std::accumulate(std::begin(mPorts), std::end(mPorts), std::string{},
+                                       [](const std::string &ls, int rs) {
+                                           return ls + std::to_string(rs) + " ";
+                                       });
             }
         };
 
@@ -823,7 +828,7 @@
                                     audio_config_base_t *mixerConfig,
                                     const sp<DeviceDescriptorBase>& device,
                                     uint32_t *latencyMs,
-                                    audio_output_flags_t flags,
+                                    audio_output_flags_t *flags,
                                     audio_attributes_t attributes);
         // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
         // a special mixer thread in the AudioFlinger.
@@ -854,9 +859,10 @@
         // misc control functions
         //
 
-        // set a stream volume for a particular output. For the same user setting, a given stream type can have different volumes
-        // for each output (destination device) it is attached to.
-        virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, audio_io_handle_t output, int delayMs = 0);
+        // set a stream volume for a particular output. For the same user setting, a given stream
+        // type can have different volumes for each output (destination device) it is attached to.
+        virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, bool muted,
+                audio_io_handle_t output, int delayMs = 0);
         /**
          * Set a volume on port(s) for a particular output. For the same user setting, a volume
          * group (and associated given port of the client's track) can have different volumes for
@@ -864,12 +870,13 @@
          *
          * @param ports to consider
          * @param volume to set
+         * @param muted to set
          * @param output to consider
          * @param delayMs to use
          * @return NO_ERROR if successful
          */
         status_t setPortsVolume(const std::vector<audio_port_handle_t> &ports, float volume,
-                audio_io_handle_t output, int delayMs = 0) override;
+                bool muted, audio_io_handle_t output, int delayMs = 0) override;
 
         // function enabling to send proprietary informations directly from audio policy manager to audio hardware interface.
         virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0);
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index 874bde4..368dde0 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -22,6 +22,7 @@
 
 #define LOG_TAG "SpatializerPoseController"
 //#define LOG_NDEBUG 0
+#include <audio_utils/mutex.h>
 #include <cutils/properties.h>
 #include <sensor/Sensor.h>
 #include <media/MediaMetricsItem.h>
@@ -131,20 +132,22 @@
               Pose3f headToStage;
               std::optional<HeadTrackingMode> modeIfChanged;
               {
-                  std::unique_lock lock(mMutex);
-                  if (maxUpdatePeriod.has_value()) {
-                      mCondVar.wait_for(lock, maxUpdatePeriod.value(),
-                                        [this] { return mShouldExit || mShouldCalculate; });
-                  } else {
-                      mCondVar.wait(lock, [this] { return mShouldExit || mShouldCalculate; });
+                  audio_utils::unique_lock ul(mMutex);
+                  while (true) {
+                      if (mShouldExit) {
+                          ALOGV("Exiting thread");
+                          return;
+                      }
+                      if (mShouldCalculate) {
+                          std::tie(headToStage, modeIfChanged) = calculate_l();
+                          break;
+                      }
+                      if (maxUpdatePeriod.has_value()) {
+                          mCondVar.wait_for(ul, maxUpdatePeriod.value());
+                      } else {
+                          mCondVar.wait(ul);
+                      }
                   }
-                  if (mShouldExit) {
-                      ALOGV("Exiting thread");
-                      return;
-                  }
-
-                  // Calculate.
-                  std::tie(headToStage, modeIfChanged) = calculate_l();
               }
 
               // Invoke the callbacks outside the lock.
@@ -173,7 +176,7 @@
 
 SpatializerPoseController::~SpatializerPoseController() {
     {
-        std::unique_lock lock(mMutex);
+        std::lock_guard lock(mMutex);
         mShouldExit = true;
         mCondVar.notify_all();
     }
@@ -278,8 +281,10 @@
 }
 
 void SpatializerPoseController::waitUntilCalculated() {
-    std::unique_lock lock(mMutex);
-    mCondVar.wait(lock, [this] { return mCalculated; });
+    audio_utils::unique_lock ul(mMutex);
+    while (!mCalculated) {
+        mCondVar.wait(ul);
+    }
 }
 
 std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
@@ -358,14 +363,15 @@
     }
 }
 
-std::string SpatializerPoseController::toString(unsigned level) const {
+std::string SpatializerPoseController::toString(unsigned level) const NO_THREAD_SAFETY_ANALYSIS {
     std::string prefixSpace(level, ' ');
     std::string ss = prefixSpace + "SpatializerPoseController:\n";
     bool needUnlock = false;
 
     prefixSpace += ' ';
     auto now = std::chrono::steady_clock::now();
-    if (!mMutex.try_lock_until(now + media::kSpatializerDumpSysTimeOutInSecond)) {
+    if (!audio_utils::std_mutex_timed_lock(mMutex, std::chrono::nanoseconds(
+            media::kSpatializerDumpSysTimeOutInSecond).count())) {
         ss.append(prefixSpace).append("try_lock failed, dumpsys maybe INACCURATE!\n");
     } else {
         needUnlock = true;
diff --git a/services/audiopolicy/service/SpatializerPoseController.h b/services/audiopolicy/service/SpatializerPoseController.h
index 7fa4f86..9955cd8 100644
--- a/services/audiopolicy/service/SpatializerPoseController.h
+++ b/services/audiopolicy/service/SpatializerPoseController.h
@@ -118,34 +118,34 @@
     std::string toString(unsigned level) const;
 
   private:
-    mutable std::timed_mutex mMutex;
+    mutable std::mutex mMutex;
     Listener* const mListener;
     const std::chrono::microseconds mSensorPeriod;
-    std::unique_ptr<media::HeadTrackingProcessor> mProcessor;
-    int32_t mHeadSensor = media::SensorPoseProvider::INVALID_HANDLE;
-    int32_t mScreenSensor = media::SensorPoseProvider::INVALID_HANDLE;
-    std::optional<media::HeadTrackingMode> mActualMode;
-    std::condition_variable_any mCondVar;
-    bool mShouldCalculate = true;
-    bool mShouldExit = false;
-    bool mCalculated = false;
+    std::unique_ptr<media::HeadTrackingProcessor> mProcessor GUARDED_BY(mMutex);
+    int32_t mHeadSensor GUARDED_BY(mMutex) = media::SensorPoseProvider::INVALID_HANDLE;
+    int32_t mScreenSensor GUARDED_BY(mMutex) = media::SensorPoseProvider::INVALID_HANDLE;
+    std::optional<media::HeadTrackingMode> mActualMode GUARDED_BY(mMutex);
+    std::condition_variable mCondVar GUARDED_BY(mMutex);
+    bool mShouldCalculate GUARDED_BY(mMutex) = true;
+    bool mShouldExit GUARDED_BY(mMutex) = false;
+    bool mCalculated GUARDED_BY(mMutex) = false;
 
-    media::VectorRecorder mHeadSensorRecorder{
+    media::VectorRecorder mHeadSensorRecorder GUARDED_BY(mMutex) {
         8 /* vectorSize */, std::chrono::seconds(1), 10 /* maxLogLine */,
         { 3, 6, 7 } /* delimiterIdx */};
-    media::VectorRecorder mHeadSensorDurableRecorder{
+    media::VectorRecorder mHeadSensorDurableRecorder GUARDED_BY(mMutex) {
         8 /* vectorSize */, std::chrono::minutes(1), 10 /* maxLogLine */,
         { 3, 6, 7 } /* delimiterIdx */};
 
-    media::VectorRecorder mScreenSensorRecorder{
+    media::VectorRecorder mScreenSensorRecorder GUARDED_BY(mMutex) {
         4 /* vectorSize */, std::chrono::seconds(1), 10 /* maxLogLine */,
         { 3 } /* delimiterIdx */};
-    media::VectorRecorder mScreenSensorDurableRecorder{
+    media::VectorRecorder mScreenSensorDurableRecorder GUARDED_BY(mMutex) {
         4 /* vectorSize */, std::chrono::minutes(1), 10 /* maxLogLine */,
         { 3 } /* delimiterIdx */};
 
     // Next to last variable as releasing this stops the callbacks
-    std::unique_ptr<media::SensorPoseProvider> mPoseProvider;
+    std::unique_ptr<media::SensorPoseProvider> mPoseProvider GUARDED_BY(mMutex);
 
     // It's important that mThread is the last variable in this class
     // since we starts mThread in initializer list
@@ -158,7 +158,8 @@
      * Calculates the new outputs and updates internal state. Must be called with the lock held.
      * Returns values that should be passed to the respective callbacks.
      */
-    std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>> calculate_l();
+    std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>> calculate_l()
+            REQUIRES(mMutex);
 };
 
 }  // namespace android
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index c600fb6..182dc61 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -29,7 +29,6 @@
         "libbase",
         "libbinder",
         "libcutils",
-        "libcutils",
         "libhidlbase",
         "liblog",
         "libmedia_helper",
@@ -41,6 +40,7 @@
     static_libs: [
         "android.media.audiopolicy-aconfig-cc",
         "audioclient-types-aidl-cpp",
+        "com.android.media.audio-aconfig-cc",
         "com.android.media.audioserver-aconfig-cc",
         "libaudiopolicycomponents",
         "libflagtest",
@@ -53,7 +53,10 @@
         "libaudiopolicymanager_interface_headers",
     ],
 
-    srcs: ["audiopolicymanager_tests.cpp"],
+    srcs: [
+        "audiopolicymanager_tests.cpp",
+        "test_execution_tracer.cpp",
+    ],
 
     data: [":audiopolicytest_configuration_files"],
 
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 45643f7..79c25ab 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -17,6 +17,7 @@
 #include <map>
 #include <set>
 
+#include <media/TypeConverter.h>
 #include <system/audio.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
@@ -37,11 +38,11 @@
 
     status_t openOutput(audio_module_handle_t module,
                         audio_io_handle_t *output,
-                        audio_config_t * /*halConfig*/,
-                        audio_config_base_t * /*mixerConfig*/,
+                        audio_config_t *halConfig,
+                        audio_config_base_t *mixerConfig,
                         const sp<DeviceDescriptorBase>& /*device*/,
                         uint32_t * /*latencyMs*/,
-                        audio_output_flags_t /*flags*/,
+                        audio_output_flags_t *flags,
                         audio_attributes_t /*attributes*/) override {
         if (module >= mNextModuleHandle) {
             ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
@@ -49,6 +50,13 @@
             return BAD_VALUE;
         }
         *output = mNextIoHandle++;
+        mOpenedOutputs[*output] = *flags;
+        ALOGD("%s: opened output %d: HAL(%s %s %d) Mixer(%s %s %d) %s", __func__, *output,
+              audio_channel_out_mask_to_string(halConfig->channel_mask),
+              audio_format_to_string(halConfig->format), halConfig->sample_rate,
+              audio_channel_out_mask_to_string(mixerConfig->channel_mask),
+              audio_format_to_string(mixerConfig->format), mixerConfig->sample_rate,
+              android::toString(*flags).c_str());
         return NO_ERROR;
     }
 
@@ -58,6 +66,16 @@
         return id;
     }
 
+    status_t closeOutput(audio_io_handle_t output) override {
+        if (auto iter = mOpenedOutputs.find(output); iter != mOpenedOutputs.end()) {
+            mOpenedOutputs.erase(iter);
+            return NO_ERROR;
+        } else {
+            ALOGE("%s: Unknown output %d", __func__, output);
+            return BAD_VALUE;
+        }
+    }
+
     status_t openInput(audio_module_handle_t module,
                        audio_io_handle_t *input,
                        audio_config_t * /*config*/,
@@ -276,6 +294,13 @@
         return mOpenInputCallsCount;
     }
 
+    std::optional<audio_output_flags_t> getOpenOutputFlags(audio_io_handle_t output) const {
+        if (auto iter = mOpenedOutputs.find(output); iter != mOpenedOutputs.end()) {
+            return iter->second;
+        }
+        return std::nullopt;
+    }
+
 private:
     audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
     audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
@@ -292,6 +317,7 @@
     std::set<audio_io_handle_t> mOpenedInputs;
     size_t mOpenInputCallsCount = 0;
     size_t mCloseInputCallsCount = 0;
+    std::map<audio_io_handle_t, audio_output_flags_t> mOpenedOutputs;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 6f63721..5290da2 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -37,7 +37,7 @@
                         audio_config_base_t* /*mixerConfig*/,
                         const sp<DeviceDescriptorBase>& /*device*/,
                         uint32_t* /*latencyMs*/,
-                        audio_output_flags_t /*flags*/,
+                        audio_output_flags_t* /*flags*/,
                         audio_attributes_t /*attributes*/) override { return NO_INIT; }
     audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
                                           audio_io_handle_t /*output2*/) override {
@@ -56,11 +56,13 @@
     status_t closeInput(audio_io_handle_t /*input*/) override { return NO_INIT; }
     status_t setStreamVolume(audio_stream_type_t /*stream*/,
                              float /*volume*/,
+                             bool /*muted*/,
                              audio_io_handle_t /*output*/,
                              int /*delayMs*/) override { return NO_INIT; }
 
-    status_t setPortsVolume(const std::vector<audio_port_handle_t>& /*ports*/, float /*volume*/,
-            audio_io_handle_t /*output*/, int /*delayMs*/) override { return NO_INIT; }
+    status_t setPortsVolume(const std::vector<audio_port_handle_t> & /*ports*/, float /*volume*/,
+                            bool /*muted*/, audio_io_handle_t /*output*/,
+                            int /*delayMs*/) override { return NO_INIT; }
 
     void setParameters(audio_io_handle_t /*ioHandle*/,
                        const String8& /*keyValuePairs*/,
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 34ceeab..e30882c 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -24,9 +24,11 @@
     explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
             : AudioPolicyTestManager(AudioPolicyConfig::createDefault(), clientInterface) {}
     AudioPolicyTestManager(const sp<const AudioPolicyConfig>& config,
-            AudioPolicyClientInterface *clientInterface)
+            AudioPolicyClientInterface *clientInterface,
+            std::string engineConfig = "")
             : AudioPolicyManager(config,
-                    loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
+                    loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix(),
+                                                        engineConfig),
                     clientInterface) {}
     using AudioPolicyManager::getConfig;
     using AudioPolicyManager::initialize;
@@ -44,6 +46,7 @@
     using AudioPolicyManager::setDeviceConnectionState;
     using AudioPolicyManager::deviceToAudioPort;
     using AudioPolicyManager::handleDeviceConfigChange;
+    using AudioPolicyManager::getInputProfile;
     uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
     HwModuleCollection getHwModules() const { return mHwModules; }
 };
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 43b451f..d83a277 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -35,6 +35,7 @@
 #include <media/AudioPolicy.h>
 #include <media/PatchBuilder.h>
 #include <media/RecordingActivityTracker.h>
+#include <media/TypeConverter.h>
 #include <utils/Log.h>
 #include <utils/Vector.h>
 #include <cutils/multiuser.h>
@@ -43,6 +44,7 @@
 #include "AudioPolicyManagerTestClient.h"
 #include "AudioPolicyTestClient.h"
 #include "AudioPolicyTestManager.h"
+#include "test_execution_tracer.h"
 
 using namespace android;
 using testing::UnorderedElementsAre;
@@ -175,6 +177,11 @@
 };
 
 class AudioPolicyManagerTest : public testing::Test {
+  public:
+    constexpr static uint32_t k384000SamplingRate = 384000;
+    constexpr static uint32_t k48000SamplingRate = 48000;
+    constexpr static uint32_t k96000SamplingRate = 96000;
+
   protected:
     void SetUp() override;
     void TearDown() override;
@@ -191,7 +198,7 @@
             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
             audio_io_handle_t *output = nullptr,
             audio_port_handle_t *portId = nullptr,
-            audio_attributes_t attr = {},
+            audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER,
             audio_session_t session = AUDIO_SESSION_NONE,
             int uid = 0,
             bool* isBitPerfect = nullptr);
@@ -222,13 +229,16 @@
     std::unique_ptr<AudioPolicyManagerTestClient> mClient;
     std::unique_ptr<AudioPolicyTestManager> mManager;
 
-    constexpr static const uint32_t k48000SamplingRate = 48000;
+    static const std::string sTestEngineConfig;
 };
 
+const std::string AudioPolicyManagerTest::sTestEngineConfig =
+        base::GetExecutableDirectory() + "/engine/test_audio_policy_engine_configuration.xml";
+
 void AudioPolicyManagerTest::SetUp() {
     mClient.reset(getClient());
     ASSERT_NO_FATAL_FAILURE(SetUpManagerConfig());  // Subclasses may want to customize the config.
-    mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get()));
+    mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get(), sTestEngineConfig));
     ASSERT_EQ(NO_ERROR, mManager->initialize());
     ASSERT_EQ(NO_ERROR, mManager->initCheck());
 }
@@ -300,11 +310,13 @@
     bool isSpatialized;
     bool isBitPerfectInternal;
     float volume;
+    bool muted;
     AttributionSourceState attributionSource = createAttributionSourceState(uid);
     ASSERT_EQ(OK, mManager->getOutputForAttr(
                     &attr, output, session, &stream, attributionSource, &config, &flags,
                     selectedDeviceId, portId, {}, &outputType, &isSpatialized,
-                    isBitPerfect == nullptr ? &isBitPerfectInternal : isBitPerfect, &volume));
+                    isBitPerfect == nullptr ? &isBitPerfectInternal : isBitPerfect, &volume,
+                    &muted));
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
     ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
 }
@@ -490,6 +502,9 @@
 void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
     // TODO: Consider using Serializer to load part of the config from a string.
     ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTest::SetUpManagerConfig());
+    mConfig->getHwModules().getModuleFromName(
+            AUDIO_HARDWARE_MODULE_ID_PRIMARY)->setHalVersion(3, 0);
+
     mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
     sp<AudioProfile> pcmOutputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, k48000SamplingRate);
@@ -521,7 +536,7 @@
                 addOutputProfile(spdifOutputProfile);
     }
 
-    sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
+    sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 3 /*halVersionMajor*/);
     HwModuleCollection modules = mConfig->getHwModules();
     modules.add(msdModule);
     mConfig->setHwModules(modules);
@@ -783,27 +798,27 @@
 
     audio_config_base_t directConfig = AUDIO_CONFIG_BASE_INITIALIZER;
     directConfig.format = AUDIO_FORMAT_DTS;
-    directConfig.sample_rate = 48000;
+    directConfig.sample_rate = k48000SamplingRate;
     directConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
 
     audio_config_base_t nonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
     nonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
-    nonDirectConfig.sample_rate = 48000;
+    nonDirectConfig.sample_rate = k48000SamplingRate;
     nonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
 
     audio_config_base_t nonExistentConfig = AUDIO_CONFIG_BASE_INITIALIZER;
     nonExistentConfig.format = AUDIO_FORMAT_E_AC3;
-    nonExistentConfig.sample_rate = 48000;
+    nonExistentConfig.sample_rate = k48000SamplingRate;
     nonExistentConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
 
     audio_config_base_t msdDirectConfig1 = AUDIO_CONFIG_BASE_INITIALIZER;
     msdDirectConfig1.format = AUDIO_FORMAT_AC3;
-    msdDirectConfig1.sample_rate = 48000;
+    msdDirectConfig1.sample_rate = k48000SamplingRate;
     msdDirectConfig1.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
 
     audio_config_base_t msdDirectConfig2 = AUDIO_CONFIG_BASE_INITIALIZER;
     msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
-    msdDirectConfig2.sample_rate = 48000;
+    msdDirectConfig2.sample_rate = k48000SamplingRate;
     msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
 
     audio_config_base_t msdNonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
@@ -850,27 +865,27 @@
 
     audio_config_t directConfig = AUDIO_CONFIG_INITIALIZER;
     directConfig.format = AUDIO_FORMAT_DTS;
-    directConfig.sample_rate = 48000;
+    directConfig.sample_rate = k48000SamplingRate;
     directConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
 
     audio_config_t nonDirectConfig = AUDIO_CONFIG_INITIALIZER;
     nonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
-    nonDirectConfig.sample_rate = 48000;
+    nonDirectConfig.sample_rate = k48000SamplingRate;
     nonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
 
     audio_config_t nonExistentConfig = AUDIO_CONFIG_INITIALIZER;
     nonExistentConfig.format = AUDIO_FORMAT_E_AC3;
-    nonExistentConfig.sample_rate = 48000;
+    nonExistentConfig.sample_rate = k48000SamplingRate;
     nonExistentConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
 
     audio_config_t msdDirectConfig1 = AUDIO_CONFIG_INITIALIZER;
     msdDirectConfig1.format = AUDIO_FORMAT_AC3;
-    msdDirectConfig1.sample_rate = 48000;
+    msdDirectConfig1.sample_rate = k48000SamplingRate;
     msdDirectConfig1.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
 
     audio_config_t msdDirectConfig2 = AUDIO_CONFIG_INITIALIZER;
     msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
-    msdDirectConfig2.sample_rate = 48000;
+    msdDirectConfig2.sample_rate = k48000SamplingRate;
     msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
 
     audio_config_t msdNonDirectConfig = AUDIO_CONFIG_INITIALIZER;
@@ -1126,12 +1141,12 @@
     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
-            48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
+            k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
             AUDIO_SESSION_NONE, uid);
     status_t status = mManager->startOutput(portId);
     if (status == DEAD_OBJECT) {
         getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
-                48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
+                k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
                 AUDIO_SESSION_NONE, uid);
         status = mManager->startOutput(portId);
     }
@@ -1172,9 +1187,9 @@
     audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
     AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
     audio_config_base_t requestedConfig = {
+            .sample_rate = k48000SamplingRate,
             .channel_mask = AUDIO_CHANNEL_IN_STEREO,
             .format = AUDIO_FORMAT_PCM_16_BIT,
-            .sample_rate = 48000
     };
     audio_config_base_t config = requestedConfig;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -1234,6 +1249,33 @@
     EXPECT_EQ(streamCountBefore, mClient->getOpenedInputsCount());
 }
 
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, UpdateConfigFromInexactProfile) {
+    const audio_format_t expectedFormat = AUDIO_FORMAT_PCM_16_BIT;
+    const uint32_t expectedSampleRate = 48000;
+    const audio_channel_mask_t expectedChannelMask = AUDIO_CHANNEL_IN_STEREO;
+    const std::string expectedIOProfile = "primary input";
+
+    auto devices = mManager->getAvailableInputDevices();
+    sp<DeviceDescriptor> mic = nullptr;
+    for (auto device : devices) {
+        if (device->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            mic = device;
+            break;
+        }
+    }
+    EXPECT_NE(nullptr, mic);
+
+    audio_format_t requestedFormat = AUDIO_FORMAT_PCM_16_BIT;
+    uint32_t requestedSampleRate = 44100;
+    audio_channel_mask_t requestedChannelMask = AUDIO_CHANNEL_IN_STEREO;
+    auto profile = mManager->getInputProfile(
+            mic, requestedSampleRate, requestedFormat, requestedChannelMask, AUDIO_INPUT_FLAG_NONE);
+    EXPECT_EQ(expectedIOProfile, profile->getName());
+    EXPECT_EQ(expectedFormat, requestedFormat);
+    EXPECT_EQ(expectedSampleRate, requestedSampleRate);
+    EXPECT_EQ(expectedChannelMask, requestedChannelMask);
+}
+
 class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
 protected:
     void TearDown() override;
@@ -2067,6 +2109,7 @@
     bool mIsSpatialized;
     bool mIsBitPerfect;
     float mVolume;
+    bool mMuted;
 };
 
 TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting, MmapPlaybackStreamMatchingLoopbackDapMixFails) {
@@ -2085,7 +2128,8 @@
               mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
                                          createAttributionSourceState(testUid), &audioConfig,
                                          &outputFlags, &mSelectedDeviceId, &mPortId, {},
-                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+                                         &mMuted));
 }
 
 TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting,
@@ -2104,7 +2148,8 @@
               mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
                                          createAttributionSourceState(testUid), &audioConfig,
                                          &outputFlags, &mSelectedDeviceId, &mPortId, {},
-                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+                                         &mMuted));
 }
 
 TEST_F(AudioPolicyManagerTestMMapPlaybackRerouting,
@@ -2135,7 +2180,8 @@
               mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
                                          createAttributionSourceState(testUid), &audioConfig,
                                          &outputFlags, &mSelectedDeviceId, &mPortId, {},
-                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+                                         &mMuted));
     ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
     auto outputDesc = mManager->getOutputs().valueFor(mOutput);
     ASSERT_NE(nullptr, outputDesc);
@@ -2151,7 +2197,8 @@
               mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
                                          createAttributionSourceState(testUid), &audioConfig,
                                          &outputFlags, &mSelectedDeviceId, &mPortId, {},
-                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+                                         &mMuted));
     ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
     outputDesc = mManager->getOutputs().valueFor(mOutput);
     ASSERT_NE(nullptr, outputDesc);
@@ -2180,7 +2227,8 @@
               mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
                                          createAttributionSourceState(testUid), &audioConfig,
                                          &outputFlags, &mSelectedDeviceId, &mPortId, {},
-                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+                                         &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+                                         &mMuted));
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -2510,7 +2558,7 @@
                         audio_config_base_t * mixerConfig,
                         const sp<DeviceDescriptorBase>& device,
                         uint32_t * latencyMs,
-                        audio_output_flags_t flags,
+                        audio_output_flags_t *flags,
                         audio_attributes_t attributes) override {
         return mSimulateFailure ? BAD_VALUE :
                 AudioPolicyManagerTestClient::openOutput(
@@ -2532,8 +2580,29 @@
 
     void setSimulateFailure(bool simulateFailure) { mSimulateFailure = simulateFailure; }
 
+    void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
+        if (status != NO_ERROR) {
+            // simulate device connect status
+            mSimulateBroadcastDeviceStatus[device] = status;
+        } else {
+            // remove device connection fixed status
+            mSimulateBroadcastDeviceStatus.erase(device);
+        }
+    }
+
+    status_t setDeviceConnectedState(const struct audio_port_v7* port,
+                                     media::DeviceConnectedState state) override {
+        if (mSimulateBroadcastDeviceStatus.find(port->ext.device.type) !=
+            mSimulateBroadcastDeviceStatus.end()) {
+            // If a simulated status exists, return a status value
+            return mSimulateBroadcastDeviceStatus[port->ext.device.type];
+        }
+        return AudioPolicyManagerTestClient::setDeviceConnectedState(port, state);
+    }
+
   private:
     bool mSimulateFailure = false;
+    std::map<audio_devices_t, status_t> mSimulateBroadcastDeviceStatus;
 };
 
 }  // namespace
@@ -2554,6 +2623,9 @@
     void setSimulateOpenFailure(bool simulateFailure) {
         mFullClient->setSimulateFailure(simulateFailure); }
 
+    void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
+        mFullClient->setSimulateBroadcastDeviceStatus(device, status); }
+
     static const std::string sBluetoothConfig;
 
   private:
@@ -2597,6 +2669,30 @@
     }
 }
 
+TEST_P(AudioPolicyManagerTestDeviceConnectionFailed, BroadcastDeviceFailure) {
+    const audio_devices_t type = std::get<0>(GetParam());
+    const std::string name = std::get<1>(GetParam());
+    const std::string address = std::get<2>(GetParam());
+    const audio_format_t format = std::get<3>(GetParam());
+
+    // simulate broadcastDeviceConnectionState return failure
+    setSimulateBroadcastDeviceStatus(type, INVALID_OPERATION);
+    ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            address.c_str(), name.c_str(), format));
+
+    // if broadcast is fail, device should not be added to available devices list
+    if (audio_is_output_device(type)) {
+        auto availableDevices = mManager->getAvailableOutputDevices();
+        EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
+    } else if (audio_is_input_device(type)) {
+        auto availableDevices = mManager->getAvailableInputDevices();
+        EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
+    }
+
+    setSimulateBroadcastDeviceStatus(type, NO_ERROR);
+}
+
 INSTANTIATE_TEST_CASE_P(
         DeviceConnectionFailure,
         AudioPolicyManagerTestDeviceConnectionFailed,
@@ -3181,6 +3277,259 @@
             "low latency");
 }
 
+class AudioPolicyManagerPhoneTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+    std::string getConfigFile() override { return sPhoneConfig; }
+    void testOutputMixPortSelectionForAttr(audio_output_flags_t flags, audio_format_t format,
+            int samplingRate, bool isMusic, const char* expectedMixPortName);
+    void testOutputMixPortSelectionForStream(
+            audio_stream_type_t stream, const char* expectedMixPortName);
+    void verifyMixPortNameAndFlags(audio_io_handle_t output, const char* expectedMixPortName);
+
+    static const std::string sPhoneConfig;
+    static const std::map<std::string, audio_output_flags_t> sMixPortFlags;
+};
+
+const std::string AudioPolicyManagerPhoneTest::sPhoneConfig =
+        AudioPolicyManagerPhoneTest::sExecutableDir + "test_phone_apm_configuration.xml";
+
+// Must be in sync with the contents of the sPhoneConfig file.
+const std::map<std::string, audio_output_flags_t> AudioPolicyManagerPhoneTest::sMixPortFlags = {
+        {"primary output",
+         (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_PRIMARY | AUDIO_OUTPUT_FLAG_FAST)},
+        {"direct", AUDIO_OUTPUT_FLAG_DIRECT},
+        {"deep buffer", AUDIO_OUTPUT_FLAG_DEEP_BUFFER},
+        {"compressed_offload",
+         (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+                                AUDIO_OUTPUT_FLAG_NON_BLOCKING |
+                                AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD)},
+        {"raw", (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_FAST)},
+        {"mmap_no_irq_out",
+         (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)},
+        {"voip_rx", AUDIO_OUTPUT_FLAG_VOIP_RX},
+};
+
+void AudioPolicyManagerPhoneTest::testOutputMixPortSelectionForAttr(
+        audio_output_flags_t flags, audio_format_t format, int samplingRate, bool isMusic,
+        const char* expectedMixPortName) {
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_io_handle_t output;
+    audio_port_handle_t portId;
+    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+    if (isMusic) {
+        attr.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+        attr.usage = AUDIO_USAGE_MEDIA;
+    }
+    getOutputForAttr(&selectedDeviceId, format, AUDIO_CHANNEL_OUT_STEREO, samplingRate, flags,
+            &output, &portId, attr);
+    EXPECT_NO_FATAL_FAILURE(verifyMixPortNameAndFlags(output, expectedMixPortName));
+    mManager->releaseOutput(portId);
+}
+
+void AudioPolicyManagerPhoneTest::testOutputMixPortSelectionForStream(
+        audio_stream_type_t stream, const char* expectedMixPortName) {
+    audio_io_handle_t output = mManager->getOutput(stream);
+    EXPECT_NO_FATAL_FAILURE(verifyMixPortNameAndFlags(output, expectedMixPortName));
+}
+
+void AudioPolicyManagerPhoneTest::verifyMixPortNameAndFlags(audio_io_handle_t output,
+                                                            const char* expectedMixPortName) {
+    ALOGI("%s: checking output %d", __func__, output);
+    sp<SwAudioOutputDescriptor> outDesc = mManager->getOutputs().valueFor(output);
+    ASSERT_NE(nullptr, outDesc.get());
+    audio_port_v7 port = {};
+    outDesc->toAudioPort(&port);
+    EXPECT_EQ(AUDIO_PORT_TYPE_MIX, port.type);
+    EXPECT_EQ(AUDIO_PORT_ROLE_SOURCE, port.role);
+    ASSERT_STREQ(expectedMixPortName, port.name);
+
+    auto iter = sMixPortFlags.find(port.name);
+    ASSERT_NE(iter, sMixPortFlags.end()) << "\"" << port.name << "\" is not in sMixPortFlags";
+    auto actualFlags = mClient->getOpenOutputFlags(output);
+    ASSERT_TRUE(actualFlags.has_value()) << "\"" << port.name << "\" was not opened via client";
+    EXPECT_EQ(*actualFlags, iter->second);
+}
+
+TEST_F(AudioPolicyManagerPhoneTest, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+enum {
+    MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER,
+    MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER,
+    MIX_PORT_ATTR_FLAGS_PARAMETER,
+    MIX_PORT_ATTR_FORMAT_PARAMETER,
+    MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER,
+};
+using MixPortSelectionForAttr =
+        std::tuple<const char*, const char*, audio_output_flags_t, audio_format_t, int>;
+
+class AudioPolicyManagerOutputMixPortForAttrSelectionTest
+    : public AudioPolicyManagerPhoneTest,
+      public testing::WithParamInterface<MixPortSelectionForAttr> {
+};
+
+// There is no easy way to create a flat tuple from tuples via ::testing::Combine.
+// Instead, just run the same selection twice while altering the deep buffer for media setting.
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags) {
+    mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+    ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForAttr(
+                    std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+                    std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+                    std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+                    false /*isMusic*/,
+                    std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_Music) {
+    mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+    ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForAttr(
+                    std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+                    std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+                    std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+                    true /*isMusic*/,
+                    std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_DeepMedia) {
+    mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+    const char* fallbackName = std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam());
+    ASSERT_NO_FATAL_FAILURE(
+            testOutputMixPortSelectionForAttr(std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+                                       std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+                                       std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+                                       false /*isMusic*/,
+                                       std::get<MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+                                               GetParam()) ?: fallbackName));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_DeepMedia_Music) {
+    mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+    const char* fallbackName = std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam());
+    ASSERT_NO_FATAL_FAILURE(
+            testOutputMixPortSelectionForAttr(std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+                                       std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+                                       std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+                                       true /*isMusic*/,
+                                       std::get<MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+                                               GetParam()) ?: fallbackName));
+}
+
+INSTANTIATE_TEST_CASE_P(AudioPolicyManagerOutputMixPortForAttrSelection,
+        AudioPolicyManagerOutputMixPortForAttrSelectionTest,
+        ::testing::Values(
+                std::make_tuple("primary output", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+                        AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+                std::make_tuple("primary output", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+                        AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k48000SamplingRate),
+                // Note: this goes to "direct" because 384000 > SAMPLE_RATE_HZ_MAX (192000)
+                std::make_tuple("direct", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+                        AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+                std::make_tuple("primary output", nullptr, AUDIO_OUTPUT_FLAG_FAST,
+                        AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+                std::make_tuple("direct", nullptr, AUDIO_OUTPUT_FLAG_DIRECT,
+                        AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k96000SamplingRate),
+                std::make_tuple("direct", nullptr, AUDIO_OUTPUT_FLAG_DIRECT,
+                        AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+                std::make_tuple("deep buffer", nullptr, AUDIO_OUTPUT_FLAG_DEEP_BUFFER,
+                        AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+                std::make_tuple("deep buffer", nullptr, AUDIO_OUTPUT_FLAG_DEEP_BUFFER,
+                        AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+                std::make_tuple("compressed_offload", nullptr,
+                        (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+                                AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+                        AUDIO_FORMAT_MP3, AudioPolicyManagerTest::k48000SamplingRate),
+                std::make_tuple("raw", nullptr,
+                        AUDIO_OUTPUT_FLAG_RAW, AUDIO_FORMAT_PCM_32_BIT,
+                        AudioPolicyManagerTest::k48000SamplingRate),
+                std::make_tuple("mmap_no_irq_out", nullptr,
+                        (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT |
+                                AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+                        AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k48000SamplingRate),
+                std::make_tuple("mmap_no_irq_out", nullptr,
+                        (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT |
+                                AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+                        AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+                std::make_tuple("voip_rx", nullptr, AUDIO_OUTPUT_FLAG_VOIP_RX,
+                        AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate)),
+        [](const ::testing::TestParamInfo<MixPortSelectionForAttr>& info) {
+            static const std::string flagPrefix = "AUDIO_OUTPUT_FLAG_";
+            static const std::string formatPrefix = "AUDIO_FORMAT_";
+            std::string flags;
+            TypeConverter<OutputFlagTraits>::maskToString(
+                    std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(info.param), flags, "__");
+            size_t index = 0;
+            while (true) {
+                index = flags.rfind(flagPrefix);
+                if (index == std::string::npos) break;
+                flags.erase(index, flagPrefix.length());
+            }
+            std::string format;
+            TypeConverter<FormatTraits>::toString(
+                    std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(info.param), format);
+            if (size_t index = format.find(formatPrefix); index != std::string::npos) {
+                format.erase(index, formatPrefix.length());
+            }
+            return flags + "__" + format + "__" +
+                    std::to_string(std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(info.param));
+        }
+);
+
+
+enum {
+    MIX_PORT_STRM_EXPECTED_NAME_PARAMETER,
+    MIX_PORT_STRM_EXPECTED_NAME_WITH_DBFM_PARAMETER,
+    MIX_PORT_STRM_STREAM_PARAMETER,
+};
+using MixPortSelectionForStream =
+        std::tuple<const char*, const char*, audio_stream_type_t>;
+
+class AudioPolicyManagerOutputMixPortForStreamSelectionTest
+    : public AudioPolicyManagerPhoneTest,
+      public testing::WithParamInterface<MixPortSelectionForStream> {
+};
+
+// There is no easy way to create a flat tuple from tuples via ::testing::Combine.
+// Instead, just run the same selection twice while altering the deep buffer for media setting.
+TEST_P(AudioPolicyManagerOutputMixPortForStreamSelectionTest, SelectPort_NoDBFM) {
+    mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+    ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForStream(
+                    std::get<MIX_PORT_STRM_STREAM_PARAMETER>(GetParam()),
+                    std::get<MIX_PORT_STRM_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForStreamSelectionTest, SelectPort_WithDBFM) {
+    mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+    const char* fallbackName = std::get<MIX_PORT_STRM_EXPECTED_NAME_PARAMETER>(GetParam());
+    ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForStream(
+                    std::get<MIX_PORT_STRM_STREAM_PARAMETER>(GetParam()),
+                    std::get<MIX_PORT_STRM_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+                            GetParam()) ?: fallbackName));
+}
+
+INSTANTIATE_TEST_CASE_P(
+        AudioPolicyManagerOutputMixPortForStreamSelection,
+        AudioPolicyManagerOutputMixPortForStreamSelectionTest,
+        ::testing::Values(std::make_tuple("primary output", nullptr, AUDIO_STREAM_DEFAULT),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_SYSTEM),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_RING),
+                          std::make_tuple("primary output", "deep buffer", AUDIO_STREAM_MUSIC),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_ALARM),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_NOTIFICATION),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_BLUETOOTH_SCO),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_ENFORCED_AUDIBLE),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_DTMF),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_TTS),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_ACCESSIBILITY),
+                          std::make_tuple("primary output", nullptr, AUDIO_STREAM_ASSISTANT)),
+        [](const ::testing::TestParamInfo<MixPortSelectionForStream>& info) {
+            static const std::string streamPrefix = "AUDIO_STREAM_";
+            std::string stream;
+            TypeConverter<StreamTraits>::toString(
+                    std::get<MIX_PORT_STRM_STREAM_PARAMETER>(info.param), stream);
+            if (size_t index = stream.find(streamPrefix); index != std::string::npos) {
+                stream.erase(index, streamPrefix.length());
+            }
+            return stream;
+        }
+);
+
 class AudioPolicyManagerDynamicHwModulesTest : public AudioPolicyManagerTestWithConfigurationFile {
 protected:
     void SetUpManagerConfig() override;
@@ -3333,7 +3682,7 @@
     audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
     auto selectedDevice = availableDevices.getDeviceFromId(selectedDeviceId);
     ASSERT_NE(nullptr, selectedDevice);
 
@@ -3354,7 +3703,7 @@
     input = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
     ASSERT_EQ(preferredDevice, availableDevices.getDeviceFromId(selectedDeviceId));
 
     // After clearing preferred device for capture preset, the selected device for input should be
@@ -3365,7 +3714,7 @@
     input = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
     ASSERT_EQ(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
 
     ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
@@ -3391,7 +3740,7 @@
     audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
     auto selectedDevice = availableDevices.getDeviceFromId(selectedDeviceId);
     ASSERT_NE(nullptr, selectedDevice);
 
@@ -3404,7 +3753,7 @@
     input = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1,
                                             &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
-                                            AUDIO_CHANNEL_IN_STEREO, 48000));
+                                            AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate));
     ASSERT_NE(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
 
     // After clearing disabled device for capture preset, the selected device for input should be
@@ -3415,7 +3764,7 @@
     input = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
     ASSERT_EQ(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
 
     ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
@@ -3518,7 +3867,7 @@
     // effect attached again
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &inputClientHandle, session, 1, &routedPortId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
 
     // unregister effect should succeed since effect shall have been restore on the client session
     ASSERT_EQ(NO_ERROR, mManager->unregisterEffect(effectId));
@@ -3535,7 +3884,7 @@
 
     const audio_format_t mBitPerfectFormat = AUDIO_FORMAT_PCM_16_BIT;
     const audio_channel_mask_t mBitPerfectChannelMask = AUDIO_CHANNEL_OUT_STEREO;
-    const uint32_t mBitPerfectSampleRate = 48000;
+    const uint32_t mBitPerfectSampleRate = k48000SamplingRate;
     const uid_t mUid = 1234;
     audio_port_handle_t mUsbPortId = AUDIO_PORT_HANDLE_NONE;
 
@@ -3637,11 +3986,12 @@
     bool isSpatialized;
     bool isBitPerfect;
     float volume;
+    bool muted;
     EXPECT_EQ(expected,
               mManager->getOutputForAttr(&sMediaAttr, &mBitPerfectOutput, AUDIO_SESSION_NONE,
                                          &stream, attributionSource, &config, &flags,
                                          &mSelectedDeviceId, &mBitPerfectPortId, {}, &outputType,
-                                         &isSpatialized, &isBitPerfect, &volume));
+                                         &isSpatialized, &isBitPerfect, &volume, &muted));
 }
 
 class AudioPolicyManagerTestBitPerfect : public AudioPolicyManagerTestBitPerfectBase {
@@ -3811,8 +4161,8 @@
     ASSERT_NO_FATAL_FAILURE(startBitPerfectOutput());
 
     audio_attributes_t attr = {
+            .content_type = AUDIO_CONTENT_TYPE_UNKNOWN,
             .usage = GetParam(),
-            .content_type = AUDIO_CONTENT_TYPE_UNKNOWN
     };
     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -3853,14 +4203,14 @@
     audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
 
     EXPECT_EQ(1, mClient->getOpenInputCallsCount());
 
     audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, TEST_SESSION_ID, 1, &selectedDeviceId,
                                         AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                        48000));
+                                        k48000SamplingRate));
 
     EXPECT_EQ(1, mClient->getOpenInputCallsCount());
     EXPECT_EQ(0, mClient->getCloseInputCallsCount());
@@ -3881,7 +4231,7 @@
     audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
 
     EXPECT_EQ(1, mClient->getOpenInputCallsCount());
 
@@ -3889,7 +4239,7 @@
     attr.source = AUDIO_SOURCE_VOICE_RECOGNITION;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
                                         AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                        48000));
+                                        k48000SamplingRate));
 
     EXPECT_EQ(1, mClient->getOpenInputCallsCount());
     EXPECT_EQ(0, mClient->getCloseInputCallsCount());
@@ -3910,7 +4260,7 @@
     audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
                                             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                            48000));
+                                            k48000SamplingRate));
 
     EXPECT_EQ(1, mClient->getOpenInputCallsCount());
 
@@ -3918,9 +4268,15 @@
     attr.source = AUDIO_SOURCE_CAMCORDER;
     ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
                                         AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
-                                        48000));
+                                        k48000SamplingRate));
 
     EXPECT_EQ(2, mClient->getOpenInputCallsCount());
     EXPECT_EQ(1, mClient->getCloseInputCallsCount());
     EXPECT_NE(input1, input2);
 }
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    return RUN_ALL_TESTS();
+}
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index 1c191f5..8e7a697 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -11,11 +11,16 @@
 filegroup {
     name: "audiopolicytest_configuration_files",
     srcs: [
+        "engine/test_audio_policy_engine_configuration.xml",
+        "engine/test_audio_policy_engine_default_stream_volumes.xml",
+        "engine/test_audio_policy_engine_product_strategies.xml",
+        "engine/test_audio_policy_engine_stream_volumes.xml",
         "test_audio_policy_configuration.xml",
         "test_audio_policy_configuration_bluetooth.xml",
         "test_audio_policy_primary_only_configuration.xml",
         "test_car_ap_atmos_offload_configuration.xml",
         "test_invalid_audio_policy_configuration.xml",
+        "test_phone_apm_configuration.xml",
         "test_settop_box_surround_configuration.xml",
         "test_tv_apm_configuration.xml",
     ],
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml
new file mode 100644
index 0000000..dc2e7af
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+     -->
+
+<configuration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+    <xi:include href="test_audio_policy_engine_product_strategies.xml"/>
+    <xi:include href="test_audio_policy_engine_stream_volumes.xml"/>
+    <xi:include href="test_audio_policy_engine_default_stream_volumes.xml"/>
+
+</configuration>
+
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml
new file mode 100644
index 0000000..d184cb5
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Default Volume Tables included by Audio Policy Configuration file -->
+<!-- Full Default Volume table for all device category -->
+<volumes>
+    <reference name="FULL_SCALE_VOLUME_CURVE">
+    <!-- Full Scale reference Volume Curve -->
+        <point>0,0</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="SILENT_VOLUME_CURVE">
+        <point>0,-9600</point>
+        <point>100,-9600</point>
+    </reference>
+    <reference name="DEFAULT_SYSTEM_VOLUME_CURVE">
+    <!-- Default System reference Volume Curve -->
+        <point>1,-2400</point>
+        <point>33,-1800</point>
+        <point>66,-1200</point>
+        <point>100,-600</point>
+    </reference>
+    <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+    <!-- Default Media reference Volume Curve -->
+        <point>1,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE">
+    <!--Default Volume Curve -->
+        <point>1,-4950</point>
+        <point>33,-3350</point>
+        <point>66,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
+    <!-- Default is Speaker Media Volume Curve -->
+        <point>1,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE">
+    <!-- Default is Speaker System Volume Curve -->
+        <point>1,-4680</point>
+        <point>42,-2070</point>
+        <point>85,-540</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE">
+    <!--Default Volume Curve -->
+        <point>1,-4950</point>
+        <point>33,-3350</point>
+        <point>66,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE">
+    <!-- Default is Ext Media System Volume Curve -->
+        <point>1,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-2100</point>
+        <point>100,-1000</point>
+    </reference>
+    <reference name="DEFAULT_HEARING_AID_VOLUME_CURVE">
+    <!-- Default Hearing Aid Volume Curve -->
+        <point>1,-12700</point>
+        <point>20,-8000</point>
+        <point>60,-4000</point>
+        <point>100,0</point>
+    </reference>
+    <!-- **************************************************************** -->
+    <!-- Non-mutable default volume curves:                               -->
+    <!--     * first point is always for index 0                          -->
+    <!--     * attenuation is small enough that stream can still be heard -->
+    <reference name="DEFAULT_NON_MUTABLE_VOLUME_CURVE">
+    <!-- Default non-mutable reference Volume Curve -->
+    <!--        based on DEFAULT_MEDIA_VOLUME_CURVE -->
+        <point>0,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE">
+    <!--Default non-mutable Volume Curve for headset -->
+    <!--    based on DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE -->
+        <point>0,-4950</point>
+        <point>33,-3350</point>
+        <point>66,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE">
+    <!-- Default non-mutable Speaker Volume Curve -->
+    <!--    based on DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE -->
+        <point>0,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE">
+    <!--Default non-mutable Volume Curve -->
+    <!--    based on DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE -->
+        <point>0,-4950</point>
+        <point>33,-3350</point>
+        <point>66,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE">
+    <!-- Default non-mutable Ext Media System Volume Curve -->
+    <!--     based on DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE -->
+        <point>0,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-2100</point>
+        <point>100,-1000</point>
+    </reference>
+    <reference name="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE">
+    <!-- Default non-mutable Hearing Aid Volume Curve -->
+    <!--     based on DEFAULT_HEARING_AID_VOLUME_CURVE -->
+        <point>0,-12700</point>
+        <point>20,-8000</point>
+        <point>60,-4000</point>
+        <point>100,0</point>
+    </reference>
+</volumes>
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml
new file mode 100644
index 0000000..58e7152
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+     -->
+
+<ProductStrategies>
+
+    <!-- "hidden strategies" like TTS, enforced audible:
+            Shall we expose them here or keep it hard coded -->
+
+    <!-- Used to identify the volume of audio streams for enforced system sounds in certain
+         countries (e.g. camera in Japan)
+         This strategy will only have higher priority than phone if force for system is set to
+         enforced. -->
+
+    <ProductStrategy name="STRATEGY_PHONE">
+        <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
+            <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
+        </AttributesGroup>
+        <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
+            <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <ProductStrategy name="STRATEGY_SONIFICATION">
+        <AttributesGroup streamType="AUDIO_STREAM_RING" volumeGroup="ring">
+            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/> </Attributes>
+        </AttributesGroup>
+        <AttributesGroup streamType="AUDIO_STREAM_ALARM" volumeGroup="alarm">
+            <Attributes> <Usage value="AUDIO_USAGE_ALARM"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <ProductStrategy name="STRATEGY_ENFORCED_AUDIBLE">
+        <AttributesGroup streamType="AUDIO_STREAM_ENFORCED_AUDIBLE" volumeGroup="enforced_audible">
+            <Attributes> <Flags value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <ProductStrategy name="STRATEGY_ACCESSIBILITY">
+        <AttributesGroup streamType="AUDIO_STREAM_ACCESSIBILITY" volumeGroup="accessibility">
+            <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <ProductStrategy name="STRATEGY_SONIFICATION_RESPECTFUL">
+        <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="notification">
+            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
+            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <ProductStrategy name="STRATEGY_MEDIA">
+        <AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
+            <Attributes>
+                <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+                <Usage value="AUDIO_USAGE_ASSISTANT"/>
+            </Attributes>
+        </AttributesGroup>
+         <AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="music">
+            <Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
+            <Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
+            <Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
+            <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
+            <Attributes></Attributes>
+        </AttributesGroup>
+        <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
+            <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <ProductStrategy name="STRATEGY_DTMF">
+        <AttributesGroup streamType="AUDIO_STREAM_DTMF" volumeGroup="dtmf">
+            <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+    <!-- Used to identify the volume of audio streams exclusively transmitted through the  speaker
+         (TTS) of the device -->
+    <ProductStrategy name="STRATEGY_TRANSMITTED_THROUGH_SPEAKER">
+        <AttributesGroup streamType="AUDIO_STREAM_TTS" volumeGroup="tts">
+            <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
+        </AttributesGroup>
+    </ProductStrategy>
+
+</ProductStrategies>
+
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml
new file mode 100644
index 0000000..af517cf
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Volume section defines a volume curve for a given use case and device category.
+It contains a list of points of this curve expressing the attenuation in Millibels for a given
+volume index from 0 to 100.
+<volume deviceCategory=””>
+<point>0,-9600</point>
+<point>100,0</point>
+</volume>
+-->
+
+<volumeGroups>
+    <volumeGroup>
+        <name>voice_call</name>
+        <indexMin>1</indexMin>
+        <indexMax>7</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-2400</point>
+            <point>33,-1600</point>
+            <point>66,-800</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+            <point>0,-2700</point>
+            <point>33,-1800</point>
+            <point>66,-900</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>system</name>
+        <indexMin>0</indexMin>
+        <indexMax>7</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>1,-3000</point>
+            <point>33,-2600</point>
+            <point>66,-2200</point>
+            <point>100,-1800</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>1,-5100</point>
+            <point>57,-2800</point>
+            <point>71,-2500</point>
+            <point>85,-2300</point>
+            <point>100,-2100</point>
+        </volume>
+        <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>ring</name>
+        <indexMin>0</indexMin>
+        <indexMax>7</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>music</name>
+        <indexMin>0</indexMin>
+        <indexMax>25</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID"  ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>alarm</name>
+        <indexMin>1</indexMin>
+        <indexMax>7</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>notification</name>
+        <indexMin>0</indexMin>
+        <indexMax>7</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>bluetooth_sco</name>
+        <indexMin>0</indexMin>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>0,-2400</point>
+            <point>33,-1600</point>
+            <point>66,-800</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+            <point>0,-4200</point>
+            <point>33,-2800</point>
+            <point>66,-1400</point>
+            <point>100,0</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>enforced_audible</name>
+        <indexMin>0</indexMin>
+        <indexMax>7</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>1,-3000</point>
+            <point>33,-2600</point>
+            <point>66,-2200</point>
+            <point>100,-1800</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>1,-3400</point>
+            <point>71,-2400</point>
+            <point>100,-2000</point>
+        </volume>
+        <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>dtmf</name>
+        <indexMin>0</indexMin>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+            <point>1,-3000</point>
+            <point>33,-2600</point>
+            <point>66,-2200</point>
+            <point>100,-1800</point>
+        </volume>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+            <point>1,-4000</point>
+            <point>71,-2400</point>
+            <point>100,-1400</point>
+        </volume>
+        <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>tts</name>
+        <indexMin>0</indexMin>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="SILENT_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="SILENT_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="SILENT_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>accessibility</name>
+        <indexMin>1</indexMin>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+    <volumeGroup>
+        <name>assistant</name>
+        <indexMin>0</indexMin>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID"  ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+    </volumeGroup>
+
+</volumeGroups>
+
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index 67e99f2..3c64898 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -66,6 +66,11 @@
                         channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
                 </mixPort>
                 <mixPort name="hifi_input" role="sink" />
+                <mixPort name="multiple_channels_input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000"
+                             channelMasks="AUDIO_CHANNEL_IN_5POINT1"/>
+                </mixPort>
             </mixPorts>
             <devicePorts>
                 <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
@@ -114,6 +119,8 @@
                     sources="BUS Device In"/>
                 <route type="mix" sink="hifi_input"
                         sources="USB Device In" />
+                <route type="mix" sink="multiple_channels_input"
+                       sources="Built-In Mic" />
             </routes>
         </module>
 
diff --git a/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
new file mode 100644
index 0000000..efe1400
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+          http://www.apache.org/licenses/LICENSE-2.0
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <globalConfiguration speaker_drc_enabled="false" call_screen_mode_supported="true" />
+    <modules>
+        <!-- Primary Audio HAL -->
+        <module name="primary" halVersion="2.0">
+            <attachedDevices>
+                <item>Speaker</item>
+                <item>Speaker Safe</item>
+                <item>Earpiece</item>
+                <item>Built-In Mic</item>
+                <item>Built-In Back Mic</item>
+                <item>Telephony Tx</item>
+                <item>Voice Call And Telephony Rx</item>
+                <item>Echo Ref In</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY AUDIO_OUTPUT_FLAG_FAST"
+                         recommendedMuteDurationMs="40">
+                    <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="direct" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT"
+                         recommendedMuteDurationMs="40">
+                    <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+                             samplingRates="48000 96000 384000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="deep buffer" role="source" flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
+                    <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="compressed_offload" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD">
+                    <profile name="" format="AUDIO_FORMAT_MP3"
+                             samplingRates="8000 16000 24000 32000 44100 48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_AAC_LC"
+                             samplingRates="8000 16000 24000 32000 44100 48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_AAC_HE_V1"
+                             samplingRates="8000 16000 24000 32000 44100 48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_AAC_HE_V2"
+                             samplingRates="8000 16000 24000 32000 44100 48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_OPUS"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="haptic" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB" />
+                </mixPort>
+                <mixPort name="raw" role="source" flags="AUDIO_OUTPUT_FLAG_RAW AUDIO_OUTPUT_FLAG_FAST">
+                    <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+                    <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+                             samplingRates="48000 96000 384000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="immersive_out" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER">
+                    <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="incall playback" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_INCALL_MUSIC">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
+                </mixPort>
+                <mixPort name="voice call tx" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
+                </mixPort>
+                <mixPort name="voip_rx" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_VOIP_RX">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                           samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="primary input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_INDEX_MASK_3"/>
+                </mixPort>
+                <mixPort name="hotword input" role="sink" flags="AUDIO_INPUT_FLAG_HW_HOTWORD" maxActiveCount="0" >
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 96000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+                <mixPort name="incall capture" role="sink"  maxActiveCount="2" maxOpenCount="2">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </mixPort>
+                <mixPort name="voice call rx" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </mixPort>
+                <mixPort name="voip_tx" role="sink"
+                         flags="AUDIO_INPUT_FLAG_VOIP_TX">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </mixPort>
+                <mixPort name="fast input" role="sink" flags="AUDIO_INPUT_FLAG_RAW AUDIO_INPUT_FLAG_FAST">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+                <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ">
+                    <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+                <mixPort name="hifi_playback" role="source" />
+                <mixPort name="hifi_input" role="sink" />
+                <mixPort name="echo_ref_input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+                             samplingRates="48000 96000"
+                             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
+                <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
+                </devicePort>
+                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+                </devicePort>
+                <devicePort tagName="Speaker Safe" type="AUDIO_DEVICE_OUT_SPEAKER_SAFE" role="sink">
+                </devicePort>
+                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
+                </devicePort>
+                <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
+                </devicePort>
+                <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
+                </devicePort>
+                <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink">
+                </devicePort>
+                <devicePort tagName="USB Headset Out" type="AUDIO_DEVICE_OUT_USB_HEADSET" role="sink">
+                </devicePort>
+                <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_HDMI" role="sink">
+                </devicePort>
+                <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
+                </devicePort>
+                <!-- Input devices declaration, i.e. Source DEVICE PORT -->
+                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+                </devicePort>
+                <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
+                </devicePort>
+                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
+                </devicePort>
+                <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink"
+                            encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink"
+                            encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink"
+                            encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BT BLE Headset" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"
+                            encodedFormats="AUDIO_FORMAT_LC3">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BT BLE Speaker" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"
+                            encodedFormats="AUDIO_FORMAT_LC3">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BT BLE Broadcast" type="AUDIO_DEVICE_OUT_BLE_BROADCAST" role="sink"
+                            encodedFormats="AUDIO_FORMAT_LC3">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BLE Headset Mic" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source">
+                </devicePort>
+                <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source">
+                </devicePort>
+                <devicePort tagName="USB Headset In" type="AUDIO_DEVICE_IN_USB_HEADSET" role="source">
+                </devicePort>
+                <!-- AUDIO_DEVICE_IN_VOICE_CALL and AUDIO_DEVICE_IN_TELEPHONY_RX are in the same value -->
+                <devicePort tagName="Voice Call And Telephony Rx" type="AUDIO_DEVICE_IN_VOICE_CALL" role="source">
+                </devicePort>
+                <devicePort tagName="Echo Ref In" type="AUDIO_DEVICE_IN_ECHO_REFERENCE" role="source">
+                </devicePort>
+            </devicePorts>
+            <!-- route declaration, i.e. list all available sources for a given sink -->
+            <routes>
+                <route type="mix" sink="Speaker"
+                       sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+                <route type="mix" sink="Speaker Safe"
+                       sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+                <route type="mix" sink="Earpiece"
+                       sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+                <route type="mix" sink="BT A2DP Out"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+                <route type="mix" sink="BT A2DP Headphones"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+                <route type="mix" sink="BT A2DP Speaker"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+                <route type="mix" sink="BT BLE Headset"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+                <route type="mix" sink="BT BLE Speaker"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+                <route type="mix" sink="BT BLE Broadcast"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+                <route type="mix" sink="USB Device Out"
+                       sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,hifi_playback,compressed_offload,immersive_out"/>
+                <route type="mix" sink="USB Headset Out"
+                       sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,hifi_playback,compressed_offload,immersive_out"/>
+                <route type="mix" sink="HDMI Out"
+                       sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+                <route type="mix" sink="BT SCO"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+                <route type="mix" sink="BT SCO Headset"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+                <route type="mix" sink="BT SCO Car Kit"
+                       sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+                <route type="mix" sink="Telephony Tx" sources="incall playback,voice call tx" />
+                <route type="mix" sink="primary input"
+                       sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+                <route type="mix" sink="hotword input"
+                       sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+                <route type="mix" sink="incall capture" sources="Voice Call And Telephony Rx" />
+                <route type="mix" sink="voice call rx" sources="Voice Call And Telephony Rx" />
+                <route type="mix" sink="voip_tx"
+                       sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+                <route type="mix" sink="fast input"
+                       sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+                <route type="mix" sink="mmap_no_irq_in"
+                       sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+                <route type="mix" sink="hifi_input" sources="USB Device In,USB Headset In" />
+                <route type="mix" sink="echo_ref_input" sources="Echo Ref In"/>
+            </routes>
+        </module>
+        <!-- Usb Audio HAL -->
+        <module name="usbv2" halVersion="2.0">
+            <mixPorts>
+                <mixPort name="usb_accessory output" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <devicePort tagName="USB Host Out" type="AUDIO_DEVICE_OUT_USB_ACCESSORY" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="USB Host Out"
+                       sources="usb_accessory output"/>
+            </routes>
+        </module>
+    </modules>
+    <!-- End of Modules section -->
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/test_execution_tracer.cpp b/services/audiopolicy/tests/test_execution_tracer.cpp
new file mode 100644
index 0000000..09de4a1
--- /dev/null
+++ b/services/audiopolicy/tests/test_execution_tracer.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TestExecutionTracer"
+
+#include "test_execution_tracer.h"
+
+#include <android-base/logging.h>
+
+void TestExecutionTracer::OnTestStart(const ::testing::TestInfo& test_info) {
+    TraceTestState("Started", test_info);
+}
+
+void TestExecutionTracer::OnTestEnd(const ::testing::TestInfo& test_info) {
+    TraceTestState("Finished", test_info);
+}
+
+void TestExecutionTracer::OnTestPartResult(const ::testing::TestPartResult& result) {
+    if (result.failed()) {
+        LOG(ERROR) << result;
+    } else {
+        LOG(INFO) << result;
+    }
+}
+
+// static
+void TestExecutionTracer::TraceTestState(const std::string& state,
+                                         const ::testing::TestInfo& test_info) {
+    LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+}
diff --git a/services/audiopolicy/tests/test_execution_tracer.h b/services/audiopolicy/tests/test_execution_tracer.h
new file mode 100644
index 0000000..9031aaf
--- /dev/null
+++ b/services/audiopolicy/tests/test_execution_tracer.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gtest/gtest.h>
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+  public:
+    void OnTestStart(const ::testing::TestInfo& test_info) override;
+    void OnTestEnd(const ::testing::TestInfo& test_info) override;
+    void OnTestPartResult(const ::testing::TestPartResult& result) override;
+
+  private:
+    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info);
+};
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index a74b6d6..3f2a617 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -267,9 +267,21 @@
         "liblog",
         "libutils",
         "libxml2",
-        "camera_platform_flags_c_lib",
     ],
 
+    target: {
+        android: {
+            shared_libs: [
+                "camera_platform_flags_c_lib",
+            ],
+        },
+        host: {
+            shared_libs: [
+                "camera_platform_flags_c_lib_for_test",
+            ],
+        },
+    },
+
     include_dirs: [
         "frameworks/av/camera/include",
         "frameworks/av/camera/include/camera",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f94300e..fa5eb6f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -89,7 +89,6 @@
 #include "utils/Utils.h"
 
 namespace {
-    const char* kPermissionServiceName = "permission";
     const char* kActivityServiceName = "activity";
     const char* kSensorPrivacyServiceName = "sensor_privacy";
     const char* kAppopsServiceName = "appops";
@@ -828,10 +827,6 @@
         hardware::camera2::impl::CameraMetadataNative* request) {
     ATRACE_CALL();
 
-    if (!flags::feature_combination_query()) {
-        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
-                "Camera subsystem doesn't support this method!");
-    }
     if (!mInitialized) {
         ALOGE("%s: Camera subsystem is not available", __FUNCTION__);
         logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
@@ -891,10 +886,6 @@
         /*out*/ bool* supported) {
     ATRACE_CALL();
 
-    if (!flags::feature_combination_query()) {
-        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
-                "Camera subsystem doesn't support this method!");
-    }
     if (!mInitialized) {
         ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
         logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
@@ -924,8 +915,7 @@
                 cameraId.c_str());
     }
 
-    bool overrideForPerfClass = flags::calculate_perf_override_during_session_support() &&
-                                SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+    bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
                                         mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
 
     auto ret = isSessionConfigurationWithParametersSupportedUnsafe(cameraId,
@@ -1021,23 +1011,23 @@
 
     bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
             mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
-    if (flags::check_session_support_before_session_char()) {
-        bool sessionConfigSupported;
-        Status res = isSessionConfigurationWithParametersSupportedUnsafe(
-                cameraId, sessionConfiguration, overrideForPerfClass, &sessionConfigSupported);
-        if (!res.isOk()) {
-            // isSessionConfigurationWithParametersSupportedUnsafe should log what went wrong and
-            // report the correct Status to send to the client. Simply forward the error to
-            // the client.
-            outMetadata->clear();
-            return res;
-        }
-        if (!sessionConfigSupported) {
-            std::string msg = fmt::sprintf(
-                    "Session configuration not supported for camera device %s.", cameraId.c_str());
-            outMetadata->clear();
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
-        }
+
+    bool sessionConfigSupported;
+    Status res = isSessionConfigurationWithParametersSupportedUnsafe(
+            cameraId, sessionConfiguration, overrideForPerfClass, &sessionConfigSupported);
+    if (!res.isOk()) {
+        // isSessionConfigurationWithParametersSupportedUnsafe should log what went wrong and
+        // report the correct Status to send to the client. Simply forward the error to
+        // the client.
+        outMetadata->clear();
+        return res;
+    }
+
+    if (!sessionConfigSupported) {
+        std::string msg = fmt::sprintf("Session configuration not supported for camera device %s.",
+                                       cameraId.c_str());
+        outMetadata->clear();
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
     }
 
     status_t ret = mCameraProviderManager->getSessionCharacteristics(
@@ -1079,7 +1069,7 @@
             }
     }
 
-    Status res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
+    res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
     if (flags::analytics_24q3()) {
         mCameraServiceProxyWrapper->logSessionCharacteristicsQuery(cameraId,
                 getCallingUid(), sessionConfiguration, res);
@@ -1612,11 +1602,12 @@
     Status ret = Status::ok();
     sp<Client> tmp = nullptr;
 
-    logConnectionAttempt(getCallingPid(), kServiceName, cameraIdStr, API_1);
+    int callingPid = getCallingPid();
+    logConnectionAttempt(callingPid, kServiceName, cameraIdStr, API_1);
 
     if (!(ret = connectHelper<ICameraClient,Client>(
             sp<ICameraClient>{nullptr}, cameraIdStr, cameraId,
-            kServiceName, /*systemNativeClient*/ false, {}, uid, USE_CALLING_PID,
+            kServiceName, /*systemNativeClient*/ false, {}, uid, callingPid,
             API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
             /*targetSdkVersion*/ __ANDROID_API_FUTURE__,
             /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
@@ -1690,7 +1681,7 @@
 }
 
 Status CameraService::validateConnectLocked(const std::string& cameraId,
-        const std::string& clientName8, /*inout*/int& clientUid, /*inout*/int& clientPid) const {
+        const std::string& clientName8, int clientUid, int clientPid) const {
 
 #ifdef __BRILLO__
     UNUSED(clientName8);
@@ -1735,36 +1726,10 @@
 }
 
 Status CameraService::validateClientPermissionsLocked(const std::string& cameraId,
-        const std::string& clientName, int& clientUid, int& clientPid) const {
+        const std::string& clientName, int clientUid, int clientPid) const {
     int callingPid = getCallingPid();
     int callingUid = getCallingUid();
 
-    // Check if we can trust clientUid
-    if (clientUid == USE_CALLING_UID) {
-        clientUid = callingUid;
-    } else if (!isTrustedCallingUid(callingUid)) {
-        ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
-                "(don't trust clientUid %d)", callingPid, callingUid, clientUid);
-        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
-                "Untrusted caller (calling PID %d, UID %d) trying to "
-                "forward camera access to camera %s for client %s (PID %d, UID %d)",
-                callingPid, callingUid, cameraId.c_str(),
-                clientName.c_str(), clientPid, clientUid);
-    }
-
-    // Check if we can trust clientPid
-    if (clientPid == USE_CALLING_PID) {
-        clientPid = callingPid;
-    } else if (!isTrustedCallingUid(callingUid)) {
-        ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
-                "(don't trust clientPid %d)", callingPid, callingUid, clientPid);
-        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
-                "Untrusted caller (calling PID %d, UID %d) trying to "
-                "forward camera access to camera %s for client %s (PID %d, UID %d)",
-                callingPid, callingUid, cameraId.c_str(),
-                clientName.c_str(), clientPid, clientUid);
-    }
-
     if (shouldRejectSystemCameraConnection(cameraId)) {
         ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
                 cameraId.c_str());
@@ -2152,20 +2117,33 @@
 
     std::string clientPackageNameMaybe = clientAttribution.packageName.value_or("");
     bool isNonSystemNdk = clientPackageNameMaybe.size() == 0;
-    std::string clientPackageName = resolvePackageName(clientAttribution.uid,
-            clientPackageNameMaybe);
-    logConnectionAttempt(clientAttribution.pid, clientPackageName, cameraIdStr, API_1);
+
+    AttributionSourceState resolvedClientAttribution(clientAttribution);
+    ret = resolveAttributionSource(resolvedClientAttribution, __FUNCTION__, cameraIdStr);
+    if (!ret.isOk()) {
+        logRejected(cameraIdStr, getCallingPid(),
+                    clientAttribution.packageName.value_or("<unknown>"),
+                    toStdString(ret.toString8()));
+        return ret;
+    }
+
+    const int clientPid = resolvedClientAttribution.pid;
+    const int clientUid = resolvedClientAttribution.uid;
+    const std::string& clientPackageName = *resolvedClientAttribution.packageName;
+
+    logConnectionAttempt(clientPid, clientPackageName, cameraIdStr, API_1);
 
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, cameraIdStr, api1CameraId,
             clientPackageName, /*systemNativeClient*/ false, {},
-            clientAttribution.uid, clientAttribution.pid, API_1,
+            clientUid, clientPid, API_1,
             /*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion,
             rotationOverride, forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*out*/client);
 
     if (!ret.isOk()) {
-        logRejected(cameraIdStr, getCallingPid(), clientAttribution.packageName.value_or(""),
-                toStdString(ret.toString8()));
+        logRejected(cameraIdStr, getCallingPid(),
+                    clientAttribution.packageName.value_or("<unknown>"),
+                    toStdString(ret.toString8()));
         return ret;
     }
 
@@ -2271,22 +2249,32 @@
     std::string cameraId = cameraIdOptional.value();
 
     bool isNonSystemNdk = clientPackageNameMaybe.size() == 0;
-    std::string clientPackageName = resolvePackageName(clientAttribution.uid,
-            clientPackageNameMaybe);
-    logConnectionAttempt(clientAttribution.pid, clientPackageName, cameraId, API_2);
 
-    if (oomScoreOffset < 0) {
-        std::string msg =
-                fmt::sprintf("Cannot increase the priority of a client %s pid %d for "
-                        "camera id %s", clientPackageName.c_str(), callingPid,
-                        cameraId.c_str());
-        ALOGE("%s: %s", __FUNCTION__, msg.c_str());
-        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+    AttributionSourceState resolvedClientAttribution(clientAttribution);
+    if (!flags::use_context_attribution_source()) {
+        resolvedClientAttribution.pid = USE_CALLING_PID;
+    }
+    ret = resolveAttributionSource(resolvedClientAttribution, __FUNCTION__, cameraId);
+    if (!ret.isOk()) {
+        logRejected(cameraId, getCallingPid(), clientAttribution.packageName.value_or(""),
+                    toStdString(ret.toString8()));
+        return ret;
     }
 
-    userid_t clientUserId = multiuser_get_user_id(clientAttribution.uid);
-    if (clientAttribution.uid == USE_CALLING_UID) {
-        clientUserId = multiuser_get_user_id(callingUid);
+    const int clientPid = resolvedClientAttribution.pid;
+    const int clientUid = resolvedClientAttribution.uid;
+    const std::string& clientPackageName = *resolvedClientAttribution.packageName;
+    userid_t clientUserId = multiuser_get_user_id(resolvedClientAttribution.uid);
+
+    logConnectionAttempt(clientPid, clientPackageName, cameraId, API_2);
+
+    if (oomScoreOffset < 0) {
+        std::string msg = fmt::sprintf(
+                "Cannot increase the priority of a client %s pid %d for "
+                "camera id %s",
+                clientPackageName.c_str(), clientPid, cameraId.c_str());
+        ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.c_str());
     }
 
     // Automotive privileged client AID_AUTOMOTIVE_EVS using exterior system camera for use cases
@@ -2299,25 +2287,24 @@
     }
 
     // enforce system camera permissions
-    if (oomScoreOffset > 0
-            && !hasPermissionsForSystemCamera(cameraId, callingPid,
-                    callingUid)
-            && !isTrustedCallingUid(callingUid)) {
-        std::string msg = fmt::sprintf("Cannot change the priority of a client %s pid %d for "
-                        "camera id %s without SYSTEM_CAMERA permissions",
-                        clientPackageName.c_str(), callingPid, cameraId.c_str());
+    if (oomScoreOffset > 0 && !hasPermissionsForSystemCamera(cameraId, clientPid, callingUid) &&
+        !isTrustedCallingUid(callingUid)) {
+        std::string msg = fmt::sprintf(
+                "Cannot change the priority of a client %s pid %d for "
+                "camera id %s without SYSTEM_CAMERA permissions",
+                clientPackageName.c_str(), clientPid, cameraId.c_str());
         ALOGE("%s: %s", __FUNCTION__, msg.c_str());
         return STATUS_ERROR(ERROR_PERMISSION_DENIED, msg.c_str());
     }
 
-    ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb,
-            cameraId, /*api1CameraId*/-1, clientPackageName, systemNativeClient,
-            clientAttribution.attributionTag, clientAttribution.uid, USE_CALLING_PID, API_2,
+    ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks, CameraDeviceClient>(
+            cameraCb, cameraId, /*api1CameraId*/ -1, clientPackageName, systemNativeClient,
+            resolvedClientAttribution.attributionTag, clientUid, clientPid, API_2,
             /*shimUpdateOnly*/ false, oomScoreOffset, targetSdkVersion, rotationOverride,
-            /*forceSlowJpegMode*/false, unresolvedCameraId, isNonSystemNdk, /*out*/client);
+            /*forceSlowJpegMode*/ false, unresolvedCameraId, isNonSystemNdk, /*out*/ client);
 
     if (!ret.isOk()) {
-        logRejected(cameraId, callingPid, clientPackageName, toStdString(ret.toString8()));
+        logRejected(cameraId, clientPid, clientPackageName, toStdString(ret.toString8()));
         return ret;
     }
 
@@ -2377,74 +2364,13 @@
     return false;
 }
 
-std::string CameraService::getPackageNameFromUid(int clientUid) const {
-    std::string packageName("");
-
-    sp<IPermissionController> permCtrl;
-    if (flags::cache_permission_services()) {
-        permCtrl = getPermissionController();
-    } else {
-        sp<IServiceManager> sm = defaultServiceManager();
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-        // Using deprecated function to preserve functionality until the
-        // cache_permission_services flag is removed.
-        sp<IBinder> binder = sm->getService(toString16(kPermissionServiceName));
-#pragma clang diagnostic pop
-        if (binder == 0) {
-            ALOGE("Cannot get permission service");
-            permCtrl = nullptr;
-        } else {
-            permCtrl = interface_cast<IPermissionController>(binder);
-        }
-    }
-
-    if (permCtrl == nullptr) {
-        // Return empty package name and the further interaction
-        // with camera will likely fail
-        return packageName;
-    }
-
-    Vector<String16> packages;
-
-    permCtrl->getPackagesForUid(clientUid, packages);
-
-    if (packages.isEmpty()) {
-        ALOGE("No packages for calling UID %d", clientUid);
-        // Return empty package name and the further interaction
-        // with camera will likely fail
-        return packageName;
-    }
-
-    // Arbitrarily pick the first name in the list
-    packageName = toStdString(packages[0]);
-
-    return packageName;
-}
-
 void CameraService::logConnectionAttempt(int clientPid, const std::string& clientPackageName,
-        const std::string& cameraId, apiLevel effectiveApiLevel) const {
-    int packagePid = (clientPid == USE_CALLING_PID) ?
-        getCallingPid() : clientPid;
+                                         const std::string& cameraId,
+                                         apiLevel effectiveApiLevel) const {
     ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) and "
-            "Camera API version %d", packagePid, clientPackageName.c_str(), cameraId.c_str(),
-            static_cast<int>(effectiveApiLevel));
-}
-
-std::string CameraService::resolvePackageName(int clientUid,
-        const std::string& clientPackageNameMaybe) const {
-    if (clientPackageNameMaybe.size() <= 0) {
-        int packageUid = (clientUid == USE_CALLING_UID) ?
-                getCallingUid() : clientUid;
-        // NDK calls don't come with package names, but we need one for various cases.
-        // Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
-        // do exist. For all authentication cases, all packages under the same UID get the
-        // same permissions, so picking any associated package name is sufficient. For some
-        // other cases, this may give inaccurate names for clients in logs.
-        return getPackageNameFromUid(packageUid);
-    } else {
-        return clientPackageNameMaybe;
-    }
+          "Camera API version %d",
+          clientPid, clientPackageName.c_str(), cameraId.c_str(),
+          static_cast<int>(effectiveApiLevel));
 }
 
 template<class CALLBACK, class CLIENT>
@@ -2456,11 +2382,6 @@
         const std::string& originalCameraId, bool isNonSystemNdk, /*out*/sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
 
-    int packageUid = (clientUid == USE_CALLING_UID) ?
-            getCallingUid() : clientUid;
-    int packagePid = (clientPid == USE_CALLING_PID) ?
-            getCallingPid() : clientPid;
-
     nsecs_t openTimeNs = systemTime();
 
     sp<CLIENT> client = nullptr;
@@ -2680,7 +2601,7 @@
         if (flags::camera_privacy_allowlist()) {
             // Set camera muting behavior.
             isCameraPrivacyEnabled = this->isCameraPrivacyEnabled(
-                    toString16(client->getPackageName()), cameraId, packagePid, packageUid);
+                    toString16(client->getPackageName()), cameraId, clientPid, clientUid);
         } else {
             isCameraPrivacyEnabled =
                     mSensorPrivacyPolicy->isCameraPrivacyEnabled();
@@ -4330,14 +4251,9 @@
         // Notify app ops that the camera is not available
         mOpsCallback = new OpsCallback(this);
 
-        if (flags::watch_foreground_changes()) {
-            mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
-                toString16(mClientPackageName),
-                AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
-        } else {
-            mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
-                toString16(mClientPackageName), mOpsCallback);
-        }
+        mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
+            toString16(mClientPackageName),
+            AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
 
         // Just check for camera acccess here on open - delay startOp until
         // camera frames start streaming in startCameraStreamingOps
@@ -4520,19 +4436,10 @@
         // (WAR for b/175320666)the AppOpsManager could return MODE_IGNORED. Do not treat such
         // cases as error.
         if (!mUidIsTrusted) {
-            if (flags::watch_foreground_changes()) {
-                if (isUidVisible && isCameraPrivacyEnabled && supportsCameraMute()) {
-                    setCameraMute(true);
-                } else {
-                    block();
-                }
+            if (isUidVisible && isCameraPrivacyEnabled && supportsCameraMute()) {
+                setCameraMute(true);
             } else {
-                if (isUidActive && isCameraPrivacyEnabled && supportsCameraMute()) {
-                    setCameraMute(true);
-                } else if (!isUidActive
-                    || (isCameraPrivacyEnabled && !supportsCameraMute())) {
-                    block();
-                }
+                block();
             }
         }
     } else if (res == AppOpsManager::MODE_ALLOWED) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d5c57cb..5eb2536 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -33,7 +33,6 @@
 #include <binder/IServiceManager.h>
 #include <binder/IActivityManager.h>
 #include <binder/IAppOpsCallback.h>
-#include <binder/IPermissionController.h>
 #include <binder/IUidObserver.h>
 #include <hardware/camera.h>
 #include <sensorprivacy/SensorPrivacyManager.h>
@@ -686,25 +685,6 @@
         return activityManager;
     }
 
-    static const sp<IPermissionController>& getPermissionController() {
-        static const char* kPermissionControllerService = "permission";
-        static thread_local sp<IPermissionController> sPermissionController = nullptr;
-
-        if (sPermissionController == nullptr ||
-                !IInterface::asBinder(sPermissionController)->isBinderAlive()) {
-            sp<IServiceManager> sm = defaultServiceManager();
-            sp<IBinder> binder = sm->checkService(toString16(kPermissionControllerService));
-            if (binder == nullptr) {
-                ALOGE("%s: Could not get permission service", __FUNCTION__);
-                sPermissionController = nullptr;
-            } else {
-                sPermissionController = interface_cast<IPermissionController>(binder);
-            }
-        }
-
-        return sPermissionController;
-    }
-
     /**
      * Typesafe version of device status, containing both the HAL-layer and the service interface-
      * layer values.
@@ -950,12 +930,10 @@
     // If clientPid/clientUid are USE_CALLING_PID/USE_CALLING_UID, they will be overwritten with
     // the calling pid/uid.
     binder::Status validateConnectLocked(const std::string& cameraId, const std::string& clientName,
-            /*inout*/int& clientUid, /*inout*/int& clientPid) const;
+            int clientUid, int clientPid) const;
     binder::Status validateClientPermissionsLocked(const std::string& cameraId,
-            const std::string& clientName, /*inout*/int& clientUid, /*inout*/int& clientPid) const;
+            const std::string& clientName, int clientUid, int clientPid) const;
 
-    // If clientPackageNameMaybe is empty, attempts to resolve the package name.
-    std::string resolvePackageName(int clientUid, const std::string& clientPackageNameMaybe) const;
     void logConnectionAttempt(int clientPid, const std::string& clientPackageName,
         const std::string& cameraId, apiLevel effectiveApiLevel) const;
 
@@ -995,15 +973,6 @@
     // sorted in alpha-numeric order.
     void filterAPI1SystemCameraLocked(const std::vector<std::string> &normalDeviceIds);
 
-    // In some cases the calling code has no access to the package it runs under.
-    // For example, NDK camera API.
-    // In this case we will get the packages for the calling UID and pick the first one
-    // for attributing the app op. This will work correctly for runtime permissions
-    // as for legacy apps we will toggle the app op for all packages in the UID.
-    // The caveat is that the operation may be attributed to the wrong package and
-    // stats based on app ops may be slightly off.
-    std::string getPackageNameFromUid(int clientUid) const;
-
     // Single implementation shared between the various connect calls
     template<class CALLBACK, class CLIENT>
     binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const std::string& cameraId,
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.cpp b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
index 1c1bd24..ad1a84f 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.cpp
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
@@ -17,11 +17,14 @@
 #define LOG_TAG "CameraServiceWatchdog"
 
 #include "CameraServiceWatchdog.h"
+#include "com_android_internal_camera_flags.h"
 #include "android/set_abort_message.h"
 #include "utils/CameraServiceProxyWrapper.h"
 
 namespace android {
 
+namespace flags = com::android::internal::camera::flags;
+
 bool CameraServiceWatchdog::threadLoop()
 {
     {
@@ -51,6 +54,12 @@
                         true /*deviceError*/);
                 // We use abort here so we can get a tombstone for better
                 // debugging.
+                if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+                    for (pid_t pid : mProviderPids) {
+                        kill(pid, SIGABRT);
+                    }
+                }
+
                 abort();
             }
         }
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.h b/services/camera/libcameraservice/CameraServiceWatchdog.h
index 165dece..691a274 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.h
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.h
@@ -30,6 +30,7 @@
  */
 #pragma once
 #include <chrono>
+#include <set>
 #include <thread>
 #include <time.h>
 #include <utils/Thread.h>
@@ -57,16 +58,17 @@
 };
 
 public:
-    explicit CameraServiceWatchdog(const std::string &cameraId,
+
+    explicit CameraServiceWatchdog(const std::set<pid_t> &pids, const std::string &cameraId,
             std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
-                    mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
+                    mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
                     mCycleLengthMs(kCycleLengthMs), mEnabled(true),
                     mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
 
-    explicit CameraServiceWatchdog (const std::string &cameraId, size_t maxCycles,
-            uint32_t cycleLengthMs, bool enabled,
+    explicit CameraServiceWatchdog (const std::set<pid_t> &pids, const std::string &cameraId,
+            size_t maxCycles, uint32_t cycleLengthMs, bool enabled,
             std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
-                    mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
+                    mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
                     mCycleLengthMs(cycleLengthMs), mEnabled(enabled),
                     mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
 
@@ -90,7 +92,8 @@
             // Lock for mEnabled
             mEnabledLock.lock();
             sp<CameraServiceWatchdog> tempWatchdog = new CameraServiceWatchdog(
-                    mCameraId, cycles, cycleLength, mEnabled, mCameraServiceProxyWrapper);
+                    mProviderPids, mCameraId, cycles, cycleLength, mEnabled,
+                    mCameraServiceProxyWrapper);
             mEnabledLock.unlock();
 
             status_t status = tempWatchdog->run("CameraServiceWatchdog");
@@ -150,6 +153,7 @@
     Mutex           mWatchdogLock;      // Lock for condition variable
     Mutex           mEnabledLock;       // Lock for enabled status
     Condition       mWatchdogCondition; // Condition variable for stop/start
+    std::set<pid_t> mProviderPids;      // Process ID set of camera providers
     std::string     mCameraId;          // Camera Id the watchdog belongs to
     bool            mPause;             // True if tid map is empty
     uint32_t        mMaxCycles;         // Max cycles
diff --git a/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h b/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h
index 86af36c..61b150d 100644
--- a/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h
@@ -30,13 +30,4 @@
 std::vector<camera_metadata_tag> extension_metadata_keys{
             ANDROID_EXTENSION_STRENGTH,
             ANDROID_EXTENSION_CURRENT_TYPE,
-            ANDROID_EFV_PADDING_ZOOM_FACTOR,
-            ANDROID_EFV_AUTO_ZOOM,
-            ANDROID_EFV_MAX_PADDING_ZOOM_FACTOR,
-            ANDROID_EFV_STABILIZATION_MODE,
-            ANDROID_EFV_TRANSLATE_VIEWPORT,
-            ANDROID_EFV_ROTATE_VIEWPORT,
-            ANDROID_EFV_PADDING_REGION,
-            ANDROID_EFV_AUTO_ZOOM_PADDING_REGION,
-            ANDROID_EFV_TARGET_COORDINATES,
 };
diff --git a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
index 0e1db5c..b07d8d5 100644
--- a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
@@ -87,7 +87,6 @@
         } },
       {35, {
           ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
-          ANDROID_EFV_PADDING_ZOOM_FACTOR_RANGE,
           ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
           ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
           ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
@@ -121,15 +120,6 @@
         }  },
       {35, {
           ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
-          ANDROID_EFV_AUTO_ZOOM,
-          ANDROID_EFV_AUTO_ZOOM_PADDING_REGION,
-          ANDROID_EFV_MAX_PADDING_ZOOM_FACTOR,
-          ANDROID_EFV_PADDING_REGION,
-          ANDROID_EFV_PADDING_ZOOM_FACTOR,
-          ANDROID_EFV_ROTATE_VIEWPORT,
-          ANDROID_EFV_STABILIZATION_MODE,
-          ANDROID_EFV_TARGET_COORDINATES,
-          ANDROID_EFV_TRANSLATE_VIEWPORT,
           ANDROID_FLASH_STRENGTH_LEVEL,
           ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION,
           ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES,
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index d4953c1..0f1d0ff 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -142,8 +142,12 @@
         mHasFocuser(false),
         mInputBuffer(nullptr),
         mProducer(nullptr),
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+        mInputSurface(nullptr),
+#else
         mInputProducer(nullptr),
         mInputProducerSlot(-1),
+#endif
         mBuffersToDetach(0) {
     // Initialize buffer queue and frame list based on pipeline max depth.
     size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
@@ -331,10 +335,17 @@
         mInputStreamId = NO_STREAM;
     }
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    if (nullptr != mInputSurface.get()) {
+        // The surface destructor calls disconnect
+        mInputSurface.clear();
+    }
+#else
     if (nullptr != mInputProducer.get()) {
         mInputProducer->disconnect(NATIVE_WINDOW_API_CPU);
         mInputProducer.clear();
     }
+#endif
 
     return OK;
 }
@@ -393,11 +404,19 @@
 
 void ZslProcessor::doNotifyInputReleasedLocked() {
     assert(nullptr != mInputBuffer.get());
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    assert(nullptr != mInputSurface.get());
+#else
     assert(nullptr != mInputProducer.get());
+#endif
 
     sp<GraphicBuffer> gb;
     sp<Fence> fence;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    auto rc = mInputSurface->detachNextBuffer(&gb, &fence);
+#else
     auto rc = mInputProducer->detachNextBuffer(&gb, &fence);
+#endif
     if (NO_ERROR != rc) {
         ALOGE("%s: Failed to detach buffer from input producer: %d",
             __FUNCTION__, rc);
@@ -456,9 +475,15 @@
             __FUNCTION__, (unsigned int) metadataIdx);
     }
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    if (nullptr == mInputSurface.get()) {
+        res = client->getCameraDevice()->getInputSurface(
+            &mInputSurface);
+#else
     if (nullptr == mInputProducer.get()) {
         res = client->getCameraDevice()->getInputBufferProducer(
             &mInputProducer);
+#endif
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to retrieve input producer: "
                     "%s (%d)", __FUNCTION__, client->getCameraId(),
@@ -466,9 +491,14 @@
             return res;
         }
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+        res = mInputSurface->connect(NATIVE_WINDOW_API_CPU, new InputProducerListener(this),
+            false);
+#else
         IGraphicBufferProducer::QueueBufferOutput output;
         res = mInputProducer->connect(new InputProducerListener(this),
             NATIVE_WINDOW_API_CPU, false, &output);
+#endif
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to connect to input producer: "
                     "%s (%d)", __FUNCTION__, client->getCameraId(),
@@ -629,19 +659,32 @@
     }
 
     BufferItem &item = mInputBuffer->getBufferItem();
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    auto rc = mInputSurface->attachBuffer(item.mGraphicBuffer->getNativeBuffer());
+#else
     auto rc = mInputProducer->attachBuffer(&mInputProducerSlot,
         item.mGraphicBuffer);
+#endif
     if (OK != rc) {
         ALOGE("%s: Failed to attach input ZSL buffer to producer: %d",
             __FUNCTION__, rc);
         return rc;
     }
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    mInputSurface->setBuffersTimestamp(item.mTimestamp);
+    mInputSurface->setBuffersDataSpace(static_cast<ui::Dataspace>(item.mDataSpace));
+    mInputSurface->setCrop(&item.mCrop);
+    mInputSurface->setScalingMode(item.mScalingMode);
+    mInputSurface->setBuffersTransform(item.mTransform);
+    rc = mInputSurface->queueBuffer(item.mGraphicBuffer, item.mFence);
+#else
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input(item.mTimestamp,
             item.mIsAutoTimestamp, item.mDataSpace, item.mCrop,
             item.mScalingMode, item.mTransform, item.mFence);
     rc = mInputProducer->queueBuffer(mInputProducerSlot, input, &output);
+#endif
     if (OK != rc) {
         ALOGE("%s: Failed to queue ZSL buffer to producer: %d",
             __FUNCTION__, rc);
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 3186233..a98160a 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -24,8 +24,9 @@
 #include <utils/Condition.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
-#include <gui/RingBufferConsumer.h>
+#include <gui/Flags.h>
 #include <gui/IProducerListener.h>
+#include <gui/RingBufferConsumer.h>
 #include <camera/CameraMetadata.h>
 
 #include "api1/client2/FrameProcessor.h"
@@ -83,6 +84,20 @@
 
   private:
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    class InputProducerListener : public SurfaceListener {
+    public:
+        InputProducerListener(wp<ZslProcessor> parent) : mParent(parent) {}
+        virtual void onBufferReleased() override;
+        virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& /* buffers */)
+            override {}
+        virtual void onBufferDetached(int /* slot */) override {}
+        virtual bool needsReleaseNotify() override { return true; }
+
+    private:
+        wp<ZslProcessor> mParent;
+    };
+#else
     class InputProducerListener : public BnProducerListener {
     public:
         InputProducerListener(wp<ZslProcessor> parent) : mParent(parent) {}
@@ -92,6 +107,7 @@
     private:
         wp<ZslProcessor> mParent;
     };
+#endif
 
     static const nsecs_t kWaitDuration = 10000000; // 10 ms
     nsecs_t mLatestClearedBufferTimestamp;
@@ -139,8 +155,13 @@
     // Input buffer queued into HAL
     sp<RingBufferConsumer::PinnedBufferItem> mInputBuffer;
     sp<RingBufferConsumer>                   mProducer;
+
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    sp<Surface>                              mInputSurface;
+#else
     sp<IGraphicBufferProducer>               mInputProducer;
     int                                      mInputProducerSlot;
+#endif
 
     Condition                                mBuffersToDetachSignal;
     int                                      mBuffersToDetach;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index fcba9bc..f469aad 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -546,14 +546,14 @@
             mRunningSessionStats.mVideoStabilizationMode = entry.data.u8[0];
         }
 
-        if (!mRunningSessionStats.mUsedUltraWide && flags::log_ultrawide_usage()) {
+        if (!mRunningSessionStats.mUsedUltraWide) {
             entry = physicalSettingsList.begin()->metadata.find(
                     ANDROID_CONTROL_ZOOM_RATIO);
             if (entry.count == 1 && entry.data.f[0] < 1.0f ) {
                 mRunningSessionStats.mUsedUltraWide = true;
             }
         }
-        if (!mRunningSessionStats.mUsedSettingsOverrideZoom && flags::log_zoom_override_usage()) {
+        if (!mRunningSessionStats.mUsedSettingsOverrideZoom) {
             entry = physicalSettingsList.begin()->metadata.find(
                     ANDROID_CONTROL_SETTINGS_OVERRIDE);
             if (entry.count == 1 && entry.data.i32[0] ==
@@ -1240,6 +1240,18 @@
     if (!mDevice.get()) {
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    sp<Surface> surface;
+    status_t err = mDevice->getInputSurface(&surface);
+    if (err != OK) {
+        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+                "Camera %s: Error getting input Surface: %s (%d)",
+                mCameraIdStr.c_str(), strerror(-err), err);
+    } else {
+        inputSurface->name = toString16("CameraInput");
+        inputSurface->graphicBufferProducer = surface->getIGraphicBufferProducer();
+    }
+#else
     sp<IGraphicBufferProducer> producer;
     status_t err = mDevice->getInputBufferProducer(&producer);
     if (err != OK) {
@@ -1250,6 +1262,7 @@
         inputSurface->name = toString16("CameraInput");
         inputSurface->graphicBufferProducer = producer;
     }
+#endif
     return res;
 }
 
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 352c6f8..18069fe 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -358,7 +358,7 @@
         bool landscapeSensor =  (orientation == 0 || orientation == 180);
         if (((TClientBase::mRotationOverride ==
                 ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT) && landscapeSensor) ||
-                        ((wm_flags::camera_compat_for_freeform() &&
+                        ((wm_flags::enable_camera_compat_for_desktop_windowing() &&
                                 TClientBase::mRotationOverride ==
                                 ICameraService::ROTATION_OVERRIDE_ROTATION_ONLY)
                                 && !landscapeSensor)) {
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index aceb5c0..9c8f5ad 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -25,6 +25,7 @@
 #include <utils/KeyedVector.h>
 #include <utils/Timers.h>
 #include <utils/List.h>
+#include <gui/Flags.h>
 
 #include "hardware/camera2.h"
 #include "camera/CameraMetadata.h"
@@ -305,9 +306,14 @@
      */
     virtual void getOfflineStreamIds(std::vector<int> *offlineStreamIds) = 0;
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    // get the surface of the input stream
+    virtual status_t getInputSurface(sp<Surface> *surface) = 0;
+#else
     // get the buffer producer of the input stream
     virtual status_t getInputBufferProducer(
             sp<IGraphicBufferProducer> *producer) = 0;
+#endif
 
     /**
      * Create a metadata buffer with fields that the HAL device believes are
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 2440c37..a03d199 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -34,6 +34,7 @@
 #include <inttypes.h>
 #include <android_companion_virtualdevice_flags.h>
 #include <android_companion_virtualdevice_build_flags.h>
+#include <android/binder_libbinder.h>
 #include <android/binder_manager.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
@@ -148,11 +149,7 @@
     using aidl::android::hardware::camera::provider::ICameraProvider;
 
     AIBinder* binder = nullptr;
-    if (flags::lazy_aidl_wait_for_service()) {
-        binder = AServiceManager_waitForService(serviceName.c_str());
-    } else {
-        binder = AServiceManager_checkService(serviceName.c_str());
-    }
+    binder = AServiceManager_waitForService(serviceName.c_str());
 
     if (binder == nullptr) {
         ALOGE("%s: AIDL Camera provider HAL '%s' is not actually available, despite waiting "
@@ -470,10 +467,6 @@
 status_t CameraProviderManager::getSessionCharacteristics(
         const std::string& id, const SessionConfiguration& configuration, bool overrideForPerfClass,
         int rotationOverride, CameraMetadata* sessionCharacteristics /*out*/) const {
-    if (!flags::feature_combination_query()) {
-        return INVALID_OPERATION;
-    }
-
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
     auto deviceInfo = findDeviceInfoLocked(id);
     if (deviceInfo == nullptr) {
@@ -2119,14 +2112,8 @@
         const std::string& providerName, const sp<ProviderInfo>& providerInfo) {
     using aidl::android::hardware::camera::provider::ICameraProvider;
 
-    std::shared_ptr<ICameraProvider> interface;
-    if (flags::delay_lazy_hal_instantiation()) {
-        // Only get remote instance if already running. Lazy Providers will be
-        // woken up later.
-        interface = mAidlServiceProxy->tryGetService(providerName);
-    } else {
-        interface = mAidlServiceProxy->getService(providerName);
-    }
+    // Only get remote instance if already running. Lazy Providers will be woken up later.
+    std::shared_ptr<ICameraProvider> interface = mAidlServiceProxy->tryGetService(providerName);
 
     if (interface == nullptr) {
         ALOGW("%s: AIDL Camera provider HAL '%s' is not actually available", __FUNCTION__,
@@ -2135,7 +2122,19 @@
     }
 
     AidlProviderInfo *aidlProviderInfo = static_cast<AidlProviderInfo *>(providerInfo.get());
-    return aidlProviderInfo->initializeAidlProvider(interface, mDeviceState);
+    status_t res = aidlProviderInfo->initializeAidlProvider(interface, mDeviceState);
+
+    if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+        pid_t pid = 0;
+
+        if (AIBinder_toPlatformBinder(interface->asBinder().get())->getDebugPid(&pid) == OK
+                && res == OK) {
+            std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+            mProviderPidMap[providerInfo->mProviderInstance] = pid;
+        }
+    }
+
+    return res;
 }
 
 status_t CameraProviderManager::tryToInitializeHidlProviderLocked(
@@ -2152,7 +2151,23 @@
     }
 
     HidlProviderInfo *hidlProviderInfo = static_cast<HidlProviderInfo *>(providerInfo.get());
-    return hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
+    status_t res = hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
+
+    if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+        pid_t pid = 0;
+
+        auto ret = interface->getDebugInfo([&pid](
+                const ::android::hidl::base::V1_0::DebugInfo& info) {
+            pid = info.pid;
+        });
+
+        if (ret.isOk() && res == OK) {
+            std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+            mProviderPidMap[providerInfo->mProviderInstance] = pid;
+        }
+    }
+
+    return res;
 }
 
 status_t CameraProviderManager::addAidlProviderLocked(const std::string& newProvider) {
@@ -2163,14 +2178,11 @@
     bool preexisting =
             (mAidlProviderWithBinders.find(newProvider) != mAidlProviderWithBinders.end());
     using aidl::android::hardware::camera::provider::ICameraProvider;
-    std::string providerNameUsed  =
-            newProvider.substr(std::string(ICameraProvider::descriptor).size() + 1);
-    if (flags::lazy_aidl_wait_for_service()) {
-        // 'newProvider' has the fully qualified name of the provider service in case of AIDL.
-        // ProviderInfo::mProviderName also has the fully qualified name - so we just compare them
-        // here.
-        providerNameUsed = newProvider;
-    }
+
+    // 'newProvider' has the fully qualified name of the provider service in case of AIDL.
+    // ProviderInfo::mProviderName also has the fully qualified name - so we just compare them
+    // here.
+    std::string providerNameUsed = newProvider;
 
     for (const auto& providerInfo : mProviders) {
         if (providerInfo->mProviderName == providerNameUsed) {
@@ -2264,20 +2276,23 @@
         ALOGW("%s: Camera provider HAL with name '%s' is not registered", __FUNCTION__,
                 provider.c_str());
     } else {
+        if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+            {
+                std::lock_guard<std::mutex> pidLock(mProviderPidMapLock);
+                mProviderPidMap.erase(provider);
+            }
+        }
+
         // Check if there are any newer camera instances from the same provider and try to
         // initialize.
         for (const auto& providerInfo : mProviders) {
             if (providerInfo->mProviderName == removedProviderName) {
                 IPCTransport providerTransport = providerInfo->getIPCTransport();
-                std::string removedAidlProviderName = getFullAidlProviderName(removedProviderName);
-                if (flags::lazy_aidl_wait_for_service()) {
-                    removedAidlProviderName = removedProviderName;
-                }
                 switch(providerTransport) {
                     case IPCTransport::HIDL:
                         return tryToInitializeHidlProviderLocked(removedProviderName, providerInfo);
                     case IPCTransport::AIDL:
-                        return tryToInitializeAidlProviderLocked(removedAidlProviderName,
+                        return tryToInitializeAidlProviderLocked(removedProviderName,
                                 providerInfo);
                     default:
                         ALOGE("%s Unsupported Transport %d", __FUNCTION__, eToI(providerTransport));
@@ -2443,7 +2458,7 @@
 
 bool CameraProviderManager::ProviderInfo::isExternalLazyHAL() const {
     std::string providerName = mProviderName;
-    if (flags::lazy_aidl_wait_for_service() && getIPCTransport() == IPCTransport::AIDL) {
+    if (getIPCTransport() == IPCTransport::AIDL) {
         using aidl::android::hardware::camera::provider::ICameraProvider;
         providerName =
                 mProviderName.substr(std::string(ICameraProvider::descriptor).size() + 1);
@@ -2451,6 +2466,20 @@
     return kEnableLazyHal && (providerName == kExternalProviderName);
 }
 
+std::set<pid_t> CameraProviderManager::getProviderPids() {
+    std::set<pid_t> pids;
+
+    if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+        std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+
+        std::transform(mProviderPidMap.begin(), mProviderPidMap.end(),
+                    std::inserter(pids, pids.begin()),
+                    [](std::pair<const std::string, pid_t>& entry) { return entry.second; });
+    }
+
+    return pids;
+}
+
 status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
     dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
             mProviderInstance.c_str(),
@@ -2771,7 +2800,7 @@
         hardware::CameraInfo *info) const {
     if (info == nullptr) return BAD_VALUE;
 
-    bool freeform_compat_enabled = wm_flags::camera_compat_for_freeform();
+    bool freeform_compat_enabled = wm_flags::enable_camera_compat_for_desktop_windowing();
     if (!freeform_compat_enabled &&
             rotationOverride > hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT) {
         ALOGW("Camera compat freeform flag disabled but rotation override is %d", rotationOverride);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 4a64b44..b686a58 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -431,6 +431,11 @@
     // LocalRegistrationCallback::onServiceRegistration
     virtual void onServiceRegistration(const String16& name, const sp<IBinder> &binder) override;
 
+    /*
+     * Return list of provider pid
+     */
+    std::set<pid_t> getProviderPids();
+
     /**
      * Dump out information about available providers and devices
      */
@@ -914,6 +919,9 @@
     // Provider names of AIDL providers with retrieved binders.
     std::set<std::string> mAidlProviderWithBinders;
 
+    std::mutex mProviderPidMapLock;
+    std::map<std::string, pid_t> mProviderPidMap;
+
     static const char* deviceStatusToString(
         const hardware::camera::common::V1_0::CameraDeviceStatus&);
     static const char* torchStatusToString(
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index e76b750..4bfe11d 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -109,11 +109,8 @@
         std::shared_ptr<ICameraProvider>& interface, int64_t currentDeviceState) {
 
     using aidl::android::hardware::camera::provider::ICameraProvider;
-    std::string parsedProviderName = mProviderName;
-    if (flags::lazy_aidl_wait_for_service()) {
-        parsedProviderName =
+    std::string parsedProviderName =
                 mProviderName.substr(std::string(ICameraProvider::descriptor).size() + 1);
-    }
 
     status_t res = parseProviderName(parsedProviderName, &mType, &mId);
     if (res != OK) {
@@ -529,13 +526,11 @@
                 __FUNCTION__, strerror(-res), res);
         return;
     }
-    if (flags::camera_manual_flash_strength_control()) {
-        res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
-        if (OK != res) {
-            ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-            return;
-        }
+    res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
+    if (OK != res) {
+        ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return;
     }
 
     auto stat = addDynamicDepthTags();
@@ -622,12 +617,10 @@
         mHasFlashUnit = false;
     }
 
-    if (flags::feature_combination_query()) {
-        res = addSessionConfigQueryVersionTag();
-        if (OK != res) {
-            ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-        }
+    res = addSessionConfigQueryVersionTag();
+    if (OK != res) {
+        ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
     }
 
     camera_metadata_entry entry =
@@ -684,13 +677,11 @@
                         __FUNCTION__, strerror(-res), res);
             }
 
-            if (flags::camera_manual_flash_strength_control()) {
-                res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
-                if (OK != res) {
-                    ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
-                            __FUNCTION__, strerror(-res), res);
-                    return;
-                }
+            res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
+            if (OK != res) {
+                ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                        __FUNCTION__, strerror(-res), res);
+                return;
             }
         }
     }
@@ -844,11 +835,7 @@
                     mVersion.get_minor());
             return INVALID_OPERATION;
         }
-        if (flags::feature_combination_query()) {
-            ret = interface->isStreamCombinationWithSettingsSupported(streamConfiguration, status);
-        } else {
-            return INVALID_OPERATION;
-        }
+        ret = interface->isStreamCombinationWithSettingsSupported(streamConfiguration, status);
     } else {
         ret = interface->isStreamCombinationSupported(streamConfiguration, status);
     }
@@ -887,10 +874,6 @@
         return res;
     }
 
-    if (!flags::feature_combination_query()) {
-        return INVALID_OPERATION;
-    }
-
     auto err = interface->constructDefaultRequestSettings(id, &request);
     if (!err.isOk()) {
         ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 40800d9..6cedb04 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -616,13 +616,12 @@
                 __FUNCTION__, strerror(-res), res);
         return;
     }
-    if (flags::camera_manual_flash_strength_control()) {
-        res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
-        if (OK != res) {
-            ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-            return;
-        }
+
+    res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
+    if (OK != res) {
+        ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return;
     }
 
     auto stat = addDynamicDepthTags();
@@ -693,12 +692,10 @@
         mHasFlashUnit = false;
     }
 
-    if (flags::feature_combination_query()) {
-        res = addSessionConfigQueryVersionTag();
-        if (OK != res) {
-            ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-        }
+    res = addSessionConfigQueryVersionTag();
+    if (OK != res) {
+        ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
     }
 
     camera_metadata_entry entry =
@@ -782,13 +779,11 @@
                         __FUNCTION__, strerror(-res), res);
             }
 
-            if (flags::camera_manual_flash_strength_control()) {
-                res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
-                if (OK != res) {
-                    ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
-                            __FUNCTION__, strerror(-res), res);
-                    return;
-                }
+            res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
+            if (OK != res) {
+                ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                        __FUNCTION__, strerror(-res), res);
+                return;
             }
         }
     }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 11891e9..5721745 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -133,7 +133,7 @@
     return mId;
 }
 
-status_t Camera3Device::initializeCommonLocked() {
+status_t Camera3Device::initializeCommonLocked(sp<CameraProviderManager> manager) {
 
     /** Start up status tracker thread */
     mStatusTracker = new StatusTracker(this);
@@ -251,7 +251,8 @@
     mInjectionMethods = createCamera3DeviceInjectionMethods(this);
 
     /** Start watchdog thread */
-    mCameraServiceWatchdog = new CameraServiceWatchdog(mId, mCameraServiceProxyWrapper);
+    mCameraServiceWatchdog = new CameraServiceWatchdog(
+            manager->getProviderPids(), mId, mCameraServiceProxyWrapper);
     res = mCameraServiceWatchdog->run("CameraServiceWatchdog");
     if (res != OK) {
         SET_ERR_L("Unable to start camera service watchdog thread: %s (%d)",
@@ -1440,6 +1441,21 @@
     return configureStreamsLocked(operatingMode, filteredParams);
 }
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3Device::getInputSurface(sp<Surface> *surface) {
+    ATRACE_CALL();
+    Mutex::Autolock il(mInterfaceLock);
+    Mutex::Autolock l(mLock);
+
+    if (surface == NULL) {
+        return BAD_VALUE;
+    } else if (mInputStream == NULL) {
+        return INVALID_OPERATION;
+    }
+
+    return mInputStream->getInputSurface(surface);
+}
+#else
 status_t Camera3Device::getInputBufferProducer(
         sp<IGraphicBufferProducer> *producer) {
     ATRACE_CALL();
@@ -1454,6 +1470,7 @@
 
     return mInputStream->getInputBufferProducer(producer);
 }
+#endif
 
 status_t Camera3Device::createDefaultRequest(camera_request_template_t templateId,
         CameraMetadata *request) {
@@ -1631,7 +1648,7 @@
     bool signalPipelineDrain = false;
     if (!active &&
             (mUseHalBufManager ||
-                    (flags::session_hal_buf_manager() && mHalBufManagedStreamIds.size() != 0))) {
+                    (mHalBufManagedStreamIds.size() != 0))) {
         auto streamIds = mOutputStreams.getStreamIds();
         if (mStatus == STATUS_ACTIVE) {
             mRequestThread->signalPipelineDrain(streamIds);
@@ -1835,10 +1852,7 @@
         mSessionStatsBuilder.stopCounter();
     }
 
-    // Calculate expected duration for flush with additional buffer time in ms for watchdog
-    uint64_t maxExpectedDuration = ns2ms(getExpectedInFlightDuration() + kBaseGetBufferWait);
-    status_t res = mCameraServiceWatchdog->WATCH_CUSTOM_TIMER(mRequestThread->flush(),
-            maxExpectedDuration / kCycleLengthMs, kCycleLengthMs);
+    status_t res = mCameraServiceWatchdog->WATCH(mRequestThread->flush());
 
     return res;
 }
@@ -2584,25 +2598,23 @@
     // It is possible that use hal buffer manager behavior was changed by the
     // configureStreams call.
     mUseHalBufManager = config.use_hal_buf_manager;
-    if (flags::session_hal_buf_manager()) {
-        bool prevSessionHalBufManager = (mHalBufManagedStreamIds.size() != 0);
-        // It is possible that configureStreams() changed config.hal_buffer_managed_streams
-        mHalBufManagedStreamIds = config.hal_buffer_managed_streams;
+    bool prevSessionHalBufManager = (mHalBufManagedStreamIds.size() != 0);
+    // It is possible that configureStreams() changed config.hal_buffer_managed_streams
+    mHalBufManagedStreamIds = config.hal_buffer_managed_streams;
 
-        bool thisSessionHalBufManager = mHalBufManagedStreamIds.size() != 0;
+    bool thisSessionHalBufManager = mHalBufManagedStreamIds.size() != 0;
 
-        if (prevSessionHalBufManager && !thisSessionHalBufManager) {
-            mRequestBufferSM.deInit();
-        } else if (!prevSessionHalBufManager && thisSessionHalBufManager) {
-            res = mRequestBufferSM.initialize(mStatusTracker);
-            if (res != OK) {
-                SET_ERR_L("%s: Camera %s: RequestBuffer State machine couldn't be initialized!",
-                          __FUNCTION__, mId.c_str());
-                return res;
-            }
+    if (prevSessionHalBufManager && !thisSessionHalBufManager) {
+        mRequestBufferSM.deInit();
+    } else if (!prevSessionHalBufManager && thisSessionHalBufManager) {
+        res = mRequestBufferSM.initialize(mStatusTracker);
+        if (res != OK) {
+            SET_ERR_L("%s: Camera %s: RequestBuffer State machine couldn't be initialized!",
+                        __FUNCTION__, mId.c_str());
+            return res;
         }
-        mRequestThread->setHalBufferManagedStreams(mHalBufManagedStreamIds);
     }
+    mRequestThread->setHalBufferManagedStreams(mHalBufManagedStreamIds);
 
     // Finish all stream configuration immediately.
     // TODO: Try to relax this later back to lazy completion, which should be
@@ -3007,8 +3019,7 @@
 }
 
 bool Camera3Device::HalInterface::isHalBufferManagedStream(int32_t streamId) const {
-    return (mUseHalBufManager || (flags::session_hal_buf_manager() &&
-                                  contains(mHalBufManagedStreamIds, streamId)));
+    return (mUseHalBufManager || contains(mHalBufManagedStreamIds, streamId));
 }
 
 status_t Camera3Device::HalInterface::popInflightBuffer(
@@ -4170,8 +4181,7 @@
             }
         }
         bool passSurfaceMap =
-                mUseHalBufManager ||
-                        (flags::session_hal_buf_manager() && containsHalBufferManagedStream);
+                mUseHalBufManager || containsHalBufferManagedStream;
         auto expectedDurationInfo = calculateExpectedDurationRange(settings);
         res = parent->registerInFlight(halRequest->frame_number,
                 totalNumBuffers, captureRequest->mResultExtras,
@@ -4287,7 +4297,7 @@
 
 void Camera3Device::RequestThread::signalPipelineDrain(const std::vector<int>& streamIds) {
     if (!mUseHalBufManager &&
-            (flags::session_hal_buf_manager() && mHalBufManagedStreamIds.size() == 0)) {
+            (mHalBufManagedStreamIds.size() == 0)) {
         ALOGE("%s called for camera device not supporting HAL buffer management", __FUNCTION__);
         return;
     }
@@ -4445,8 +4455,7 @@
             Camera3Stream *stream = Camera3Stream::cast((*outputBuffers)[i].stream);
             int32_t streamId = stream->getId();
             bool skipBufferForStream =
-                    mUseHalBufManager || (flags::session_hal_buf_manager() &&
-                            contains(mHalBufManagedStreamIds, streamId));
+                    mUseHalBufManager || (contains(mHalBufManagedStreamIds, streamId));
             if (skipBufferForStream) {
                 // No output buffer can be returned when using HAL buffer manager for its stream
                 continue;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index e5ccbae..3c45c1a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -31,6 +31,7 @@
 #include <utils/Timers.h>
 
 #include <camera/CaptureResult.h>
+#include <gui/Flags.h>
 
 #include "CameraServiceWatchdog.h"
 #include <aidl/android/hardware/camera/device/CameraBlob.h>
@@ -197,8 +198,12 @@
     status_t configureStreams(const CameraMetadata& sessionParams,
             int operatingMode =
             camera_stream_configuration_mode_t::CAMERA_STREAM_CONFIGURATION_NORMAL_MODE) override;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    status_t getInputSurface(sp<Surface> *surface) override;
+#else
     status_t getInputBufferProducer(
             sp<IGraphicBufferProducer> *producer) override;
+#endif
 
     void getOfflineStreamIds(std::vector<int> *offlineStreamIds) override;
 
@@ -726,7 +731,7 @@
      *
      * Must be called with mLock and mInterfaceLock held.
      */
-    status_t initializeCommonLocked();
+    status_t initializeCommonLocked(sp<CameraProviderManager> manager);
 
     /**
      * Update capture request list so that each batch size honors the batch_size_max report from
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index f9b6037..999f563 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -182,6 +182,21 @@
                                  /*output*/false, /*transform*/ -1);
 }
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3InputStream::getInputSurfaceLocked(sp<Surface> *surface) {
+    ATRACE_CALL();
+
+    if (surface == NULL) {
+        return BAD_VALUE;
+    } else if (mSurface == NULL) {
+        ALOGE("%s: No input stream is configured", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    *surface = mSurface;
+    return OK;
+}
+#else
 status_t Camera3InputStream::getInputBufferProducerLocked(
             sp<IGraphicBufferProducer> *producer) {
     ATRACE_CALL();
@@ -196,6 +211,7 @@
     *producer = mProducer;
     return OK;
 }
+#endif
 
 status_t Camera3InputStream::disconnectLocked() {
 
@@ -284,7 +300,12 @@
         mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
         mConsumer->setMaxAcquiredBufferCount(mTotalBufferCount);
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+        mSurface = mConsumer->getSurface();
+#else
         mProducer = mConsumer->getSurface()->getIGraphicBufferProducer();
+#endif // WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+
 #else
         mConsumer = new BufferItemConsumer(consumer, mUsage,
                                            mTotalBufferCount);
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index a99c364..b1603e5 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -18,6 +18,7 @@
 #define ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H
 
 #include <utils/RefBase.h>
+#include <gui/Flags.h>
 #include <gui/Surface.h>
 #include <gui/BufferItemConsumer.h>
 
@@ -50,7 +51,11 @@
   private:
 
     sp<BufferItemConsumer> mConsumer;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    sp<Surface> mSurface;
+#else
     sp<IGraphicBufferProducer> mProducer;
+#endif
     Vector<BufferItem> mBuffersInFlight;
 
     static const std::string FAKE_ID;
@@ -75,8 +80,12 @@
     virtual status_t getInputBufferLocked(camera_stream_buffer *buffer, Size *size);
     virtual status_t returnInputBufferLocked(
             const camera_stream_buffer &buffer);
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    virtual status_t getInputSurfaceLocked(sp<Surface> *surface);
+#else
     virtual status_t getInputBufferProducerLocked(
             sp<IGraphicBufferProducer> *producer);
+#endif
     virtual status_t disconnectLocked();
 
     virtual status_t configureQueueLocked();
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 04867b9..83c8a38 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -687,11 +687,7 @@
         }
     }
 
-    if (flags::surface_ipc()) {
-        res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
-    } else {
-        res = native_window_set_buffer_count(mConsumer.get(), mTotalBufferCount);
-    }
+    res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
     if (res != OK) {
         ALOGE("%s: Unable to set buffer count for stream %d",
                 __FUNCTION__, mId);
@@ -1035,7 +1031,7 @@
 status_t Camera3OutputStream::getEndpointUsageForSurface(uint64_t *usage,
         const sp<Surface>& surface) {
     bool internalConsumer = (mConsumer.get() != nullptr) && (mConsumer == surface);
-    if (mConsumerUsageCachedValue.has_value() && flags::surface_ipc() && internalConsumer) {
+    if (mConsumerUsageCachedValue.has_value() && internalConsumer) {
         *usage = mConsumerUsageCachedValue.value();
         return OK;
     }
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 31707ec..62226e1 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -894,8 +894,7 @@
 
         if (outputBuffers[i].buffer == nullptr) {
             if (!useHalBufManager &&
-                    !(flags::session_hal_buf_manager() &&
-                            contains(halBufferManagedStreams, streamId))) {
+                    !contains(halBufferManagedStreams, streamId)) {
                 // With HAL buffer management API, HAL sometimes will have to return buffers that
                 // has not got a output buffer handle filled yet. This is though illegal if HAL
                 // buffer management API is not being used.
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
index aca7a67..2d75d03 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
@@ -212,8 +212,7 @@
         bool noBufferReturned = false;
         buffer_handle_t *buffer = nullptr;
         if (states.useHalBufManager ||
-                (flags::session_hal_buf_manager() &&
-                        contains(states.halBufManagedStreamIds, bSrc.streamId))) {
+                contains(states.halBufManagedStreamIds, bSrc.streamId)) {
             // This is suspicious most of the time but can be correct during flush where HAL
             // has to return capture result before a buffer is requested
             if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
@@ -303,8 +302,7 @@
 
     for (const auto& buf : buffers) {
         if (!states.useHalBufManager &&
-            !(flags::session_hal_buf_manager() &&
-             contains(states.halBufManagedStreamIds, buf.streamId))) {
+            !contains(states.halBufManagedStreamIds, buf.streamId)) {
             ALOGE("%s: Camera %s does not support HAL buffer management for stream id %d",
                   __FUNCTION__, states.cameraId.c_str(), buf.streamId);
             return;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 4934203..ae76e60 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -29,6 +29,9 @@
 #include "ui/GraphicBufferMapper.h"
 
 #include <cutils/properties.h>
+#include <com_android_internal_camera_flags.h>
+
+namespace flags = com::android::internal::camera::flags;
 
 namespace android {
 
@@ -388,6 +391,10 @@
             mOldDataSpace == camera_stream::data_space &&
             mOldFormat == camera_stream::format) {
         mState = STATE_CONFIGURED;
+        if (flags::enable_stream_reconfiguration_for_unchanged_streams()
+                && streamReconfigured != nullptr) {
+            *streamReconfigured = true;
+        }
         return OK;
     }
 
@@ -864,12 +871,21 @@
     return res;
 }
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3Stream::getInputSurface(sp<Surface> *surface) {
+    ATRACE_CALL();
+    Mutex::Autolock l(mLock);
+
+    return getInputSurfaceLocked(surface);
+}
+#else
 status_t Camera3Stream::getInputBufferProducer(sp<IGraphicBufferProducer> *producer) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
     return getInputBufferProducerLocked(producer);
 }
+#endif
 
 void Camera3Stream::fireBufferRequestForFrameNumber(uint64_t frameNumber,
         const CameraMetadata& settings) {
@@ -983,10 +999,17 @@
     ALOGE("%s: This type of stream does not support input", __FUNCTION__);
     return INVALID_OPERATION;
 }
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3Stream::getInputSurfaceLocked(sp<Surface>*) {
+    ALOGE("%s: This type of stream does not support input", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+#else
 status_t Camera3Stream::getInputBufferProducerLocked(sp<IGraphicBufferProducer>*) {
     ALOGE("%s: This type of stream does not support input", __FUNCTION__);
     return INVALID_OPERATION;
 }
+#endif
 
 void Camera3Stream::addBufferListener(
         wp<Camera3StreamBufferListener> listener) {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index ccd1044..1519ada 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SERVERS_CAMERA3_STREAM_H
 #define ANDROID_SERVERS_CAMERA3_STREAM_H
 
+#include <gui/Flags.h>
 #include <gui/Surface.h>
 #include <utils/RefBase.h>
 #include <utils/String16.h>
@@ -382,9 +383,13 @@
      */
     status_t         returnInputBuffer(const camera_stream_buffer &buffer);
 
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    status_t         getInputSurface(sp<Surface> *producer);
+#else
     // get the buffer producer of the input buffer queue.
     // only apply to input streams.
     status_t         getInputBufferProducer(sp<IGraphicBufferProducer> *producer);
+#endif
 
     /**
      * Whether any of the stream's buffers are currently in use by the HAL,
@@ -534,8 +539,12 @@
     virtual status_t returnInputBufferLocked(
             const camera_stream_buffer &buffer);
     virtual bool     hasOutstandingBuffersLocked() const = 0;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+    virtual status_t getInputSurfaceLocked(sp<Surface> *surface);
+#else
     // Get the buffer producer of the input buffer queue. Only apply to input streams.
     virtual status_t getInputBufferProducerLocked(sp<IGraphicBufferProducer> *producer);
+#endif
 
     // Can return -ENOTCONN when we are already disconnected (not an error)
     virtual status_t disconnectLocked() = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 4df8193..0786622 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SERVERS_CAMERA3_STREAM_INTERFACE_H
 #define ANDROID_SERVERS_CAMERA3_STREAM_INTERFACE_H
 
+#include <gui/Flags.h>
 #include <utils/RefBase.h>
 
 #include <camera/camera2/OutputConfiguration.h>
@@ -435,12 +436,14 @@
      */
     virtual status_t returnInputBuffer(const camera_stream_buffer &buffer) = 0;
 
+#if !WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
     /**
      * Get the buffer producer of the input buffer queue.
      *
      * This method only applies to input streams.
      */
     virtual status_t getInputBufferProducer(sp<IGraphicBufferProducer> *producer) = 0;
+#endif
 
     /**
      * Whether any of the stream's buffers are currently in use by the HAL,
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 77c037a..7090545 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -14,32 +14,39 @@
  * limitations under the License.
  */
 
-#include <inttypes.h>
-
 #define LOG_TAG "Camera3StreamSplitter"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
+#include <binder/ProcessState.h>
 #include <camera/StringUtils.h>
 #include <com_android_graphics_libgui_flags.h>
 #include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
 #include <gui/BufferQueue.h>
 #include <gui/IGraphicBufferConsumer.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
-
+#include <system/window.h>
 #include <ui/GraphicBuffer.h>
-
-#include <binder/ProcessState.h>
-
 #include <utils/Trace.h>
 
 #include <cutils/atomic.h>
+#include <inttypes.h>
+#include <algorithm>
+#include <cstdint>
+#include <memory>
 
 #include "Camera3Stream.h"
+#include "Flags.h"
 
 #include "Camera3StreamSplitter.h"
 
+// We're relying on a large number of yet-to-be-fully-launched flag dependencies
+// here. So instead of flagging each one, we flag the entire implementation to
+// improve legibility.
+#if USE_NEW_STREAM_SPLITTER
+
 namespace android {
 
 status_t Camera3StreamSplitter::connect(const std::unordered_map<size_t, sp<Surface>> &surfaces,
@@ -55,7 +62,7 @@
     Mutex::Autolock lock(mMutex);
     status_t res = OK;
 
-    if (mOutputs.size() > 0 || mConsumer != nullptr) {
+    if (mOutputSurfaces.size() > 0 || mBufferItemConsumer != nullptr) {
         SP_LOGE("%s: already connected", __FUNCTION__);
         return BAD_VALUE;
     }
@@ -82,43 +89,43 @@
         }
     }
 
-#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-    // Create BufferQueue for input
-    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
-#endif  // !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-
     // Allocate 1 extra buffer to handle the case where all buffers are detached
     // from input, and attached to the outputs. In this case, the input queue's
     // dequeueBuffer can still allocate 1 extra buffer before being blocked by
     // the output's attachBuffer().
     mMaxConsumerBuffers++;
+
 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-    mBufferItemConsumer = new BufferItemConsumer(consumerUsage, mMaxConsumerBuffers);
+    mBufferItemConsumer = sp<BufferItemConsumer>::make(consumerUsage, mMaxConsumerBuffers);
+    mSurface = mBufferItemConsumer->getSurface();
 #else
-    mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage, mMaxConsumerBuffers);
+    // Create BufferQueue for input
+    sp<IGraphicBufferProducer> bqProducer;
+    sp<IGraphicBufferConsumer> bqConsumer;
+    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+
+    mBufferItemConsumer = new BufferItemConsumer(bqConsumer, consumerUsage, mMaxConsumerBuffers);
+    mSurface = new Surface(bqProducer);
 #endif  // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+
     if (mBufferItemConsumer == nullptr) {
         return NO_MEMORY;
     }
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-    mProducer = mBufferItemConsumer->getSurface()->getIGraphicBufferProducer();
-    mConsumer = mBufferItemConsumer->getIGraphicBufferConsumer();
-#endif  //  COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-    mConsumer->setConsumerName(toString8(mConsumerName));
+    mBufferItemConsumer->setName(toString8(mConsumerName));
 
-    *consumer = new Surface(mProducer);
+    *consumer = mSurface;
     if (*consumer == nullptr) {
         return NO_MEMORY;
     }
 
-    res = mProducer->setAsyncMode(true);
+    res = mSurface->setAsyncMode(true);
     if (res != OK) {
         SP_LOGE("%s: Failed to enable input queue async mode: %s(%d)", __FUNCTION__,
                 strerror(-res), res);
         return res;
     }
 
-    res = mConsumer->consumerConnect(this, /* controlledByApp */ false);
+    mBufferItemConsumer->setFrameAvailableListener(this);
 
     mWidth = width;
     mHeight = height;
@@ -139,25 +146,19 @@
     ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
 
-    for (auto& notifier : mNotifiers) {
-        sp<IGraphicBufferProducer> producer = notifier.first;
-        sp<OutputListener> listener = notifier.second;
-        IInterface::asBinder(producer)->unlinkToDeath(listener);
-    }
     mNotifiers.clear();
 
-    for (auto& output : mOutputs) {
+    for (auto& output : mOutputSurfaces) {
         if (output.second != nullptr) {
             output.second->disconnect(NATIVE_WINDOW_API_CAMERA);
         }
     }
-    mOutputs.clear();
     mOutputSurfaces.clear();
-    mOutputSlots.clear();
+    mHeldBuffers.clear();
     mConsumerBufferCount.clear();
 
-    if (mConsumer.get() != nullptr) {
-        mConsumer->consumerDisconnect();
+    if (mBufferItemConsumer != nullptr) {
+        mBufferItemConsumer->abandon();
     }
 
     if (mBuffers.size() > 0) {
@@ -189,7 +190,7 @@
     }
 
     if (mMaxConsumerBuffers > mAcquiredInputBuffers) {
-        res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+        res = mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
     }
 
     return res;
@@ -207,7 +208,7 @@
         return BAD_VALUE;
     }
 
-    if (mOutputs[surfaceId] != nullptr) {
+    if (mOutputSurfaces[surfaceId] != nullptr) {
         SP_LOGE("%s: surfaceId: %u already taken!", __FUNCTION__, (unsigned) surfaceId);
         return BAD_VALUE;
     }
@@ -226,11 +227,9 @@
         return res;
     }
 
-    sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
     // Connect to the buffer producer
-    sp<OutputListener> listener(new OutputListener(this, gbp));
-    IInterface::asBinder(gbp)->linkToDeath(listener);
-    res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener);
+    sp<OutputListener> listener = sp<OutputListener>::make(this, outputQueue);
+    res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener, /* reportBufferRemoval */ false);
     if (res != NO_ERROR) {
         SP_LOGE("addOutput: failed to connect (%d)", res);
         return res;
@@ -272,22 +271,21 @@
         outputQueue->setDequeueTimeout(timeout);
     }
 
-    res = gbp->allowAllocation(false);
+    res = outputQueue->allowAllocation(false);
     if (res != OK) {
         SP_LOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
         return res;
     }
 
     // Add new entry into mOutputs
-    mOutputs[surfaceId] = gbp;
     mOutputSurfaces[surfaceId] = outputQueue;
     mConsumerBufferCount[surfaceId] = maxConsumerBuffers;
     if (mConsumerBufferCount[surfaceId] > mMaxHalBuffers) {
         SP_LOGW("%s: Consumer buffer count %zu larger than max. Hal buffers: %zu", __FUNCTION__,
                 mConsumerBufferCount[surfaceId], mMaxHalBuffers);
     }
-    mNotifiers[gbp] = listener;
-    mOutputSlots[gbp] = std::make_unique<OutputSlots>(totalBufferCount);
+    mNotifiers[outputQueue] = listener;
+    mHeldBuffers[outputQueue] = std::make_unique<HeldBuffers>(totalBufferCount);
 
     mMaxConsumerBuffers += maxConsumerBuffers;
     return NO_ERROR;
@@ -304,7 +302,7 @@
     }
 
     if (mAcquiredInputBuffers < mMaxConsumerBuffers) {
-        res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+        res = mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
         if (res != OK) {
             SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
             return res;
@@ -315,70 +313,54 @@
 }
 
 status_t Camera3StreamSplitter::removeOutputLocked(size_t surfaceId) {
-    if (mOutputs[surfaceId] == nullptr) {
+    if (mOutputSurfaces[surfaceId] == nullptr) {
         SP_LOGE("%s: output surface is not present!", __FUNCTION__);
         return BAD_VALUE;
     }
 
-    sp<IGraphicBufferProducer> gbp = mOutputs[surfaceId];
+    sp<Surface> surface = mOutputSurfaces[surfaceId];
     //Search and decrement the ref. count of any buffers that are
     //still attached to the removed surface.
     std::vector<uint64_t> pendingBufferIds;
-    auto& outputSlots = *mOutputSlots[gbp];
-    for (size_t i = 0; i < outputSlots.size(); i++) {
-        if (outputSlots[i] != nullptr) {
-            pendingBufferIds.push_back(outputSlots[i]->getId());
-            auto rc = gbp->detachBuffer(i);
-            if (rc != NO_ERROR) {
-                //Buffers that fail to detach here will be scheduled for detach in the
-                //input buffer queue and the rest of the registered outputs instead.
-                //This will help ensure that camera stops accessing buffers that still
-                //can get referenced by the disconnected output.
-                mDetachedBuffers.emplace(outputSlots[i]->getId());
-            }
+
+    // TODO: can we simplify this to just use the tracker?
+    for (const auto& buffer : (*mHeldBuffers[surface])) {
+        pendingBufferIds.push_back(buffer->getId());
+        auto rc = surface->detachBuffer(buffer);
+        if (rc != NO_ERROR) {
+            // Buffers that fail to detach here will be scheduled for detach in the
+            // input buffer queue and the rest of the registered outputs instead.
+            // This will help ensure that camera stops accessing buffers that still
+            // can get referenced by the disconnected output.
+            mDetachedBuffers.emplace(buffer->getId());
         }
     }
-    mOutputs[surfaceId] = nullptr;
     mOutputSurfaces[surfaceId] = nullptr;
-    mOutputSlots[gbp] = nullptr;
+    mHeldBuffers[surface] = nullptr;
     for (const auto &id : pendingBufferIds) {
         decrementBufRefCountLocked(id, surfaceId);
     }
 
-    auto res = IInterface::asBinder(gbp)->unlinkToDeath(mNotifiers[gbp]);
-    if (res != OK) {
-        SP_LOGE("%s: Failed to unlink producer death listener: %d ", __FUNCTION__, res);
-        return res;
-    }
-
-    res = gbp->disconnect(NATIVE_WINDOW_API_CAMERA);
+    status_t res = surface->disconnect(NATIVE_WINDOW_API_CAMERA);
     if (res != OK) {
         SP_LOGE("%s: Unable disconnect from producer interface: %d ", __FUNCTION__, res);
         return res;
     }
 
-    mNotifiers[gbp] = nullptr;
+    mNotifiers[surface] = nullptr;
     mMaxConsumerBuffers -= mConsumerBufferCount[surfaceId];
     mConsumerBufferCount[surfaceId] = 0;
 
     return res;
 }
 
-status_t Camera3StreamSplitter::outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+status_t Camera3StreamSplitter::outputBufferLocked(const sp<Surface>& output,
         const BufferItem& bufferItem, size_t surfaceId) {
     ATRACE_CALL();
     status_t res;
-    IGraphicBufferProducer::QueueBufferInput queueInput(
-            bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
-            bufferItem.mDataSpace, bufferItem.mCrop,
-            static_cast<int32_t>(bufferItem.mScalingMode),
-            bufferItem.mTransform, bufferItem.mFence);
-
-    IGraphicBufferProducer::QueueBufferOutput queueOutput;
 
     uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
     const BufferTracker& tracker = *(mBuffers[bufferId]);
-    int slot = getSlotForOutputLocked(output, tracker.getBuffer());
 
     if (mOutputSurfaces[surfaceId] != nullptr) {
         sp<ANativeWindow> anw = mOutputSurfaces[surfaceId];
@@ -388,19 +370,26 @@
         SP_LOGE("%s: Invalid surface id: %zu!", __FUNCTION__, surfaceId);
     }
 
+    output->setBuffersTimestamp(bufferItem.mTimestamp);
+    output->setBuffersDataSpace(static_cast<ui::Dataspace>(bufferItem.mDataSpace));
+    output->setCrop(&bufferItem.mCrop);
+    output->setScalingMode(bufferItem.mScalingMode);
+    output->setBuffersTransform(bufferItem.mTransform);
+
     // In case the output BufferQueue has its own lock, if we hold splitter lock while calling
     // queueBuffer (which will try to acquire the output lock), the output could be holding its
     // own lock calling releaseBuffer (which  will try to acquire the splitter lock), running into
     // circular lock situation.
     mMutex.unlock();
-    res = output->queueBuffer(slot, queueInput, &queueOutput);
+    SurfaceQueueBufferOutput queueBufferOutput;
+    res = output->queueBuffer(bufferItem.mGraphicBuffer, bufferItem.mFence, &queueBufferOutput);
     mMutex.lock();
 
-    SP_LOGV("%s: Queuing buffer to buffer queue %p slot %d returns %d",
-            __FUNCTION__, output.get(), slot, res);
-    //During buffer queue 'mMutex' is not held which makes the removal of
-    //"output" possible. Check whether this is the case and return.
-    if (mOutputSlots[output] == nullptr) {
+    SP_LOGV("%s: Queuing buffer to buffer queue %p bufferId %" PRIu64 " returns %d", __FUNCTION__,
+            output.get(), bufferId, res);
+    // During buffer queue 'mMutex' is not held which makes the removal of
+    // "output" possible. Check whether this is the case and return.
+    if (mOutputSurfaces[surfaceId] == nullptr) {
         return res;
     }
     if (res != OK) {
@@ -418,7 +407,7 @@
     // If the queued buffer replaces a pending buffer in the async
     // queue, no onBufferReleased is called by the buffer queue.
     // Proactively trigger the callback to avoid buffer loss.
-    if (queueOutput.bufferReplaced) {
+    if (queueBufferOutput.bufferReplaced) {
         onBufferReplacedLocked(output, surfaceId);
     }
 
@@ -456,52 +445,32 @@
     auto tracker = std::make_unique<BufferTracker>(gb, surface_ids);
 
     for (auto& surface_id : surface_ids) {
-        sp<IGraphicBufferProducer>& gbp = mOutputs[surface_id];
-        if (gbp.get() == nullptr) {
+        sp<Surface>& surface = mOutputSurfaces[surface_id];
+        if (surface.get() == nullptr) {
             //Output surface got likely removed by client.
             continue;
         }
-        int slot = getSlotForOutputLocked(gbp, gb);
-        if (slot != BufferItem::INVALID_BUFFER_SLOT) {
-            //Buffer is already attached to this output surface.
-            continue;
-        }
+
         //Temporarly Unlock the mutex when trying to attachBuffer to the output
         //queue, because attachBuffer could block in case of a slow consumer. If
         //we block while holding the lock, onFrameAvailable and onBufferReleased
         //will block as well because they need to acquire the same lock.
         mMutex.unlock();
-        res = gbp->attachBuffer(&slot, gb);
+        res = surface->attachBuffer(anb);
         mMutex.lock();
         if (res != OK) {
-            SP_LOGE("%s: Cannot attachBuffer from GraphicBufferProducer %p: %s (%d)",
-                    __FUNCTION__, gbp.get(), strerror(-res), res);
+            SP_LOGE("%s: Cannot attachBuffer from GraphicBufferProducer %p: %s (%d)", __FUNCTION__,
+                    surface.get(), strerror(-res), res);
             // TODO: might need to detach/cleanup the already attached buffers before return?
             return res;
         }
-        if ((slot < 0) || (slot > BufferQueue::NUM_BUFFER_SLOTS)) {
-            SP_LOGE("%s: Slot received %d either bigger than expected maximum %d or negative!",
-                    __FUNCTION__, slot, BufferQueue::NUM_BUFFER_SLOTS);
-            return BAD_VALUE;
-        }
         //During buffer attach 'mMutex' is not held which makes the removal of
         //"gbp" possible. Check whether this is the case and continue.
-        if (mOutputSlots[gbp] == nullptr) {
+        if (mHeldBuffers[surface] == nullptr) {
             continue;
         }
-        auto& outputSlots = *mOutputSlots[gbp];
-        if (static_cast<size_t> (slot + 1) > outputSlots.size()) {
-            outputSlots.resize(slot + 1);
-        }
-        if (outputSlots[slot] != nullptr) {
-            // If the buffer is attached to a slot which already contains a buffer,
-            // the previous buffer will be removed from the output queue. Decrement
-            // the reference count accordingly.
-            decrementBufRefCountLocked(outputSlots[slot]->getId(), surface_id);
-        }
-        SP_LOGV("%s: Attached buffer %p to slot %d on output %p.",__FUNCTION__, gb.get(),
-                slot, gbp.get());
-        outputSlots[slot] = gb;
+        mHeldBuffers[surface]->insert(gb);
+        SP_LOGV("%s: Attached buffer %p on output %p.", __FUNCTION__, gb.get(), surface.get());
     }
 
     mBuffers[bufferId] = std::move(tracker);
@@ -515,25 +484,14 @@
 
     // Acquire and detach the buffer from the input
     BufferItem bufferItem;
-    status_t res = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
+    status_t res = mBufferItemConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
     if (res != NO_ERROR) {
         SP_LOGE("%s: Acquiring buffer from input failed (%d)", __FUNCTION__, res);
         mOnFrameAvailableRes.store(res);
         return;
     }
 
-    uint64_t bufferId;
-    if (bufferItem.mGraphicBuffer != nullptr) {
-        mInputSlots[bufferItem.mSlot] = bufferItem;
-    } else if (bufferItem.mAcquireCalled) {
-        bufferItem.mGraphicBuffer = mInputSlots[bufferItem.mSlot].mGraphicBuffer;
-        mInputSlots[bufferItem.mSlot].mFrameNumber = bufferItem.mFrameNumber;
-    } else {
-        SP_LOGE("%s: Invalid input graphic buffer!", __FUNCTION__);
-        mOnFrameAvailableRes.store(BAD_VALUE);
-        return;
-    }
-    bufferId = bufferItem.mGraphicBuffer->getId();
+    uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
 
     if (mBuffers.find(bufferId) == mBuffers.end()) {
         SP_LOGE("%s: Acquired buffer doesn't exist in attached buffer map",
@@ -556,13 +514,12 @@
     SP_LOGV("%s: BufferTracker for buffer %" PRId64 ", number of requests %zu",
            __FUNCTION__, bufferItem.mGraphicBuffer->getId(), tracker.requestedSurfaces().size());
     for (const auto id : tracker.requestedSurfaces()) {
-
-        if (mOutputs[id] == nullptr) {
+        if (mOutputSurfaces[id] == nullptr) {
             //Output surface got likely removed by client.
             continue;
         }
 
-        res = outputBufferLocked(mOutputs[id], bufferItem, id);
+        res = outputBufferLocked(mOutputSurfaces[id], bufferItem, id);
         if (res != OK) {
             SP_LOGE("%s: outputBufferLocked failed %d", __FUNCTION__, res);
             mOnFrameAvailableRes.store(res);
@@ -601,26 +558,11 @@
     mBuffers.erase(id);
 
     uint64_t bufferId = tracker_ptr->getBuffer()->getId();
-    int consumerSlot = -1;
-    uint64_t frameNumber;
-    auto inputSlot = mInputSlots.begin();
-    for (; inputSlot != mInputSlots.end(); inputSlot++) {
-        if (inputSlot->second.mGraphicBuffer->getId() == bufferId) {
-            consumerSlot = inputSlot->second.mSlot;
-            frameNumber = inputSlot->second.mFrameNumber;
-            break;
-        }
-    }
-    if (consumerSlot == -1) {
-        SP_LOGE("%s: Buffer missing inside input slots!", __FUNCTION__);
-        return;
-    }
 
     auto detachBuffer = mDetachedBuffers.find(bufferId);
     bool detach = (detachBuffer != mDetachedBuffers.end());
     if (detach) {
         mDetachedBuffers.erase(detachBuffer);
-        mInputSlots.erase(inputSlot);
     }
     // Temporarily unlock mutex to avoid circular lock:
     // 1. This function holds splitter lock, calls releaseBuffer which triggers
@@ -629,15 +571,14 @@
     // 2. Camera3SharedOutputStream::getBufferLocked calls
     // attachBufferToOutputs, which holds the stream lock, and waits for the
     // splitter lock.
-    sp<IGraphicBufferConsumer> consumer(mConsumer);
     mMutex.unlock();
     int res = NO_ERROR;
-    if (consumer != nullptr) {
+    if (mBufferItemConsumer != nullptr) {
         if (detach) {
-            res = consumer->detachBuffer(consumerSlot);
+            res = mBufferItemConsumer->detachBuffer(tracker_ptr->getBuffer());
         } else {
-            res = consumer->releaseBuffer(consumerSlot, frameNumber,
-                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence());
+            res = mBufferItemConsumer->releaseBuffer(tracker_ptr->getBuffer(),
+                                                     tracker_ptr->getMergedFence());
         }
     } else {
         SP_LOGE("%s: consumer has become null!", __FUNCTION__);
@@ -659,23 +600,25 @@
     }
 }
 
-void Camera3StreamSplitter::onBufferReleasedByOutput(
-        const sp<IGraphicBufferProducer>& from) {
+void Camera3StreamSplitter::onBufferReleasedByOutput(const sp<Surface>& from) {
     ATRACE_CALL();
-    sp<Fence> fence;
 
-    int slot = BufferItem::INVALID_BUFFER_SLOT;
-    auto res = from->dequeueBuffer(&slot, &fence, mWidth, mHeight, mFormat, mProducerUsage,
-            nullptr, nullptr);
+    from->setBuffersDimensions(mWidth, mHeight);
+    from->setBuffersFormat(mFormat);
+    from->setUsage(mProducerUsage);
+
+    sp<GraphicBuffer> buffer;
+    sp<Fence> fence;
+    auto res = from->dequeueBuffer(&buffer, &fence);
     Mutex::Autolock lock(mMutex);
-    handleOutputDequeueStatusLocked(res, slot);
+    handleOutputDequeueStatusLocked(res, buffer);
     if (res != OK) {
         return;
     }
 
     size_t surfaceId = 0;
     bool found = false;
-    for (const auto& it : mOutputs) {
+    for (const auto& it : mOutputSurfaces) {
         if (it.second == from) {
             found = true;
             surfaceId = it.first;
@@ -687,36 +630,29 @@
         return;
     }
 
-    returnOutputBufferLocked(fence, from, surfaceId, slot);
+    returnOutputBufferLocked(fence, from, surfaceId, buffer);
 }
 
-void Camera3StreamSplitter::onBufferReplacedLocked(
-        const sp<IGraphicBufferProducer>& from, size_t surfaceId) {
+void Camera3StreamSplitter::onBufferReplacedLocked(const sp<Surface>& from, size_t surfaceId) {
     ATRACE_CALL();
-    sp<Fence> fence;
 
-    int slot = BufferItem::INVALID_BUFFER_SLOT;
-    auto res = from->dequeueBuffer(&slot, &fence, mWidth, mHeight, mFormat, mProducerUsage,
-            nullptr, nullptr);
-    handleOutputDequeueStatusLocked(res, slot);
+    from->setBuffersDimensions(mWidth, mHeight);
+    from->setBuffersFormat(mFormat);
+    from->setUsage(mProducerUsage);
+
+    sp<GraphicBuffer> buffer;
+    sp<Fence> fence;
+    auto res = from->dequeueBuffer(&buffer, &fence);
+    handleOutputDequeueStatusLocked(res, buffer);
     if (res != OK) {
         return;
     }
 
-    returnOutputBufferLocked(fence, from, surfaceId, slot);
+    returnOutputBufferLocked(fence, from, surfaceId, buffer);
 }
 
 void Camera3StreamSplitter::returnOutputBufferLocked(const sp<Fence>& fence,
-        const sp<IGraphicBufferProducer>& from, size_t surfaceId, int slot) {
-    sp<GraphicBuffer> buffer;
-
-    if (mOutputSlots[from] == nullptr) {
-        //Output surface got likely removed by client.
-        return;
-    }
-
-    auto outputSlots = *mOutputSlots[from];
-    buffer = outputSlots[slot];
+        const sp<Surface>& from, size_t surfaceId, const sp<GraphicBuffer>& buffer) {
     BufferTracker& tracker = *(mBuffers[buffer->getId()]);
     // Merge the release fence of the incoming buffer so that the fence we send
     // back to the input includes all of the outputs' fences
@@ -727,9 +663,16 @@
     auto detachBuffer = mDetachedBuffers.find(buffer->getId());
     bool detach = (detachBuffer != mDetachedBuffers.end());
     if (detach) {
-        auto res = from->detachBuffer(slot);
+        auto res = from->detachBuffer(buffer);
         if (res == NO_ERROR) {
-            outputSlots[slot] = nullptr;
+            if (mHeldBuffers.contains(from)) {
+                mHeldBuffers[from]->erase(buffer);
+            } else {
+                uint64_t surfaceId = 0;
+                from->getUniqueId(&surfaceId);
+                SP_LOGW("%s: buffer %" PRIu64 " not found in held buffers of surface %" PRIu64,
+                        __FUNCTION__, buffer->getId(), surfaceId);
+            }
         } else {
             SP_LOGE("%s: detach buffer from output failed (%d)", __FUNCTION__, res);
         }
@@ -739,22 +682,17 @@
     decrementBufRefCountLocked(buffer->getId(), surfaceId);
 }
 
-void Camera3StreamSplitter::handleOutputDequeueStatusLocked(status_t res, int slot) {
+void Camera3StreamSplitter::handleOutputDequeueStatusLocked(status_t res,
+        const sp<GraphicBuffer>& buffer) {
     if (res == NO_INIT) {
         // If we just discovered that this output has been abandoned, note that,
         // but we can't do anything else, since buffer is invalid
         onAbandonedLocked();
-    } else if (res == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
-        SP_LOGE("%s: Producer needs to re-allocate buffer!", __FUNCTION__);
-        SP_LOGE("%s: This should not happen with buffer allocation disabled!", __FUNCTION__);
-    } else if (res == IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
-        SP_LOGE("%s: All slot->buffer mapping should be released!", __FUNCTION__);
-        SP_LOGE("%s: This should not happen with buffer allocation disabled!", __FUNCTION__);
     } else if (res == NO_MEMORY) {
         SP_LOGE("%s: No free buffers", __FUNCTION__);
     } else if (res == WOULD_BLOCK) {
         SP_LOGE("%s: Dequeue call will block", __FUNCTION__);
-    } else if (res != OK || (slot == BufferItem::INVALID_BUFFER_SLOT)) {
+    } else if (res != OK || buffer == nullptr) {
         SP_LOGE("%s: dequeue buffer from output failed (%d)", __FUNCTION__, res);
     }
 }
@@ -773,36 +711,20 @@
     SP_LOGV("One of my outputs has abandoned me");
 }
 
-int Camera3StreamSplitter::getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
-        const sp<GraphicBuffer>& gb) {
-    auto& outputSlots = *mOutputSlots[gbp];
-
-    for (size_t i = 0; i < outputSlots.size(); i++) {
-        if (outputSlots[i] == gb) {
-            return (int)i;
-        }
-    }
-
-    SP_LOGV("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
-            gbp.get());
-    return BufferItem::INVALID_BUFFER_SLOT;
-}
-
-Camera3StreamSplitter::OutputListener::OutputListener(
-        wp<Camera3StreamSplitter> splitter,
-        wp<IGraphicBufferProducer> output)
-      : mSplitter(splitter), mOutput(output) {}
+Camera3StreamSplitter::OutputListener::OutputListener(wp<Camera3StreamSplitter> splitter,
+        wp<Surface> output)
+    : mSplitter(splitter), mOutput(output) {}
 
 void Camera3StreamSplitter::OutputListener::onBufferReleased() {
     ATRACE_CALL();
     sp<Camera3StreamSplitter> splitter = mSplitter.promote();
-    sp<IGraphicBufferProducer> output = mOutput.promote();
+    sp<Surface> output = mOutput.promote();
     if (splitter != nullptr && output != nullptr) {
         splitter->onBufferReleasedByOutput(output);
     }
 }
 
-void Camera3StreamSplitter::OutputListener::binderDied(const wp<IBinder>& /* who */) {
+void Camera3StreamSplitter::OutputListener::onRemoteDied() {
     sp<Camera3StreamSplitter> splitter = mSplitter.promote();
     if (splitter != nullptr) {
         Mutex::Autolock lock(splitter->mMutex);
@@ -833,3 +755,5 @@
 }
 
 } // namespace android
+
+#endif  // USE_NEW_STREAM_SPLITTER
\ No newline at end of file
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 43f12fb..0440e08 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -14,22 +14,25 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SERVERS_STREAMSPLITTER_H
-#define ANDROID_SERVERS_STREAMSPLITTER_H
+#pragma once
 
+#include <memory>
 #include <unordered_set>
 
 #include <camera/CameraMetadata.h>
 
-#include <gui/IConsumerListener.h>
-#include <gui/Surface.h>
 #include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
 
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
 
+#include "Flags.h"
+
+#if USE_NEW_STREAM_SPLITTER  // trying to do this for each change would be a huge hassle.
+
 #define SP_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.c_str(), ##__VA_ARGS__)
 #define SP_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.c_str(), ##__VA_ARGS__)
 #define SP_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.c_str(), ##__VA_ARGS__)
@@ -38,8 +41,6 @@
 namespace android {
 
 class GraphicBuffer;
-class IGraphicBufferConsumer;
-class IGraphicBufferProducer;
 
 // Camera3StreamSplitter is an autonomous class that manages one input BufferQueue
 // and multiple output BufferQueues. By using the buffer attach and detach logic
@@ -47,9 +48,8 @@
 // BufferQueue, where each buffer queued to the input is available to be
 // acquired by each of the outputs, and is able to be dequeued by the input
 // again only once all of the outputs have released it.
-class Camera3StreamSplitter : public BnConsumerListener {
-public:
-
+class Camera3StreamSplitter : public BufferItemConsumer::FrameAvailableListener {
+  public:
     // Constructor
     Camera3StreamSplitter(bool useHalBufManager = false);
 
@@ -67,7 +67,7 @@
     //
     // A return value other than NO_ERROR means that an error has occurred and
     // outputQueue has not been added to the splitter. BAD_VALUE is returned if
-    // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations
+    // outputQueue is NULL. See Surface::connect for explanations
     // of other error codes.
     status_t addOutput(size_t surfaceId, const sp<Surface>& outputQueue);
 
@@ -97,7 +97,7 @@
     void setHalBufferManager(bool enabled);
 
 private:
-    // From IConsumerListener
+    // From BufferItemConsumer::FrameAvailableListener
     //
     // During this callback, we store some tracking information, detach the
     // buffer from the input, and attach it to each of the outputs. This call
@@ -106,23 +106,13 @@
     // input.
     void onFrameAvailable(const BufferItem& item) override;
 
-    // From IConsumerListener
+    // From BufferItemConsumer::FrameAvailableListener
     //
     // Similar to onFrameAvailable, but buffer item is indeed replacing a buffer
     // in the buffer queue. This can happen when buffer queue is in droppable
     // mode.
     void onFrameReplaced(const BufferItem& item) override;
 
-    // From IConsumerListener
-    // We don't care about released buffers because we detach each buffer as
-    // soon as we acquire it. See the comment for onBufferReleased below for
-    // some clarifying notes about the name.
-    void onBuffersReleased() override {}
-
-    // From IConsumerListener
-    // We don't care about sideband streams, since we won't be splitting them
-    void onSidebandStreamChanged() override {}
-
     // This is the implementation of the onBufferReleased callback from
     // IProducerListener. It gets called from an OutputListener (see below), and
     // 'from' is which producer interface from which the callback was received.
@@ -132,10 +122,10 @@
     // last output releasing the buffer, and if so, release it to the input.
     // If we release the buffer to the input, we allow a blocked
     // onFrameAvailable call to proceed.
-    void onBufferReleasedByOutput(const sp<IGraphicBufferProducer>& from);
+    void onBufferReleasedByOutput(const sp<Surface>& from);
 
     // Called by outputBufferLocked when a buffer in the async buffer queue got replaced.
-    void onBufferReplacedLocked(const sp<IGraphicBufferProducer>& from, size_t surfaceId);
+    void onBufferReplacedLocked(const sp<Surface>& from, size_t surfaceId);
 
     // When this is called, the splitter disconnects from (i.e., abandons) its
     // input queue and signals any waiting onFrameAvailable calls to wake up.
@@ -149,35 +139,32 @@
     void decrementBufRefCountLocked(uint64_t id, size_t surfaceId);
 
     // Check for and handle any output surface dequeue errors.
-    void handleOutputDequeueStatusLocked(status_t res, int slot);
+    void handleOutputDequeueStatusLocked(status_t res, const sp<GraphicBuffer>& buffer);
 
     // Handles released output surface buffers.
-    void returnOutputBufferLocked(const sp<Fence>& fence, const sp<IGraphicBufferProducer>& from,
-            size_t surfaceId, int slot);
+    void returnOutputBufferLocked(const sp<Fence>& fence, const sp<Surface>& from, size_t surfaceId,
+            const sp<GraphicBuffer>& buffer);
 
     // This is a thin wrapper class that lets us determine which BufferQueue
     // the IProducerListener::onBufferReleased callback is associated with. We
     // create one of these per output BufferQueue, and then pass the producer
     // into onBufferReleasedByOutput above.
-    class OutputListener : public SurfaceListener,
-                           public IBinder::DeathRecipient {
-    public:
-        OutputListener(wp<Camera3StreamSplitter> splitter,
-                wp<IGraphicBufferProducer> output);
+    class OutputListener : public SurfaceListener {
+      public:
+        OutputListener(wp<Camera3StreamSplitter> splitter, wp<Surface> output);
         virtual ~OutputListener() = default;
 
-        // From IProducerListener
+        // From SurfaceListener
         void onBufferReleased() override;
         bool needsReleaseNotify() override { return true; };
-        void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& /*buffers*/) override {};
+        void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>&) override {}
         void onBufferDetached(int /*slot*/) override {}
 
-        // From IBinder::DeathRecipient
-        void binderDied(const wp<IBinder>& who) override;
+        void onRemoteDied() override;
 
     private:
         wp<Camera3StreamSplitter> mSplitter;
-        wp<IGraphicBufferProducer> mOutput;
+        wp<Surface> mOutput;
     };
 
     class BufferTracker {
@@ -198,7 +185,6 @@
         const std::vector<size_t> requestedSurfaces() const { return mRequestedSurfaces; }
 
     private:
-
         // Disallow copying
         BufferTracker(const BufferTracker& other);
         BufferTracker& operator=(const BufferTracker& other);
@@ -223,16 +209,12 @@
     // Send a buffer to particular output, and increment the reference count
     // of the buffer. If this output is abandoned, the buffer's reference count
     // won't be incremented.
-    status_t outputBufferLocked(const sp<IGraphicBufferProducer>& output,
-            const BufferItem& bufferItem, size_t surfaceId);
+    status_t outputBufferLocked(const sp<Surface>& output, const BufferItem& bufferItem,
+            size_t surfaceId);
 
     // Get unique name for the buffer queue consumer
     std::string getUniqueConsumerName();
 
-    // Helper function to get the BufferQueue slot where a particular buffer is attached to.
-    int getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
-            const sp<GraphicBuffer>& gb);
-
     // Sum of max consumer buffers for all outputs
     size_t mMaxConsumerBuffers = 0;
     size_t mMaxHalBuffers = 0;
@@ -249,17 +231,9 @@
 
     Mutex mMutex;
 
-    sp<IGraphicBufferProducer> mProducer;
-    sp<IGraphicBufferConsumer> mConsumer;
     sp<BufferItemConsumer> mBufferItemConsumer;
     sp<Surface> mSurface;
 
-    //Map graphic buffer ids -> buffer items
-    std::unordered_map<uint64_t, BufferItem> mInputSlots;
-
-    //Map surface ids -> gbp outputs
-    std::unordered_map<int, sp<IGraphicBufferProducer> > mOutputs;
-
     //Map surface ids -> gbp outputs
     std::unordered_map<int, sp<Surface>> mOutputSurfaces;
 
@@ -271,18 +245,22 @@
     // buffer, but also contain merged release fences).
     std::unordered_map<uint64_t, std::unique_ptr<BufferTracker> > mBuffers;
 
-    struct GBPHash {
-        std::size_t operator()(const sp<IGraphicBufferProducer>& producer) const {
-            return std::hash<IGraphicBufferProducer *>{}(producer.get());
+    struct SurfaceHash {
+        std::size_t operator()(const sp<Surface>& producer) const {
+            return std::hash<Surface*>{}(producer.get());
         }
     };
 
-    std::unordered_map<sp<IGraphicBufferProducer>, sp<OutputListener>,
-            GBPHash> mNotifiers;
+    struct BufferHash {
+        std::size_t operator()(const sp<GraphicBuffer>& buffer) const {
+            return std::hash<GraphicBuffer*>{}(buffer.get());
+        }
+    };
 
-    typedef std::vector<sp<GraphicBuffer>> OutputSlots;
-    std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>,
-            GBPHash> mOutputSlots;
+    std::unordered_map<sp<Surface>, sp<OutputListener>, SurfaceHash> mNotifiers;
+
+    typedef std::unordered_set<sp<GraphicBuffer>, BufferHash> HeldBuffers;
+    std::unordered_map<sp<Surface>, std::unique_ptr<HeldBuffers>, SurfaceHash> mHeldBuffers;
 
     //A set of buffers that could potentially stay in some of the outputs after removal
     //and therefore should be detached from the input queue.
@@ -301,4 +279,4 @@
 
 } // namespace android
 
-#endif
+#endif  // USE_NEW_STREAM_SPLITTER
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index 9a3f433..9a4e9e3 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -43,9 +43,7 @@
             kResultPointsToCorrectNoClamp.begin(),
             kResultPointsToCorrectNoClamp.end());
     mRemappedKeys.insert(ANDROID_DISTORTION_CORRECTION_MODE);
-    if (flags::concert_mode()) {
-        mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
-    }
+    mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
 }
 
 bool DistortionMapper::isDistortionSupported(const CameraMetadata &deviceInfo) {
diff --git a/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
index 8bb22a9..1ea077c 100644
--- a/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
+++ b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
@@ -37,9 +37,7 @@
 
     mRemappedKeys.insert(ANDROID_SCALER_ROTATE_AND_CROP);
     mRemappedKeys.insert(ANDROID_SCALER_CROP_REGION);
-    if (flags::concert_mode()) {
-        mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
-    }
+    mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
 }
 
 bool RotateAndCropMapper::isNeeded(const CameraMetadata* deviceInfo) {
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 1f52e9b..2016284 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -38,9 +38,7 @@
             kResultPointsToCorrectNoClamp.end());
 
     mRemappedKeys.insert(ANDROID_CONTROL_ZOOM_RATIO);
-    if (flags::concert_mode()) {
-        mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
-    }
+    mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
 }
 
 status_t ZoomRatioMapper::initZoomRatioInTemplate(CameraMetadata *request) {
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 57297bc..e52e9a2 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -349,7 +349,7 @@
                 readoutSupported.data.u8[0] == ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE;
     }
 
-    return initializeCommonLocked();
+    return initializeCommonLocked(manager);
 }
 
 ::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::processCaptureResult(
@@ -918,12 +918,6 @@
         camera3::camera_stream_t *src = config->streams[i];
 
         Camera3Stream* cam3stream = Camera3Stream::cast(src);
-        // For stream configurations with multi res streams, hal buffer manager has to be used.
-        if (!flags::session_hal_buf_manager() && cam3stream->getHalStreamGroupId() != -1 &&
-                src->stream_type != CAMERA_STREAM_INPUT) {
-            mUseHalBufManager = true;
-            config->use_hal_buf_manager = true;
-        }
         cam3stream->setBufferFreedListener(this);
         int streamId = cam3stream->getId();
         StreamType streamType;
@@ -1002,8 +996,7 @@
               err.getMessage());
         return AidlProviderInfo::mapToStatusT(err);
     }
-    if (flags::session_hal_buf_manager() && interfaceVersion >= AIDL_DEVICE_SESSION_V3
-            && mSupportSessionHalBufManager) {
+    if (interfaceVersion >= AIDL_DEVICE_SESSION_V3 && mSupportSessionHalBufManager) {
         err = mAidlSession->configureStreamsV2(requestedConfiguration, &configureStreamsRet);
         finalConfiguration = std::move(configureStreamsRet.halStreams);
     } else {
@@ -1015,18 +1008,16 @@
         return AidlProviderInfo::mapToStatusT(err);
     }
 
-    if (flags::session_hal_buf_manager()) {
-        std::set<int32_t> halBufferManagedStreamIds;
-        for (const auto &halStream: finalConfiguration) {
-            if ((interfaceVersion >= AIDL_DEVICE_SESSION_V3 &&
-                    mSupportSessionHalBufManager && halStream.enableHalBufferManager)
-                    || mUseHalBufManager) {
-                halBufferManagedStreamIds.insert(halStream.id);
-            }
+    std::set<int32_t> halBufferManagedStreamIds;
+    for (const auto &halStream: finalConfiguration) {
+        if ((interfaceVersion >= AIDL_DEVICE_SESSION_V3 &&
+                mSupportSessionHalBufManager && halStream.enableHalBufferManager)
+                || mUseHalBufManager) {
+            halBufferManagedStreamIds.insert(halStream.id);
         }
-        mHalBufManagedStreamIds = std::move(halBufferManagedStreamIds);
-        config->hal_buffer_managed_streams = mHalBufManagedStreamIds;
     }
+    mHalBufManagedStreamIds = std::move(halBufferManagedStreamIds);
+    config->hal_buffer_managed_streams = mHalBufManagedStreamIds;
     // And convert output stream configuration from AIDL
     for (size_t i = 0; i < config->num_streams; i++) {
         camera3::camera_stream_t *dst = config->streams[i];
@@ -1096,10 +1087,8 @@
             }
             dstStream->setUsage(
                     mapProducerToFrameworkUsage(src.producerUsage));
-            if (flags::session_hal_buf_manager()) {
-                dstStream->setHalBufferManager(
-                        contains(config->hal_buffer_managed_streams, streamId));
-            }
+            dstStream->setHalBufferManager(
+                    contains(config->hal_buffer_managed_streams, streamId));
         }
         dst->max_buffers = src.maxBuffers;
     }
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index 09299e6..6986d3c 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -303,7 +303,7 @@
     }
     mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
 
-    return initializeCommonLocked();
+    return initializeCommonLocked(manager);
 }
 
 hardware::Return<void> HidlCamera3Device::requestStreamBuffers(
@@ -929,7 +929,7 @@
         switch (src->stream_type) {
             case CAMERA_STREAM_OUTPUT:
                 streamType = StreamType::OUTPUT;
-                if (flags::session_hal_buf_manager() && mUseHalBufManager) {
+                if (mUseHalBufManager) {
                     mHalBufManagedStreamIds.insert(streamId);
                 }
                 break;
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index bbc10dc..837bf6d 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -44,13 +44,25 @@
         "libjpeg",
         "liblog",
         "libutils",
-        "camera_platform_flags_c_lib",
     ],
 
     static_libs: [
         "libgmock",
     ],
 
+    target: {
+        android: {
+            shared_libs: [
+                "camera_platform_flags_c_lib",
+            ],
+        },
+        host: {
+            shared_libs: [
+                "camera_platform_flags_c_lib_for_test",
+            ],
+        },
+    },
+
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 939126c..56cacef 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -445,10 +445,6 @@
 
     virtual std::shared_ptr<aidl::android::hardware::camera::provider::ICameraProvider>
             getService(const std::string& serviceName) override {
-        if (!flags::delay_lazy_hal_instantiation()) {
-            return mTestAidlCameraProvider;
-        }
-
         // If no provider has been given, fail; in reality, getService would
         // block for HALs that don't start correctly, so we should never use
         // getService when we don't have a valid HAL running
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
index 93b440b..37903e1 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AttributionAndPermissionUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
 #include "AttributionAndPermissionUtils.h"
 
 #include <binder/AppOpsManager.h>
@@ -25,8 +28,12 @@
 #include "CameraService.h"
 
 #include <binder/IPCThreadState.h>
-#include <hwbinder/IPCThreadState.h>
 #include <binderthreadstate/CallerUtils.h>
+#include <hwbinder/IPCThreadState.h>
+
+namespace {
+static const std::string kPermissionServiceName = "permission";
+} // namespace
 
 namespace android {
 
@@ -35,8 +42,7 @@
 const std::string AttributionAndPermissionUtils::sDumpPermission("android.permission.DUMP");
 const std::string AttributionAndPermissionUtils::sManageCameraPermission(
         "android.permission.MANAGE_CAMERA");
-const std::string AttributionAndPermissionUtils::sCameraPermission(
-        "android.permission.CAMERA");
+const std::string AttributionAndPermissionUtils::sCameraPermission("android.permission.CAMERA");
 const std::string AttributionAndPermissionUtils::sSystemCameraPermission(
         "android.permission.SYSTEM_CAMERA");
 const std::string AttributionAndPermissionUtils::sCameraHeadlessSystemUserPermission(
@@ -50,14 +56,14 @@
 const std::string AttributionAndPermissionUtils::sCameraInjectExternalCameraPermission(
         "android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
 
-int AttributionAndPermissionUtils::getCallingUid() {
+int AttributionAndPermissionUtils::getCallingUid() const {
     if (getCurrentServingCall() == BinderCallType::HWBINDER) {
         return hardware::IPCThreadState::self()->getCallingUid();
     }
     return IPCThreadState::self()->getCallingUid();
 }
 
-int AttributionAndPermissionUtils::getCallingPid() {
+int AttributionAndPermissionUtils::getCallingPid() const {
     if (getCurrentServingCall() == BinderCallType::HWBINDER) {
         return hardware::IPCThreadState::self()->getCallingPid();
     }
@@ -80,47 +86,38 @@
     return;
 }
 
-bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(const std::string &cameraId,
-        const AttributionSourceState &attributionSource) {
-    if (isAutomotivePrivilegedClient(attributionSource.uid)) {
-        // If cameraId is empty, then it means that this check is not used for the
-        // purpose of accessing a specific camera, hence grant permission just
-        // based on uid to the automotive privileged client.
-        if (cameraId.empty())
-            return true;
-
-        auto cameraService = mCameraService.promote();
-        if (cameraService == nullptr) {
-            ALOGE("%s: CameraService unavailable.", __FUNCTION__);
-            return false;
-        }
-
-        // If this call is used for accessing a specific camera then cam_id must be provided.
-        // In that case, only pre-grants the permission for accessing the exterior system only
-        // camera.
-        return cameraService->isAutomotiveExteriorSystemCamera(cameraId);
+binder::Status AttributionAndPermissionUtils::resolveAttributionSource(
+        /*inout*/ AttributionSourceState& resolvedAttributionSource, const std::string& methodName,
+        const std::optional<std::string>& cameraIdMaybe) {
+    // Check if we can trust clientUid
+    if (!resolveClientUid(resolvedAttributionSource.uid)) {
+        return errorNotTrusted(resolvedAttributionSource.pid, resolvedAttributionSource.uid,
+                               methodName, cameraIdMaybe, *resolvedAttributionSource.packageName,
+                               /* isPid= */ false);
     }
 
-    return false;
+    resolveAttributionPackage(resolvedAttributionSource);
+
+    if (!resolveClientPid(resolvedAttributionSource.pid)) {
+        return errorNotTrusted(resolvedAttributionSource.pid, resolvedAttributionSource.uid,
+                               methodName, cameraIdMaybe, *resolvedAttributionSource.packageName,
+                               /* isPid= */ true);
+    }
+
+    return binder::Status::ok();
 }
 
-bool AttributionAndPermissionUtils::checkPermissionForPreflight(const std::string &cameraId,
-        const std::string &permission, const AttributionSourceState &attributionSource,
-        const std::string& message, int32_t attributedOpCode) {
+bool AttributionAndPermissionUtils::checkPermissionForPreflight(
+        const std::string& cameraId, const std::string& permission,
+        const AttributionSourceState& attributionSource, const std::string& message,
+        int32_t attributedOpCode) {
     if (checkAutomotivePrivilegedClient(cameraId, attributionSource)) {
         return true;
     }
 
-    if (!flags::cache_permission_services()) {
-        PermissionChecker permissionChecker;
-        return permissionChecker.checkPermissionForPreflight(
-                       toString16(permission), attributionSource, toString16(message),
-                       attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
-    } else {
-        return mPermissionChecker->checkPermissionForPreflight(
-                       toString16(permission), attributionSource, toString16(message),
-                       attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
-    }
+    return mPermissionChecker->checkPermissionForPreflight(
+                   toString16(permission), attributionSource, toString16(message),
+                   attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
 }
 
 // Can camera service trust the caller based on the calling UID?
@@ -153,8 +150,7 @@
 
 bool AttributionAndPermissionUtils::isAutomotivePrivilegedClient(int32_t uid) {
     // Returns false if this is not an automotive device type.
-    if (!isAutomotiveDevice())
-        return false;
+    if (!isAutomotiveDevice()) return false;
 
     // Returns true if the uid is AID_AUTOMOTIVE_EVS which is a
     // privileged client uid used for safety critical use cases such as
@@ -162,8 +158,35 @@
     return uid == AID_AUTOMOTIVE_EVS;
 }
 
-status_t AttributionAndPermissionUtils::getUidForPackage(const std::string &packageName,
-        int userId, /*inout*/uid_t& uid, int err) {
+std::string AttributionAndPermissionUtils::getPackageNameFromUid(int clientUid) const {
+    std::string packageName("");
+
+    sp<IPermissionController> permCtrl = getPermissionController();
+    if (permCtrl == nullptr) {
+        // Return empty package name and the further interaction
+        // with camera will likely fail
+        return packageName;
+    }
+
+    Vector<String16> packages;
+
+    permCtrl->getPackagesForUid(clientUid, packages);
+
+    if (packages.isEmpty()) {
+        ALOGE("No packages for calling UID %d", clientUid);
+        // Return empty package name and the further interaction
+        // with camera will likely fail
+        return packageName;
+    }
+
+    // Arbitrarily pick the first name in the list
+    packageName = toStdString(packages[0]);
+
+    return packageName;
+}
+
+status_t AttributionAndPermissionUtils::getUidForPackage(const std::string& packageName, int userId,
+                                                         /*inout*/ uid_t& uid, int err) {
     PermissionController pc;
     uid = pc.getPackageUid(toString16(packageName), 0);
     if (uid <= 0) {
@@ -186,36 +209,147 @@
     return (getCallingPid() == getpid());
 }
 
-bool AttributionAndPermissionUtils::hasPermissionsForCamera(const std::string& cameraId,
-        const AttributionSourceState& attributionSource) {
-    return checkPermissionForPreflight(cameraId, sCameraPermission,
-            attributionSource, std::string(), AppOpsManager::OP_NONE);
+bool AttributionAndPermissionUtils::hasPermissionsForCamera(
+        const std::string& cameraId, const AttributionSourceState& attributionSource) {
+    return checkPermissionForPreflight(cameraId, sCameraPermission, attributionSource,
+                                       std::string(), AppOpsManager::OP_NONE);
 }
 
-bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(const std::string& cameraId,
-        const AttributionSourceState& attributionSource, bool checkCameraPermissions) {
-    bool systemCameraPermission = checkPermissionForPreflight(cameraId,
-            sSystemCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
-    return systemCameraPermission && (!checkCameraPermissions
-            || hasPermissionsForCamera(cameraId, attributionSource));
+bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(
+        const std::string& cameraId, const AttributionSourceState& attributionSource,
+        bool checkCameraPermissions) {
+    bool systemCameraPermission =
+            checkPermissionForPreflight(cameraId, sSystemCameraPermission, attributionSource,
+                                        std::string(), AppOpsManager::OP_NONE);
+    return systemCameraPermission &&
+           (!checkCameraPermissions || hasPermissionsForCamera(cameraId, attributionSource));
 }
 
 bool AttributionAndPermissionUtils::hasPermissionsForCameraHeadlessSystemUser(
         const std::string& cameraId, const AttributionSourceState& attributionSource) {
     return checkPermissionForPreflight(cameraId, sCameraHeadlessSystemUserPermission,
-            attributionSource, std::string(), AppOpsManager::OP_NONE);
+                                       attributionSource, std::string(), AppOpsManager::OP_NONE);
 }
 
 bool AttributionAndPermissionUtils::hasPermissionsForCameraPrivacyAllowlist(
         const AttributionSourceState& attributionSource) {
     return checkPermissionForPreflight(std::string(), sCameraPrivacyAllowlistPermission,
-            attributionSource, std::string(), AppOpsManager::OP_NONE);
+                                       attributionSource, std::string(), AppOpsManager::OP_NONE);
 }
 
 bool AttributionAndPermissionUtils::hasPermissionsForOpenCloseListener(
         const AttributionSourceState& attributionSource) {
     return checkPermissionForPreflight(std::string(), sCameraOpenCloseListenerPermission,
-            attributionSource, std::string(), AppOpsManager::OP_NONE);
+                                       attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(
+        const std::string& cameraId, const AttributionSourceState& attributionSource) {
+    if (isAutomotivePrivilegedClient(attributionSource.uid)) {
+        // If cameraId is empty, then it means that this check is not used for the
+        // purpose of accessing a specific camera, hence grant permission just
+        // based on uid to the automotive privileged client.
+        if (cameraId.empty()) return true;
+
+        auto cameraService = mCameraService.promote();
+        if (cameraService == nullptr) {
+            ALOGE("%s: CameraService unavailable.", __FUNCTION__);
+            return false;
+        }
+
+        // If this call is used for accessing a specific camera then cam_id must be provided.
+        // In that case, only pre-grants the permission for accessing the exterior system only
+        // camera.
+        return cameraService->isAutomotiveExteriorSystemCamera(cameraId);
+    }
+
+    return false;
+}
+
+void AttributionAndPermissionUtils::resolveAttributionPackage(
+        AttributionSourceState& resolvedAttributionSource) {
+    if (resolvedAttributionSource.packageName.has_value() &&
+        resolvedAttributionSource.packageName->size() > 0) {
+        return;
+    }
+
+    // NDK calls don't come with package names, but we need one for various cases.
+    // Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
+    // do exist. For all authentication cases, all packages under the same UID get the
+    // same permissions, so picking any associated package name is sufficient. For some
+    // other cases, this may give inaccurate names for clients in logs.
+    resolvedAttributionSource.packageName = getPackageNameFromUid(resolvedAttributionSource.uid);
+}
+
+// TODO(362551824): Make USE_CALLING_UID more explicit with a scoped enum.
+bool AttributionAndPermissionUtils::resolveClientUid(/*inout*/ int& clientUid) {
+    int callingUid = getCallingUid();
+
+    bool validUid = true;
+    if (clientUid == hardware::ICameraService::USE_CALLING_UID) {
+        clientUid = callingUid;
+    } else {
+        validUid = isTrustedCallingUid(callingUid);
+        if (flags::use_context_attribution_source()) {
+            validUid = validUid || (clientUid == callingUid);
+        }
+    }
+
+    return validUid;
+}
+
+// TODO(362551824): Make USE_CALLING_UID more explicit with a scoped enum.
+bool AttributionAndPermissionUtils::resolveClientPid(/*inout*/ int& clientPid) {
+    int callingUid = getCallingUid();
+    int callingPid = getCallingPid();
+
+    bool validPid = true;
+    if (clientPid == hardware::ICameraService::USE_CALLING_PID) {
+        clientPid = callingPid;
+    } else {
+        validPid = isTrustedCallingUid(callingUid);
+        if (flags::use_context_attribution_source()) {
+            validPid = validPid || (clientPid == callingPid);
+        }
+    }
+
+    return validPid;
+}
+
+binder::Status AttributionAndPermissionUtils::errorNotTrusted(
+        int clientPid, int clientUid, const std::string& methodName,
+        const std::optional<std::string>& cameraIdMaybe, const std::string& clientName,
+        bool isPid) const {
+    int callingPid = getCallingPid();
+    int callingUid = getCallingUid();
+    ALOGE("CameraService::%s X (calling PID %d, calling UID %d) rejected "
+          "(don't trust %s %d)",
+          methodName.c_str(), callingPid, callingUid, isPid ? "clientPid" : "clientUid",
+          isPid ? clientPid : clientUid);
+    return STATUS_ERROR_FMT(hardware::ICameraService::ERROR_PERMISSION_DENIED,
+                            "Untrusted caller (calling PID %d, UID %d) trying to "
+                            "forward camera access to camera %s for client %s (PID %d, UID %d)",
+                            getCallingPid(), getCallingUid(), cameraIdMaybe.value_or("N/A").c_str(),
+                            clientName.c_str(), clientPid, clientUid);
+}
+
+const sp<IPermissionController>& AttributionAndPermissionUtils::getPermissionController() const {
+    static const char* kPermissionControllerService = "permission";
+    static thread_local sp<IPermissionController> sPermissionController = nullptr;
+
+    if (sPermissionController == nullptr ||
+        !IInterface::asBinder(sPermissionController)->isBinderAlive()) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->checkService(toString16(kPermissionControllerService));
+        if (binder == nullptr) {
+            ALOGE("%s: Could not get permission service", __FUNCTION__);
+            sPermissionController = nullptr;
+        } else {
+            sPermissionController = interface_cast<IPermissionController>(binder);
+        }
+    }
+
+    return sPermissionController;
 }
 
 } // namespace android
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
index 4daab0f..22abccc 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
@@ -19,6 +19,7 @@
 #include <android/content/AttributionSourceState.h>
 #include <android/permission/PermissionChecker.h>
 #include <binder/BinderService.h>
+#include <binder/IPermissionController.h>
 #include <private/android_filesystem_config.h>
 
 namespace android {
@@ -34,12 +35,10 @@
  */
 class AttributionAndPermissionUtils {
   public:
-    AttributionAndPermissionUtils() { }
+    AttributionAndPermissionUtils() {}
     virtual ~AttributionAndPermissionUtils() {}
 
-    void setCameraService(wp<CameraService> cameraService) {
-        mCameraService = cameraService;
-    }
+    void setCameraService(wp<CameraService> cameraService) { mCameraService = cameraService; }
 
     static AttributionSourceState buildAttributionSource(int callingPid, int callingUid) {
         AttributionSourceState attributionSource{};
@@ -49,19 +48,33 @@
     }
 
     static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
-            int32_t deviceId) {
+                                                         int32_t deviceId) {
         AttributionSourceState attributionSource = buildAttributionSource(callingPid, callingUid);
         attributionSource.deviceId = deviceId;
         return attributionSource;
     }
 
     // Utilities handling Binder calling identities (previously in CameraThreadState)
-    virtual int getCallingUid();
-    virtual int getCallingPid();
+    virtual int getCallingUid() const;
+    virtual int getCallingPid() const;
     virtual int64_t clearCallingIdentity();
     virtual void restoreCallingIdentity(int64_t token);
 
     /**
+     * If flag::use_context_attribution_source() is enabled, check the calling attribution source
+     * and resolve its package name, or fill in the pid/uid/package name if necessary.
+     *
+     * @param resolvedAttributionSource The resolved attribution source.
+     * @param methodName The name of the method calling this function (for logging only).
+     * @param cameraIdMaybe The camera ID, if applicable.
+     * @return The status of the operation.
+     */
+    virtual binder::Status resolveAttributionSource(
+            /*inout*/ AttributionSourceState& resolvedAttributionSource,
+            const std::string& methodName,
+            const std::optional<std::string>& cameraIdMaybe = std::nullopt);
+
+    /**
      * Pre-grants the permission if the attribution source uid is for an automotive
      * privileged client. Otherwise uses system service permission checker to check
      * for the appropriate permission. If this function is called for accessing a specific
@@ -70,9 +83,10 @@
      * which is located outside of the vehicle body frame because camera located inside the vehicle
      * cabin would need user permission.
      */
-    virtual bool checkPermissionForPreflight(const std::string &cameraId,
-            const std::string &permission, const AttributionSourceState& attributionSource,
-            const std::string& message, int32_t attributedOpCode);
+    virtual bool checkPermissionForPreflight(const std::string& cameraId,
+                                             const std::string& permission,
+                                             const AttributionSourceState& attributionSource,
+                                             const std::string& message, int32_t attributedOpCode);
 
     // Can camera service trust the caller based on the calling UID?
     virtual bool isTrustedCallingUid(uid_t uid);
@@ -85,17 +99,27 @@
      */
     virtual bool isAutomotivePrivilegedClient(int32_t uid);
 
-    virtual status_t getUidForPackage(const std::string &packageName, int userId,
-            /*inout*/uid_t& uid, int err);
+    // In some cases the calling code has no access to the package it runs under.
+    // For example, NDK camera API.
+    // In this case we will get the packages for the calling UID and pick the first one
+    // for attributing the app op. This will work correctly for runtime permissions
+    // as for legacy apps we will toggle the app op for all packages in the UID.
+    // The caveat is that the operation may be attributed to the wrong package and
+    // stats based on app ops may be slightly off.
+    virtual std::string getPackageNameFromUid(int clientUid) const;
+
+    virtual status_t getUidForPackage(const std::string& packageName, int userId,
+                                      /*inout*/ uid_t& uid, int err);
     virtual bool isCallerCameraServerNotDelegating();
 
     // Utils for checking specific permissions
     virtual bool hasPermissionsForCamera(const std::string& cameraId,
-            const AttributionSourceState& attributionSource);
+                                         const AttributionSourceState& attributionSource);
     virtual bool hasPermissionsForSystemCamera(const std::string& cameraId,
-            const AttributionSourceState& attributionSource, bool checkCameraPermissions = true);
-    virtual bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId,
-            const AttributionSourceState& attributionSource);
+                                               const AttributionSourceState& attributionSource,
+                                               bool checkCameraPermissions = true);
+    virtual bool hasPermissionsForCameraHeadlessSystemUser(
+            const std::string& cameraId, const AttributionSourceState& attributionSource);
     virtual bool hasPermissionsForCameraPrivacyAllowlist(
             const AttributionSourceState& attributionSource);
     virtual bool hasPermissionsForOpenCloseListener(
@@ -114,10 +138,24 @@
   protected:
     wp<CameraService> mCameraService;
 
-    bool checkAutomotivePrivilegedClient(const std::string &cameraId,
-            const AttributionSourceState &attributionSource);
+    bool checkAutomotivePrivilegedClient(const std::string& cameraId,
+                                         const AttributionSourceState& attributionSource);
+
+    // If the package name is missing from the AttributionSource and a package name exists for the
+    // AttributionSource's uid, fills in the missing package name.
+    void resolveAttributionPackage(AttributionSourceState& resolvedAttributionSource);
+
+    virtual bool resolveClientUid(/*inout*/ int& clientUid);
+    virtual bool resolveClientPid(/*inout*/ int& clientPid);
+
+    virtual binder::Status errorNotTrusted(int clientPid, int clientUid,
+                                           const std::string& methodName,
+                                           const std::optional<std::string>& cameraIdMaybe,
+                                           const std::string& clientName, bool isPid) const;
 
   private:
+    virtual const sp<IPermissionController>& getPermissionController() const;
+
     std::unique_ptr<permission::PermissionChecker> mPermissionChecker =
             std::make_unique<permission::PermissionChecker>();
 };
@@ -128,39 +166,36 @@
  * in the encapsulating class's methods.
  */
 class AttributionAndPermissionUtilsEncapsulator {
-protected:
+  protected:
     std::shared_ptr<AttributionAndPermissionUtils> mAttributionAndPermissionUtils;
 
-public:
+  public:
     AttributionAndPermissionUtilsEncapsulator(
-        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
-            : mAttributionAndPermissionUtils(attributionAndPermissionUtils) { }
+            std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
+        : mAttributionAndPermissionUtils(attributionAndPermissionUtils) {}
 
     static AttributionSourceState buildAttributionSource(int callingPid, int callingUid) {
         return AttributionAndPermissionUtils::buildAttributionSource(callingPid, callingUid);
     }
 
     static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
-            int32_t deviceId) {
-        return AttributionAndPermissionUtils::buildAttributionSource(
-                callingPid, callingUid, deviceId);
+                                                         int32_t deviceId) {
+        return AttributionAndPermissionUtils::buildAttributionSource(callingPid, callingUid,
+                                                                     deviceId);
     }
 
     static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
-            const std::string& packageName, int32_t deviceId) {
-        AttributionSourceState attributionSource = buildAttributionSource(callingPid, callingUid,
-                deviceId);
+                                                         const std::string& packageName,
+                                                         int32_t deviceId) {
+        AttributionSourceState attributionSource =
+                buildAttributionSource(callingPid, callingUid, deviceId);
         attributionSource.packageName = packageName;
         return attributionSource;
     }
 
-    int getCallingUid() const {
-        return mAttributionAndPermissionUtils->getCallingUid();
-    }
+    int getCallingUid() const { return mAttributionAndPermissionUtils->getCallingUid(); }
 
-    int getCallingPid() const {
-        return mAttributionAndPermissionUtils->getCallingPid();
-    }
+    int getCallingPid() const { return mAttributionAndPermissionUtils->getCallingPid(); }
 
     int64_t clearCallingIdentity() const {
         return mAttributionAndPermissionUtils->clearCallingIdentity();
@@ -170,48 +205,52 @@
         mAttributionAndPermissionUtils->restoreCallingIdentity(token);
     }
 
+    binder::Status resolveAttributionSource(AttributionSourceState& resolvedAttributionSource,
+                                            const std::string& methodName,
+                                            const std::optional<std::string>& cameraIdMaybe) {
+        return mAttributionAndPermissionUtils->resolveAttributionSource(resolvedAttributionSource,
+                                                                        methodName, cameraIdMaybe);
+    }
+
     // The word 'System' here does not refer to callers only on the system
     // partition. They just need to have an android system uid.
-    bool callerHasSystemUid() const {
-        return (getCallingUid() < AID_APP_START);
-    }
+    bool callerHasSystemUid() const { return (getCallingUid() < AID_APP_START); }
 
     bool hasPermissionsForCamera(int callingPid, int callingUid, int32_t deviceId) const {
         return hasPermissionsForCamera(std::string(), callingPid, callingUid, deviceId);
     }
 
-    bool hasPermissionsForCamera(int callingPid, int callingUid,
-            const std::string& packageName, int32_t deviceId) const {
+    bool hasPermissionsForCamera(int callingPid, int callingUid, const std::string& packageName,
+                                 int32_t deviceId) const {
         return hasPermissionsForCamera(std::string(), callingPid, callingUid, packageName,
-                deviceId);
+                                       deviceId);
     }
 
-    bool hasPermissionsForCamera(const std::string& cameraId, int callingPid,
-            int callingUid, int32_t deviceId) const {
-        auto attributionSource = buildAttributionSource(callingPid, callingUid,
-                deviceId);
+    bool hasPermissionsForCamera(const std::string& cameraId, int callingPid, int callingUid,
+                                 int32_t deviceId) const {
+        auto attributionSource = buildAttributionSource(callingPid, callingUid, deviceId);
         return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
     }
 
     bool hasPermissionsForCamera(const std::string& cameraId, int callingPid, int callingUid,
-            const std::string& packageName, int32_t deviceId) const {
-        auto attributionSource = buildAttributionSource(callingPid, callingUid, packageName,
-                deviceId);
+                                 const std::string& packageName, int32_t deviceId) const {
+        auto attributionSource =
+                buildAttributionSource(callingPid, callingUid, packageName, deviceId);
         return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
     }
 
     bool hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid, int callingUid,
-            bool checkCameraPermissions = true) const  {
+                                       bool checkCameraPermissions = true) const {
         auto attributionSource = buildAttributionSource(callingPid, callingUid);
         return mAttributionAndPermissionUtils->hasPermissionsForSystemCamera(
-                    cameraId, attributionSource, checkCameraPermissions);
+                cameraId, attributionSource, checkCameraPermissions);
     }
 
     bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId, int callingPid,
-            int callingUid) const {
+                                                   int callingUid) const {
         auto attributionSource = buildAttributionSource(callingPid, callingUid);
         return mAttributionAndPermissionUtils->hasPermissionsForCameraHeadlessSystemUser(
-                    cameraId, attributionSource);
+                cameraId, attributionSource);
     }
 
     bool hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const {
@@ -226,9 +265,7 @@
                 attributionSource);
     }
 
-    bool isAutomotiveDevice() const {
-        return mAttributionAndPermissionUtils->isAutomotiveDevice();
-    }
+    bool isAutomotiveDevice() const { return mAttributionAndPermissionUtils->isAutomotiveDevice(); }
 
     bool isAutomotivePrivilegedClient(int32_t uid) const {
         return mAttributionAndPermissionUtils->isAutomotivePrivilegedClient(uid);
@@ -242,11 +279,15 @@
         return mAttributionAndPermissionUtils->isHeadlessSystemUserMode();
     }
 
-    status_t getUidForPackage(const std::string &packageName, int userId,
-            /*inout*/uid_t& uid, int err) const {
+    status_t getUidForPackage(const std::string& packageName, int userId,
+                              /*inout*/ uid_t& uid, int err) const {
         return mAttributionAndPermissionUtils->getUidForPackage(packageName, userId, uid, err);
     }
 
+    std::string getPackageNameFromUid(int clientUid) const {
+        return mAttributionAndPermissionUtils->getPackageNameFromUid(clientUid);
+    }
+
     bool isCallerCameraServerNotDelegating() const {
         return mAttributionAndPermissionUtils->isCallerCameraServerNotDelegating();
     }
@@ -254,4 +295,4 @@
 
 } // namespace android
 
-#endif // ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
+#endif  // ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
diff --git a/services/camera/libcameraservice/utils/Utils.cpp b/services/camera/libcameraservice/utils/Utils.cpp
index 76517dc..5f61de5 100644
--- a/services/camera/libcameraservice/utils/Utils.cpp
+++ b/services/camera/libcameraservice/utils/Utils.cpp
@@ -25,44 +25,7 @@
 
 namespace android {
 
-namespace flags = com::android::internal::camera::flags;
-
-namespace {
-constexpr const char* LEGACY_VNDK_VERSION_PROP = "ro.vndk.version";
-constexpr const char* BOARD_API_LEVEL_PROP = "ro.board.api_level";
-constexpr int MAX_VENDOR_API_LEVEL = 1000000;
-constexpr int FIRST_VNDK_VERSION = 202404;
-
-int legacyGetVNDKVersionFromProp(int defaultVersion) {
-    if (!flags::use_ro_board_api_level_for_vndk_version()) {
-        return base::GetIntProperty(LEGACY_VNDK_VERSION_PROP, defaultVersion);
-    }
-
-    int vndkVersion = base::GetIntProperty(BOARD_API_LEVEL_PROP, MAX_VENDOR_API_LEVEL);
-
-    if (vndkVersion == MAX_VENDOR_API_LEVEL) {
-        // Couldn't find property
-        return defaultVersion;
-    }
-
-    if (vndkVersion < __ANDROID_API_V__) {
-        // VNDK versions below V return the corresponding SDK version.
-        return vndkVersion;
-    }
-
-    // VNDK for Android V and above are of the format YYYYMM starting with 202404 and is bumped
-    // up once a year. So V would be 202404 and the next one would be 202504.
-    // This is the same assumption as that made in system/core/init/property_service.cpp.
-    vndkVersion = (vndkVersion - FIRST_VNDK_VERSION) / 100;
-    return __ANDROID_API_V__ + vndkVersion;
-}
-}  // anonymous namespace
-
 int getVNDKVersionFromProp(int defaultVersion) {
-    if (!flags::use_system_api_for_vndk_version()) {
-        return legacyGetVNDKVersionFromProp(defaultVersion);
-    }
-
     int vendorApiLevel = AVendorSupport_getVendorApiLevel();
     if (vendorApiLevel == 0) {
         // Couldn't find vendor API level, return default
@@ -77,28 +40,26 @@
 
 RunThreadWithRealtimePriority::RunThreadWithRealtimePriority(int tid)
     : mTid(tid), mPreviousPolicy(sched_getscheduler(tid)) {
-    if (flags::realtime_priority_bump()) {
-        auto res = sched_getparam(mTid, &mPreviousParams);
-        if (res != OK) {
-            ALOGE("Can't retrieve thread scheduler parameters: %s (%d)", strerror(-res), res);
-            return;
-        }
+    auto res = sched_getparam(mTid, &mPreviousParams);
+    if (res != OK) {
+        ALOGE("Can't retrieve thread scheduler parameters: %s (%d)", strerror(-res), res);
+        return;
+    }
 
-        struct sched_param param = {0};
-        param.sched_priority = kRequestThreadPriority;
+    struct sched_param param = {0};
+    param.sched_priority = kRequestThreadPriority;
 
-        res = sched_setscheduler(mTid, SCHED_FIFO, &param);
-        if (res != OK) {
-            ALOGW("Can't set realtime priority for thread: %s (%d)", strerror(-res), res);
-        } else {
-            ALOGD("Set real time priority for thread (tid %d)", mTid);
-            mPolicyBumped = true;
-        }
+    res = sched_setscheduler(mTid, SCHED_FIFO, &param);
+    if (res != OK) {
+        ALOGW("Can't set realtime priority for thread: %s (%d)", strerror(-res), res);
+    } else {
+        ALOGD("Set real time priority for thread (tid %d)", mTid);
+        mPolicyBumped = true;
     }
 }
 
 RunThreadWithRealtimePriority::~RunThreadWithRealtimePriority() {
-    if (mPolicyBumped && flags::realtime_priority_bump()) {
+    if (mPolicyBumped) {
         auto res = sched_setscheduler(mTid, mPreviousPolicy, &mPreviousParams);
         if (res != OK) {
             ALOGE("Can't set regular priority for thread: %s (%d)", strerror(-res), res);
diff --git a/services/camera/virtualcamera/Android.bp b/services/camera/virtualcamera/Android.bp
index 7ece0cb..dd64daa 100644
--- a/services/camera/virtualcamera/Android.bp
+++ b/services/camera/virtualcamera/Android.bp
@@ -25,6 +25,7 @@
         "libEGL",
         "libGLESv2",
         "libGLESv3",
+        "android.companion.virtualdevice.flags-aconfig-cc",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 40a96e4..becba90 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
+// #define LOG_NDEBUG 0
 #define LOG_TAG "VirtualCameraRenderThread"
 #include "VirtualCameraRenderThread.h"
 
+#include <android_companion_virtualdevice_flags.h>
+
 #include <chrono>
 #include <cstdint>
 #include <cstring>
@@ -46,13 +49,11 @@
 #include "android-base/thread_annotations.h"
 #include "android/binder_auto_utils.h"
 #include "android/hardware_buffer.h"
-#include "hardware/gralloc.h"
 #include "system/camera_metadata.h"
 #include "ui/GraphicBuffer.h"
 #include "ui/Rect.h"
 #include "util/EglFramebuffer.h"
 #include "util/JpegUtil.h"
-#include "util/MetadataUtil.h"
 #include "util/Util.h"
 #include "utils/Errors.h"
 
@@ -91,6 +92,8 @@
 
 using namespace std::chrono_literals;
 
+namespace flags = ::android::companion::virtualdevice::flags;
+
 static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
 
 static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024;  // 32 KiB
@@ -117,12 +120,12 @@
 
 NotifyMsg createRequestErrorNotifyMsg(int frameNumber) {
   NotifyMsg msg;
-  msg.set<NotifyMsg::Tag::error>(ErrorMsg{
-      .frameNumber = frameNumber,
-      // errorStreamId needs to be set to -1 for ERROR_REQUEST
-      // (not tied to specific stream).
-      .errorStreamId = -1,
-      .errorCode = ErrorCode::ERROR_REQUEST});
+  msg.set<NotifyMsg::Tag::error>(
+      ErrorMsg{.frameNumber = frameNumber,
+               // errorStreamId needs to be set to -1 for ERROR_REQUEST
+               // (not tied to specific stream).
+               .errorStreamId = -1,
+               .errorCode = ErrorCode::ERROR_REQUEST});
   return msg;
 }
 
@@ -413,29 +416,8 @@
                                                     std::memory_order_relaxed));
 
   if (request.getRequestSettings().fpsRange) {
-    const int maxFps =
-        std::max(1, request.getRequestSettings().fpsRange->maxFps);
-    const std::chrono::nanoseconds minFrameDuration(
-        static_cast<uint64_t>(1e9 / maxFps));
-    const std::chrono::nanoseconds frameDuration =
-        timestamp - lastAcquisitionTimestamp;
-    if (frameDuration < minFrameDuration) {
-      // We're too fast for the configured maxFps, let's wait a bit.
-      const std::chrono::nanoseconds sleepTime =
-          minFrameDuration - frameDuration;
-      ALOGV("Current frame duration would  be %" PRIu64
-            " ns corresponding to, "
-            "sleeping for %" PRIu64
-            " ns before updating texture to match maxFps %d",
-            static_cast<uint64_t>(frameDuration.count()),
-            static_cast<uint64_t>(sleepTime.count()), maxFps);
-
-      std::this_thread::sleep_for(sleepTime);
-      timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
-          std::chrono::steady_clock::now().time_since_epoch());
-      mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
-                                                 std::memory_order_relaxed);
-    }
+    int maxFps = std::max(1, request.getRequestSettings().fpsRange->maxFps);
+    timestamp = throttleRendering(maxFps, lastAcquisitionTimestamp, timestamp);
   }
 
   // Calculate the maximal amount of time we can afford to wait for next frame.
@@ -463,6 +445,17 @@
   }
   // Acquire new (most recent) image from the Surface.
   mEglSurfaceTexture->updateTexture();
+  std::chrono::nanoseconds captureTimestamp = timestamp;
+
+  if (flags::camera_timestamp_from_surface()) {
+    std::chrono::nanoseconds surfaceTimestamp =
+        getSurfaceTimestamp(elapsedDuration);
+    if (surfaceTimestamp.count() > 0) {
+      captureTimestamp = surfaceTimestamp;
+    }
+    ALOGV("%s captureTimestamp:%lld timestamp:%lld", __func__,
+          captureTimestamp.count(), timestamp.count());
+  }
 
   CaptureResult captureResult;
   captureResult.fmqResultSize = 0;
@@ -472,7 +465,7 @@
   captureResult.inputBuffer.streamId = -1;
   captureResult.physicalCameraMetadata.resize(0);
   captureResult.result = createCaptureResultMetadata(
-      timestamp, request.getRequestSettings(), mReportedSensorSize);
+      captureTimestamp, request.getRequestSettings(), mReportedSensorSize);
 
   const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
   captureResult.outputBuffers.resize(buffers.size());
@@ -506,7 +499,7 @@
   }
 
   std::vector<NotifyMsg> notifyMsg{
-      createShutterNotifyMsg(request.getFrameNumber(), timestamp)};
+      createShutterNotifyMsg(request.getFrameNumber(), captureTimestamp)};
   for (const StreamBuffer& resBuffer : captureResult.outputBuffers) {
     if (resBuffer.status != BufferStatus::OK) {
       notifyMsg.push_back(createBufferErrorNotifyMsg(request.getFrameNumber(),
@@ -535,6 +528,52 @@
   ALOGV("%s: Successfully called processCaptureResult", __func__);
 }
 
+std::chrono::nanoseconds VirtualCameraRenderThread::throttleRendering(
+    int maxFps, std::chrono::nanoseconds lastAcquisitionTimestamp,
+    std::chrono::nanoseconds timestamp) {
+  const std::chrono::nanoseconds minFrameDuration(
+      static_cast<uint64_t>(1e9 / maxFps));
+  const std::chrono::nanoseconds frameDuration =
+      timestamp - lastAcquisitionTimestamp;
+  if (frameDuration < minFrameDuration) {
+    // We're too fast for the configured maxFps, let's wait a bit.
+    const std::chrono::nanoseconds sleepTime = minFrameDuration - frameDuration;
+    ALOGV("Current frame duration would  be %" PRIu64
+          " ns corresponding to, "
+          "sleeping for %" PRIu64
+          " ns before updating texture to match maxFps %d",
+          static_cast<uint64_t>(frameDuration.count()),
+          static_cast<uint64_t>(sleepTime.count()), maxFps);
+
+    std::this_thread::sleep_for(sleepTime);
+    timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
+        std::chrono::steady_clock::now().time_since_epoch());
+    mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
+                                               std::memory_order_relaxed);
+  }
+  return timestamp;
+}
+
+std::chrono::nanoseconds VirtualCameraRenderThread::getSurfaceTimestamp(
+    std::chrono::nanoseconds timeSinceLastFrame) {
+  std::chrono::nanoseconds surfaceTimestamp = mEglSurfaceTexture->getTimestamp();
+  uint64_t lastSurfaceTimestamp = mLastSurfaceTimestampNanoseconds.load();
+  if (surfaceTimestamp.count() < 0 ||
+      surfaceTimestamp.count() == lastSurfaceTimestamp) {
+    if (lastSurfaceTimestamp > 0) {
+      // The timestamps were provided by the producer but we are
+      // repeating the last frame, so we increase the previous timestamp by
+      // the elapsed time sinced its capture, otherwise the camera framework
+      // will discard the frame.
+      surfaceTimestamp = std::chrono::nanoseconds(lastSurfaceTimestamp +
+                                                  timeSinceLastFrame.count());
+    }
+  }
+  mLastSurfaceTimestampNanoseconds.store(surfaceTimestamp.count(),
+                                         std::memory_order_relaxed);
+  return surfaceTimestamp;
+}
+
 void VirtualCameraRenderThread::flushCaptureRequest(
     const ProcessCaptureRequestTask& request) {
   CaptureResult captureResult;
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index aafed44..a35eea1 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -18,6 +18,7 @@
 #define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERARENDERTHREAD_H
 
 #include <atomic>
+#include <chrono>
 #include <cstdint>
 #include <deque>
 #include <future>
@@ -188,6 +189,22 @@
       EglFrameBuffer& framebuffer, sp<Fence> fence = nullptr,
       std::optional<Rect> viewport = std::nullopt);
 
+  // Throttle the current thread to ensure that we are not rendering faster than
+  // the provided maxFps.
+  // maxFps: The maximum fps in the capture request
+  // lastAcquisitionTimestamp: timestamp of the previous frame
+  // timestamp: the current capture time
+  // Returns the time at which the capture has happened after throttling.
+  std::chrono::nanoseconds throttleRendering(
+      int maxFps, std::chrono::nanoseconds lastAcquisitionTimestamp,
+      std::chrono::nanoseconds timestamp);
+
+  // Fetch the timestamp of the latest buffer from the EGL Surface
+  // timeSinceLastFrame: The elapsed time since the last captured frame.
+  // Return 0 if no timestamp has been associated to this surface by the producer.
+  std::chrono::nanoseconds getSurfaceTimestamp(
+      std::chrono::nanoseconds timeSinceLastFrame);
+
   // Camera callback
   const std::shared_ptr<
       ::aidl::android::hardware::camera::device::ICameraDeviceCallback>
@@ -209,6 +226,7 @@
 
   // Acquisition timestamp of last frame.
   std::atomic<uint64_t> mLastAcquisitionTimestampNanoseconds;
+  std::atomic<uint64_t> mLastSurfaceTimestampNanoseconds;
 
   // EGL helpers - constructed and accessed only from rendering thread.
   std::unique_ptr<EglDisplayContext> mEglDisplayContext;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 98bf62a..be36ec4 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -15,6 +15,8 @@
  */
 
 // #define LOG_NDEBUG 0
+#include <chrono>
+
 #include "utils/Timers.h"
 #define LOG_TAG "EglSurfaceTexture"
 
@@ -99,6 +101,10 @@
                                     static_cast<nsecs_t>(timeout.count()));
 }
 
+std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() {
+  return std::chrono::nanoseconds(mGlConsumer->getTimestamp());
+}
+
 GLuint EglSurfaceTexture::updateTexture() {
   int previousFrameId;
   int framesAdvance = 0;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index a46af8f..c1f1169 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -82,6 +82,10 @@
   // See SurfaceTexture.getTransformMatrix for more details.
   std::array<float, 16> getTransformMatrix();
 
+  // Retrieves the timestamp associated with the texture image
+  // set by the most recent call to updateTexture.
+  std::chrono::nanoseconds getTimestamp();
+
  private:
 #if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
   sp<IGraphicBufferProducer> mBufferProducer;
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index bd4ac38..c01d46e 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -555,22 +555,24 @@
 }
 
 std::pair<std::string, int32_t> AudioAnalytics::dump(
-        int32_t lines, int64_t sinceNs, const char *prefix) const
+        bool details, int32_t lines, int64_t sinceNs, const char *prefix) const
 {
     std::stringstream ss;
     int32_t ll = lines;
 
     if (ll > 0) {
-        auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
+        auto [s, l] = mAnalyticsState->dump(details, ll, sinceNs, prefix);
         ss << s;
         ll -= l;
     }
-    if (ll > 0) {
+
+    // use details to dump prior state.
+    if (details && ll > 0) {
         ss << "Prior audioserver state:\n";
         --ll;
     }
-    if (ll > 0) {
-        auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
+    if (details && ll > 0) {
+        auto [s, l] = mPreviousAnalyticsState->dump(details, ll, sinceNs, prefix);
         ss << s;
         ll -= l;
     }
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index f81db53..2ec4ac8 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -49,12 +49,9 @@
 // (0 for either of these disables that threshold)
 //
 static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * NANOS_PER_SECOND;
-// 2019/6: average daily per device is currently 375-ish;
-// setting this to 2000 is large enough to catch most devices
-// we'll lose some data on very very media-active devices, but only for
-// the gms collection; statsd will have already covered those for us.
-// This also retains enough information to help with bugreports
-static constexpr size_t kMaxRecords = 2000;
+
+// Max records to keep in queue which dump out for bugreports.
+static constexpr size_t kMaxRecords = 2500;
 
 // max we expire in a single call, to constrain how long we hold the
 // mutex, which also constrains how long a client might wait.
@@ -92,16 +89,12 @@
 /* static */
 std::pair<std::string, int64_t>
 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid_t uid) {
-    // Meyer's singleton, initialized on first access.
-    // mUidInfo is locked internally.
-    static mediautils::UidInfo uidInfo;
-
-    // get info.
-    mediautils::UidInfo::Info info = uidInfo.getInfo(uid);
-    if (useUidForPackage(info.package, info.installer)) {
+    const std::shared_ptr<const mediautils::UidInfo::Info> info =
+            mediautils::UidInfo::getInfo(uid);
+    if (useUidForPackage(info->package, info->installer)) {
         return { std::to_string(uid), /* versionCode */ 0 };
     } else {
-        return { info.package, info.versionCode };
+        return { info->package, info->versionCode };
     }
 }
 
@@ -315,7 +308,8 @@
 
             // TODO: maybe consider a better way of dumping audio analytics info.
             const int32_t linesToDump = all ? INT32_MAX : 1000;
-            auto [ dumpString, lines ] = mAudioAnalytics.dump(linesToDump, sinceNs, prefixptr);
+            auto [ dumpString, lines ] = mAudioAnalytics.dump(
+                    all, linesToDump, sinceNs, prefixptr);
             result << dumpString;
             if (lines == linesToDump) {
                 result << "-- some lines may be truncated --\n";
diff --git a/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
index c7468c7..572e969 100644
--- a/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
@@ -22,6 +22,7 @@
 using ::android::MediaMetricsService;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    signal(SIGPIPE, SIG_IGN);
     auto service = sp<MediaMetricsService>::make();
     fuzzService(service, FuzzedDataProvider(data, size));
     return 0;
diff --git a/services/mediametrics/include/mediametricsservice/AnalyticsState.h b/services/mediametrics/include/mediametricsservice/AnalyticsState.h
index 09c0b4c..1dabe5d 100644
--- a/services/mediametrics/include/mediametricsservice/AnalyticsState.h
+++ b/services/mediametrics/include/mediametricsservice/AnalyticsState.h
@@ -83,11 +83,12 @@
      * different locks, so may not be 100% consistent with the last data
      * delivered.
      *
+     * \param details dumps the detailed internal state.
      * \param lines the maximum number of lines in the string returned.
      * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
      * \param prefix the desired key prefix to match (nullptr shows all)
      */
-    std::pair<std::string, int32_t> dump(
+    std::pair<std::string, int32_t> dump(bool details,
             int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const {
         std::stringstream ss;
         int32_t ll = lines;
@@ -96,7 +97,7 @@
             ss << "TransactionLog: gc(" << mTransactionLog.getGarbageCollectionCount() << ")\n";
             --ll;
         }
-        if (ll > 0) {
+        if (details && ll > 0) {
             auto [s, l] = mTransactionLog.dump(ll, sinceNs, prefix);
             ss << s;
             ll -= l;
@@ -105,7 +106,7 @@
             ss << "TimeMachine: gc(" << mTimeMachine.getGarbageCollectionCount() << ")\n";
             --ll;
         }
-        if (ll > 0) {
+        if (details && ll > 0) {
             auto [s, l] = mTimeMachine.dump(ll, sinceNs, prefix);
             ss << s;
             ll -= l;
diff --git a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
index f0a4ac8..57f55c1 100644
--- a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
+++ b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
@@ -67,11 +67,12 @@
      * different locks, so may not be 100% consistent with the last data
      * delivered.
      *
+     * \param details dumps the detailed internal state.
      * \param lines the maximum number of lines in the string returned.
      * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
      * \param prefix the desired key prefix to match (nullptr shows all)
      */
-    std::pair<std::string, int32_t> dump(
+    std::pair<std::string, int32_t> dump(bool details,
             int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const;
 
     /**
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 4a6aee4..a7684f4 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -850,14 +850,14 @@
 
   // TODO: Verify contents of AudioAnalytics.
   // Currently there is no getter API in AudioAnalytics besides dump.
-  ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
+  ASSERT_EQ(10, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
 
   ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
   // untrusted entities can add to an existing key
   ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
 
   // Check that we have some info in the dump.
-  ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+  ASSERT_LT(9, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
 }
 
 TEST(mediametrics_tests, audio_analytics_permission2) {
@@ -888,14 +888,14 @@
 
   // TODO: Verify contents of AudioAnalytics.
   // Currently there is no getter API in AudioAnalytics besides dump.
-  ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
+  ASSERT_EQ(10, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
 
   ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
   // untrusted entities can add to an existing key
   ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
 
   // Check that we have some info in the dump.
-  ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+  ASSERT_LT(9, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
 }
 
 TEST(mediametrics_tests, audio_analytics_dump) {
@@ -922,13 +922,13 @@
   ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item3, true /* isTrusted */));
 
   // find out how many lines we have.
-  auto [string, lines] = audioAnalytics.dump(1000);
+  auto [string, lines] = audioAnalytics.dump(true /* details */, 1000);
   ASSERT_EQ(lines, (int32_t) countNewlines(string.c_str()));
 
   printf("AudioAnalytics: %s", string.c_str());
   // ensure that dump operates over those lines.
   for (int32_t ll = 0; ll < lines; ++ll) {
-      auto [s, l] = audioAnalytics.dump(ll);
+      auto [s, l] = audioAnalytics.dump(true /* details */, ll);
       ASSERT_EQ(ll, l);
       ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
   }
diff --git a/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp b/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
index 6253df7..1cad482 100644
--- a/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
+++ b/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
@@ -26,6 +26,7 @@
 using ndk::SharedRefBase;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+   signal(SIGPIPE, SIG_IGN);
    std::shared_ptr<ResourceManagerService> service = ResourceManagerService::Create();
    fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
    return 0;
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index 84a2b4e..e393c44 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -335,26 +335,40 @@
 
 /////////////// FilterCallback ///////////////////////
 ::ndk::ScopedAStatus TunerFilter::FilterCallback::onFilterStatus(DemuxFilterStatus status) {
-    Mutex::Autolock _l(mCallbackLock);
-    if (mTunerFilterCallback != nullptr) {
-        mTunerFilterCallback->onFilterStatus(status);
+    shared_ptr<ITunerFilterCallback> cb(nullptr);
+    {
+        Mutex::Autolock _l(mCallbackLock);
+        cb = mTunerFilterCallback;
+    }
+    if (cb != nullptr) {
+        cb->onFilterStatus(status);
     }
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus TunerFilter::FilterCallback::onFilterEvent(
         const vector<DemuxFilterEvent>& events) {
-    Mutex::Autolock _l(mCallbackLock);
-    if (mTunerFilterCallback != nullptr) {
-        mTunerFilterCallback->onFilterEvent(events);
+    shared_ptr<ITunerFilterCallback> cb(nullptr);
+    {
+        Mutex::Autolock _l(mCallbackLock);
+        cb = mTunerFilterCallback;
+    }
+    if (cb != nullptr) {
+        cb->onFilterEvent(events);
     }
     return ::ndk::ScopedAStatus::ok();
 }
 
 void TunerFilter::FilterCallback::sendSharedFilterStatus(int32_t status) {
-    Mutex::Autolock _l(mCallbackLock);
-    if (mTunerFilterCallback != nullptr && mOriginalCallback != nullptr) {
-        mTunerFilterCallback->onFilterStatus(static_cast<DemuxFilterStatus>(status));
+    shared_ptr<ITunerFilterCallback> cb(nullptr);
+    shared_ptr<ITunerFilterCallback> orig_cb(nullptr);
+    {
+        Mutex::Autolock _l(mCallbackLock);
+        cb = mTunerFilterCallback;
+        orig_cb = mOriginalCallback;
+    }
+    if (cb != nullptr && orig_cb != nullptr) {
+        cb->onFilterStatus(static_cast<DemuxFilterStatus>(status));
     }
 }
 
diff --git a/services/tuner/TunerHelper.cpp b/services/tuner/TunerHelper.cpp
index a03386f..8357a9e 100644
--- a/services/tuner/TunerHelper.cpp
+++ b/services/tuner/TunerHelper.cpp
@@ -73,7 +73,7 @@
 
 // TODO: update Demux, Descrambler.
 void TunerHelper::updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
-                                       const vector<int32_t>& lnbHandles) {
+                                       const vector<int64_t>& lnbHandles) {
     ::ndk::SpAIBinder binder(AServiceManager_waitForService("tv_tuner_resource_mgr"));
     shared_ptr<ITunerResourceManager> tunerRM = ITunerResourceManager::fromBinder(binder);
     if (tunerRM == nullptr) {
@@ -85,7 +85,7 @@
 }
 void TunerHelper::updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
                                        const vector<TunerDemuxInfo>& demuxInfos,
-                                       const vector<int32_t>& lnbHandles) {
+                                       const vector<int64_t>& lnbHandles) {
     ::ndk::SpAIBinder binder(AServiceManager_waitForService("tv_tuner_resource_mgr"));
     shared_ptr<ITunerResourceManager> tunerRM = ITunerResourceManager::fromBinder(binder);
     if (tunerRM == nullptr) {
@@ -101,13 +101,22 @@
 }
 
 // TODO: create a map between resource id and handles.
-int TunerHelper::getResourceIdFromHandle(int resourceHandle, int /*type*/) {
-    return (resourceHandle & 0x00ff0000) >> 16;
+int TunerHelper::getResourceIdFromHandle(long resourceHandle, int /*type*/) {
+    return (int)((resourceHandle >> RESOURCE_ID_SHIFT) & RESOURCE_ID_MASK);
 }
 
-int TunerHelper::getResourceHandleFromId(int id, int resourceType) {
+/**
+ *   Generate resource handle for resourceType and id
+ *   Resource Handle Allotment : 64 bits (long)
+ *   8 bits - resourceType
+ *   32 bits - id
+ *   24 bits - resourceRequestCount
+ */
+long TunerHelper::getResourceHandleFromId(int id, int resourceType) {
     // TODO: build up randomly generated id to handle mapping
-    return (resourceType & 0x000000ff) << 24 | (id << 16) | (sResourceRequestCount++ & 0xffff);
+    return static_cast<int64_t>(resourceType & RESOURCE_TYPE_MASK) << RESOURCE_TYPE_SHIFT |
+           static_cast<int64_t>(id & RESOURCE_ID_MASK) << RESOURCE_ID_SHIFT |
+           (sResourceRequestCount++ & RESOURCE_COUNT_MASK);
 }
 
 }  // namespace tuner
diff --git a/services/tuner/TunerHelper.h b/services/tuner/TunerHelper.h
index 65a9b0b..74e1662 100644
--- a/services/tuner/TunerHelper.h
+++ b/services/tuner/TunerHelper.h
@@ -56,17 +56,23 @@
 
     // TODO: update Demux, Descrambler.
     static void updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
-                                     const vector<int32_t>& lnbHandles);
+                                     const vector<int64_t>& lnbHandles);
 
     static void updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
                                      const vector<TunerDemuxInfo>& demuxInfos,
-                                     const vector<int32_t>& lnbHandles);
+                                     const vector<int64_t>& lnbHandles);
     // TODO: create a map between resource id and handles.
-    static int getResourceIdFromHandle(int resourceHandle, int type);
-    static int getResourceHandleFromId(int id, int resourceType);
+    static int getResourceIdFromHandle(long resourceHandle, int type);
+    static long getResourceHandleFromId(int id, int resourceType);
 
 private:
     static int32_t sResourceRequestCount;
+
+    static constexpr uint32_t RESOURCE_ID_SHIFT = 24;
+    static constexpr uint32_t RESOURCE_TYPE_SHIFT = 56;
+    static constexpr uint32_t RESOURCE_COUNT_MASK = 0xffffff;
+    static constexpr uint32_t RESOURCE_ID_MASK = 0xffffffff;
+    static constexpr uint32_t RESOURCE_TYPE_MASK = 0xff;
 };
 
 }  // namespace tuner
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 9a1e8bb..8cf84e2 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -82,7 +82,7 @@
     return AServiceManager_addService(tunerService->asBinder().get(), getServiceName());
 }
 
-::ndk::ScopedAStatus TunerService::openDemux(int32_t in_demuxHandle,
+::ndk::ScopedAStatus TunerService::openDemux(int64_t in_demuxHandle,
                                              shared_ptr<ITunerDemux>* _aidl_return) {
     ALOGV("openDemux");
     shared_ptr<IDemux> demux;
@@ -116,7 +116,7 @@
     }
 }
 
-::ndk::ScopedAStatus TunerService::getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) {
+::ndk::ScopedAStatus TunerService::getDemuxInfo(int64_t in_demuxHandle, DemuxInfo* _aidl_return) {
     if (mTunerVersion <= TUNER_HAL_VERSION_2_0) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(Result::UNAVAILABLE));
@@ -169,7 +169,7 @@
     return mTuner->getFrontendInfo(id, _aidl_return);
 }
 
-::ndk::ScopedAStatus TunerService::openFrontend(int32_t frontendHandle,
+::ndk::ScopedAStatus TunerService::openFrontend(int64_t frontendHandle,
                                                 shared_ptr<ITunerFrontend>* _aidl_return) {
     int id = TunerHelper::getResourceIdFromHandle(frontendHandle, FRONTEND);
     shared_ptr<IFrontend> frontend;
@@ -181,7 +181,7 @@
     return status;
 }
 
-::ndk::ScopedAStatus TunerService::openLnb(int lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) {
+::ndk::ScopedAStatus TunerService::openLnb(int64_t lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) {
     shared_ptr<ILnb> lnb;
     int id = TunerHelper::getResourceIdFromHandle(lnbHandle, LNB);
     auto status = mTuner->openLnbById(id, &lnb);
@@ -204,7 +204,7 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus TunerService::openDescrambler(int32_t /*descramblerHandle*/,
+::ndk::ScopedAStatus TunerService::openDescrambler(int64_t /*descramblerHandle*/,
                                                    shared_ptr<ITunerDescrambler>* _aidl_return) {
     shared_ptr<IDescrambler> descrambler;
     // int id = TunerHelper::getResourceIdFromHandle(descramblerHandle, DESCRAMBLER);
@@ -310,7 +310,7 @@
             continue;
         }
         TunerFrontendInfo tunerFrontendInfo{
-                .handle = TunerHelper::getResourceHandleFromId((int)ids[i], FRONTEND),
+                .handle = TunerHelper::getResourceHandleFromId(ids[i], FRONTEND),
                 .type = static_cast<int>(frontendInfo.type),
                 .exclusiveGroupId = frontendInfo.exclusiveGroupId,
         };
@@ -336,18 +336,16 @@
     for (int i = 0; i < ids.size(); i++) {
         DemuxInfo demuxInfo;
         mTuner->getDemuxInfo(ids[i], &demuxInfo);
-        TunerDemuxInfo tunerDemuxInfo{
-                .handle = TunerHelper::getResourceHandleFromId((int)ids[i], DEMUX),
-                .filterTypes = static_cast<int>(demuxInfo.filterTypes)
-        };
+        TunerDemuxInfo tunerDemuxInfo{.handle = TunerHelper::getResourceHandleFromId(ids[i], DEMUX),
+                                      .filterTypes = static_cast<int>(demuxInfo.filterTypes)};
         infos.push_back(tunerDemuxInfo);
     }
 
     return infos;
 }
 
-vector<int32_t> TunerService::getTRMLnbHandles() {
-    vector<int32_t> lnbHandles;
+vector<int64_t> TunerService::getTRMLnbHandles() {
+    vector<int64_t> lnbHandles;
     if (mTuner != nullptr) {
         vector<int32_t> lnbIds;
         auto res = mTuner->getLnbIds(&lnbIds);
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
index 190ccd4..07b414e 100644
--- a/services/tuner/TunerService.h
+++ b/services/tuner/TunerService.h
@@ -61,20 +61,20 @@
     virtual ~TunerService();
 
     ::ndk::ScopedAStatus getFrontendIds(vector<int32_t>* out_ids) override;
-    ::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendHandle,
+    ::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendId,
                                          FrontendInfo* _aidl_return) override;
-    ::ndk::ScopedAStatus openFrontend(int32_t in_frontendHandle,
+    ::ndk::ScopedAStatus openFrontend(int64_t in_frontendHandle,
                                       shared_ptr<ITunerFrontend>* _aidl_return) override;
-    ::ndk::ScopedAStatus openLnb(int32_t in_lnbHandle,
+    ::ndk::ScopedAStatus openLnb(int64_t in_lnbHandle,
                                  shared_ptr<ITunerLnb>* _aidl_return) override;
     ::ndk::ScopedAStatus openLnbByName(const string& in_lnbName,
                                        shared_ptr<ITunerLnb>* _aidl_return) override;
-    ::ndk::ScopedAStatus openDemux(int32_t in_demuxHandle,
+    ::ndk::ScopedAStatus openDemux(int64_t in_demuxHandle,
                                    shared_ptr<ITunerDemux>* _aidl_return) override;
     ::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
-    ::ndk::ScopedAStatus getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) override;
+    ::ndk::ScopedAStatus getDemuxInfo(int64_t in_demuxHandle, DemuxInfo* _aidl_return) override;
     ::ndk::ScopedAStatus getDemuxInfoList(vector<DemuxInfo>* _aidl_return) override;
-    ::ndk::ScopedAStatus openDescrambler(int32_t in_descramblerHandle,
+    ::ndk::ScopedAStatus openDescrambler(int64_t in_descramblerHandle,
                                          shared_ptr<ITunerDescrambler>* _aidl_return) override;
     ::ndk::ScopedAStatus getTunerHalVersion(int32_t* _aidl_return) override;
     ::ndk::ScopedAStatus openSharedFilter(const string& in_filterToken,
@@ -94,7 +94,7 @@
     void updateTunerResources();
     vector<TunerFrontendInfo> getTRMFrontendInfos();
     vector<TunerDemuxInfo> getTRMDemuxInfos();
-    vector<int32_t> getTRMLnbHandles();
+    vector<int64_t> getTRMLnbHandles();
 
     shared_ptr<ITuner> mTuner;
     int mTunerVersion = TUNER_HAL_VERSION_UNKNOWN;
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
index 932133e..0d23817 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
@@ -54,7 +54,7 @@
      * @param frontendHandle the handle of the frontend granted by TRM.
      * @return the aidl interface of the frontend.
      */
-    ITunerFrontend openFrontend(in int frontendHandle);
+    ITunerFrontend openFrontend(in long frontendHandle);
 
     /**
      * Open a new interface of ITunerLnb given a lnbHandle.
@@ -62,7 +62,7 @@
      * @param lnbHandle the handle of the LNB granted by TRM.
      * @return a newly created ITunerLnb interface.
      */
-    ITunerLnb openLnb(in int lnbHandle);
+    ITunerLnb openLnb(in long lnbHandle);
 
     /**
      * Open a new interface of ITunerLnb given a LNB name.
@@ -75,7 +75,7 @@
     /**
      * Create a new instance of Demux.
      */
-    ITunerDemux openDemux(in int demuxHandle);
+    ITunerDemux openDemux(in long demuxHandle);
 
     /**
      * Retrieve the supported filter main types
@@ -83,7 +83,7 @@
      * @param demuxHandle the handle of the demux to query demux info for
      * @return the demux info
      */
-    DemuxInfo getDemuxInfo(in int demuxHandle);
+    DemuxInfo getDemuxInfo(in long demuxHandle);
 
     /**
      * Retrieve the list of demux info for all the demuxes on the system
@@ -104,7 +104,7 @@
      * @param descramblerHandle the handle of the descrambler granted by TRM.
      * @return a newly created ITunerDescrambler interface.
      */
-    ITunerDescrambler openDescrambler(in int descramblerHandle);
+    ITunerDescrambler openDescrambler(in long descramblerHandle);
 
     /**
      * Get an integer that carries the Tuner HIDL version. The high 16 bits are the
diff --git a/services/tuner/hidl/TunerHidlService.cpp b/services/tuner/hidl/TunerHidlService.cpp
index 6bc36be..1b6b032 100644
--- a/services/tuner/hidl/TunerHidlService.cpp
+++ b/services/tuner/hidl/TunerHidlService.cpp
@@ -101,7 +101,7 @@
     return AServiceManager_addService(tunerService->asBinder().get(), getServiceName());
 }
 
-::ndk::ScopedAStatus TunerHidlService::openDemux(int32_t /* in_demuxHandle */,
+::ndk::ScopedAStatus TunerHidlService::openDemux(int64_t /* in_demuxHandle */,
                                                  shared_ptr<ITunerDemux>* _aidl_return) {
     ALOGV("openDemux");
     HidlResult res;
@@ -123,7 +123,7 @@
     return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
 }
 
-::ndk::ScopedAStatus TunerHidlService::getDemuxInfo(int32_t /* in_demuxHandle */,
+::ndk::ScopedAStatus TunerHidlService::getDemuxInfo(int64_t /* in_demuxHandle */,
                                                     DemuxInfo* /* _aidl_return */) {
     ALOGE("getDemuxInfo is not supported");
     return ::ndk::ScopedAStatus::fromServiceSpecificError(
@@ -195,7 +195,7 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus TunerHidlService::openFrontend(int32_t frontendHandle,
+::ndk::ScopedAStatus TunerHidlService::openFrontend(int64_t frontendHandle,
                                                     shared_ptr<ITunerFrontend>* _aidl_return) {
     HidlResult status;
     sp<HidlIFrontend> frontend;
@@ -221,7 +221,8 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus TunerHidlService::openLnb(int lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) {
+::ndk::ScopedAStatus TunerHidlService::openLnb(int64_t lnbHandle,
+                                               shared_ptr<ITunerLnb>* _aidl_return) {
     HidlResult status;
     sp<HidlILnb> lnb;
     int id = TunerHelper::getResourceIdFromHandle(lnbHandle, LNB);
@@ -256,7 +257,7 @@
 }
 
 ::ndk::ScopedAStatus TunerHidlService::openDescrambler(
-        int32_t /*descramblerHandle*/, shared_ptr<ITunerDescrambler>* _aidl_return) {
+        int64_t /*descramblerHandle*/, shared_ptr<ITunerDescrambler>* _aidl_return) {
     HidlResult status;
     sp<HidlIDescrambler> descrambler;
     //int id = TunerHelper::getResourceIdFromHandle(descramblerHandle, DESCRAMBLER);
@@ -410,8 +411,8 @@
     return infos;
 }
 
-vector<int32_t> TunerHidlService::getTRMLnbHandles() {
-    vector<int32_t> lnbHandles;
+vector<int64_t> TunerHidlService::getTRMLnbHandles() {
+    vector<int64_t> lnbHandles;
     if (mTuner != nullptr) {
         HidlResult res;
         vector<HidlLnbId> lnbIds;
diff --git a/services/tuner/hidl/TunerHidlService.h b/services/tuner/hidl/TunerHidlService.h
index 526c5e6..1973a77 100644
--- a/services/tuner/hidl/TunerHidlService.h
+++ b/services/tuner/hidl/TunerHidlService.h
@@ -73,20 +73,19 @@
     virtual ~TunerHidlService();
 
     ::ndk::ScopedAStatus getFrontendIds(vector<int32_t>* out_ids) override;
-    ::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendHandle,
-                                         FrontendInfo* _aidl_return) override;
-    ::ndk::ScopedAStatus openFrontend(int32_t in_frontendHandle,
+    ::ndk::ScopedAStatus getFrontendInfo(int32_t in_id, FrontendInfo* _aidl_return) override;
+    ::ndk::ScopedAStatus openFrontend(int64_t in_frontendHandle,
                                       shared_ptr<ITunerFrontend>* _aidl_return) override;
-    ::ndk::ScopedAStatus openLnb(int32_t in_lnbHandle,
+    ::ndk::ScopedAStatus openLnb(int64_t in_lnbHandle,
                                  shared_ptr<ITunerLnb>* _aidl_return) override;
     ::ndk::ScopedAStatus openLnbByName(const std::string& in_lnbName,
                                        shared_ptr<ITunerLnb>* _aidl_return) override;
-    ::ndk::ScopedAStatus openDemux(int32_t in_demuxHandle,
+    ::ndk::ScopedAStatus openDemux(int64_t in_demuxHandle,
                                    shared_ptr<ITunerDemux>* _aidl_return) override;
     ::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
-    ::ndk::ScopedAStatus getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) override;
+    ::ndk::ScopedAStatus getDemuxInfo(int64_t in_demuxHandle, DemuxInfo* _aidl_return) override;
     ::ndk::ScopedAStatus getDemuxInfoList(vector<DemuxInfo>* _aidl_return) override;
-    ::ndk::ScopedAStatus openDescrambler(int32_t in_descramblerHandle,
+    ::ndk::ScopedAStatus openDescrambler(int64_t in_descramblerHandle,
                                          shared_ptr<ITunerDescrambler>* _aidl_return) override;
     ::ndk::ScopedAStatus getTunerHalVersion(int32_t* _aidl_return) override;
     ::ndk::ScopedAStatus openSharedFilter(const string& in_filterToken,
@@ -106,7 +105,7 @@
 private:
     void updateTunerResources();
     vector<TunerFrontendInfo> getTRMFrontendInfos();
-    vector<int32_t> getTRMLnbHandles();
+    vector<int64_t> getTRMLnbHandles();
     HidlResult getHidlFrontendIds(hidl_vec<HidlFrontendId>& ids);
     HidlResult getHidlFrontendInfo(const int id, HidlFrontendInfo& info);
     DemuxCapabilities getAidlDemuxCaps(const HidlDemuxCapabilities& caps);
diff --git a/tools/mainline_hook_partial.sh b/tools/mainline_hook_partial.sh
index 63ae4c0..978dc02 100755
--- a/tools/mainline_hook_partial.sh
+++ b/tools/mainline_hook_partial.sh
Binary files differ
diff --git a/tools/mainline_hook_project.sh b/tools/mainline_hook_project.sh
index d58143e..65f4073 100755
--- a/tools/mainline_hook_project.sh
+++ b/tools/mainline_hook_project.sh
@@ -16,8 +16,9 @@
 
 
 # tunables
+# as of 2024/5, things are all on the same branch
 DEV_BRANCH=main
-MAINLINE_BRANCH=udc-mainline-prod
+MAINLINE_BRANCH=main
 
 ###
 RED=$(tput setaf 1)