Merge "Camera: Fix assorted deprecation and formatting warnings" into main
diff --git a/aidl/com/android/media/permission/PermissionEnum.aidl b/aidl/com/android/media/permission/PermissionEnum.aidl
index 834a275..b08db44 100644
--- a/aidl/com/android/media/permission/PermissionEnum.aidl
+++ b/aidl/com/android/media/permission/PermissionEnum.aidl
@@ -21,11 +21,21 @@
  * {@hide}
  */
 enum PermissionEnum {
-    MODIFY_AUDIO_ROUTING = 0,
-    MODIFY_PHONE_STATE = 1,
-    CALL_AUDIO_INTERCEPTION = 2,
     // This is a runtime + WIU permission, which means data delivery should be protected by AppOps
     // We query the controller only for early fails/hard errors
-    RECORD_AUDIO = 3,
-    ENUM_SIZE = 4, // Not for actual usage
+    RECORD_AUDIO = 0,
+    MODIFY_AUDIO_ROUTING = 1,
+    MODIFY_AUDIO_SETTINGS = 2,
+    MODIFY_PHONE_STATE = 3,
+    MODIFY_DEFAULT_AUDIO_EFFECTS = 4,
+    WRITE_SECURE_SETTINGS = 5,
+    CALL_AUDIO_INTERCEPTION = 6,
+    ACCESS_ULTRASOUND = 7,
+    CAPTURE_AUDIO_OUTPUT = 8,
+    CAPTURE_MEDIA_OUTPUT = 9,
+    CAPTURE_AUDIO_HOTWORD = 10,
+    CAPTURE_TUNER_AUDIO_INPUT = 11,
+    CAPTURE_VOICE_COMMUNICATION_OUTPUT = 12,
+    BLUETOOTH_CONNECT = 13,
+    ENUM_SIZE = 14, // Not for actual usage, used by Java
 }
diff --git a/camera/Android.bp b/camera/Android.bp
index 75c2999..9e1efae 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -86,40 +86,40 @@
 
         // Source for camera interface parcelables, and manually-written interfaces
         "Camera.cpp",
+        "CameraBase.cpp",
         "CameraMetadata.cpp",
         "CameraParameters.cpp",
-        "CaptureResult.cpp",
         "CameraParameters2.cpp",
         "CameraSessionStats.cpp",
+        "CameraUtils.cpp",
+        "CaptureResult.cpp",
         "ICamera.cpp",
         "ICameraClient.cpp",
         "ICameraRecordingProxy.cpp",
+        "VendorTagDescriptor.cpp",
         "camera2/CaptureRequest.cpp",
         "camera2/ConcurrentCamera.cpp",
         "camera2/OutputConfiguration.cpp",
         "camera2/SessionConfiguration.cpp",
         "camera2/SubmitInfo.cpp",
-        "CameraBase.cpp",
-        "CameraUtils.cpp",
-        "VendorTagDescriptor.cpp",
     ],
 
     shared_libs: [
         "camera_platform_flags_c_lib",
-        "libbase",
-        "libcutils",
-        "libutils",
-        "liblog",
-        "libbinder",
-        "libgui",
-        "libcamera_metadata",
-        "libnativewindow",
         "lib-platform-compat-native-api",
+        "libbase",
+        "libbinder",
+        "libcamera_metadata",
+        "libcutils",
+        "libgui",
+        "liblog",
+        "libnativewindow",
+        "libutils",
     ],
 
     include_dirs: [
-        "system/media/private/camera/include",
         "frameworks/native/include/media/openmax",
+        "system/media/private/camera/include",
     ],
     export_include_dirs: [
         "include",
@@ -127,13 +127,13 @@
     ],
     export_shared_lib_headers: [
         "libcamera_metadata",
-        "libnativewindow",
         "libgui",
+        "libnativewindow",
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
         "-Wextra",
     ],
 
@@ -153,8 +153,8 @@
     ],
 
     include_dirs: [
-        "system/media/private/camera/include",
         "frameworks/native/include/media/openmax",
+        "system/media/private/camera/include",
     ],
 
     export_include_dirs: [
@@ -168,6 +168,7 @@
     name: "libcamera_client_aidl",
     srcs: [
         "aidl/android/hardware/CameraExtensionSessionStats.aidl",
+        "aidl/android/hardware/CameraFeatureCombinationStats.aidl",
         "aidl/android/hardware/ICameraService.aidl",
         "aidl/android/hardware/ICameraServiceListener.aidl",
         "aidl/android/hardware/ICameraServiceProxy.aidl",
diff --git a/camera/aidl/android/hardware/CameraFeatureCombinationStats.aidl b/camera/aidl/android/hardware/CameraFeatureCombinationStats.aidl
new file mode 100644
index 0000000..f4a11b1
--- /dev/null
+++ b/camera/aidl/android/hardware/CameraFeatureCombinationStats.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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 android.hardware;
+
+/**
+ * {@hide}
+ */
+parcelable CameraFeatureCombinationStats {
+    /**
+     * Values for feature combination queries
+     */
+    const long CAMERA_FEATURE_UNKNOWN = 0;
+    const long CAMERA_FEATURE_60_FPS = 1 << 0;
+    const long CAMERA_FEATURE_STABILIZATION = 1 << 1;
+    const long CAMERA_FEATURE_HLG10 = 1 << 2;
+    const long CAMERA_FEATURE_JPEG = 1 << 3;
+    const long CAMERA_FEATURE_JPEG_R = 1 << 4;
+    const long CAMERA_FEATURE_4K = 1 << 5;
+
+    /**
+     * Values for notifyFeatureCombinationStats type
+     */
+    enum QueryType {
+        QUERY_FEATURE_COMBINATION = 0,
+        QUERY_SESSION_CHARACTERISTICS = 1,
+    }
+
+    @utf8InCpp String mCameraId;
+    int mUid;
+    long mFeatureCombination;
+    int mQueryType;
+    int mStatus;
+}
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index dcd69b0..887a68b 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware;
 
+import android.hardware.CameraFeatureCombinationStats;
 import android.hardware.CameraSessionStats;
 import android.hardware.CameraExtensionSessionStats;
 
@@ -38,6 +39,12 @@
     oneway void notifyCameraState(in CameraSessionStats cameraSessionStats);
 
     /**
+     * Notify feature combination query for a camera device.
+     */
+    oneway void notifyFeatureCombinationStats(
+            in CameraFeatureCombinationStats cameraFeatureCombinationStats);
+
+    /**
      * Returns the necessary rotate and crop override for the top activity which
      * will be one of ({@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_NONE},
      * {@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_90},
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 5577775..a603659 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -66,40 +66,40 @@
 cc_library_shared {
     name: "libcamera2ndk",
     srcs: [
+        "NdkCameraCaptureSession.cpp",
+        "NdkCameraDevice.cpp",
         "NdkCameraManager.cpp",
         "NdkCameraMetadata.cpp",
-        "NdkCameraDevice.cpp",
         "NdkCaptureRequest.cpp",
-        "NdkCameraCaptureSession.cpp",
+        "impl/ACameraCaptureSession.cpp",
+        "impl/ACameraDevice.cpp",
         "impl/ACameraManager.cpp",
         "impl/ACameraMetadata.cpp",
-        "impl/ACameraDevice.cpp",
-        "impl/ACameraCaptureSession.cpp",
     ],
     shared_libs: [
         "android.companion.virtual.virtualdevice_aidl-cpp",
         "android.companion.virtualdevice.flags-aconfig-cc",
-        "libbinder",
-        "liblog",
-        "libgui",
-        "libutils",
         "libandroid_runtime",
+        "libbinder",
         "libcamera_client",
-        "libstagefright_foundation",
-        "libcutils",
         "libcamera_metadata",
+        "libcutils",
+        "libgui",
+        "liblog",
         "libmediandk",
         "libnativewindow",
+        "libstagefright_foundation",
+        "libutils",
     ],
     header_libs: [
         "jni_headers",
     ],
     cflags: [
-        "-fvisibility=hidden",
         "-DEXPORT=__attribute__((visibility(\"default\")))",
         "-Wall",
-        "-Wextra",
         "-Werror",
+        "-Wextra",
+        "-fvisibility=hidden",
     ],
     // TODO: jchowdhary@, use header_libs instead b/131165718
     include_dirs: [
@@ -117,16 +117,16 @@
     cpp_std: "gnu++17",
     vendor: true,
     srcs: [
+        "NdkCameraCaptureSession.cpp",
+        "NdkCameraDevice.cpp",
+        "NdkCameraManager.cpp",
+        "NdkCameraMetadata.cpp",
+        "NdkCaptureRequest.cpp",
+        "impl/ACameraCaptureSession.cpp",
+        "impl/ACameraMetadata.cpp",
         "ndk_vendor/impl/ACameraDevice.cpp",
         "ndk_vendor/impl/ACameraManager.cpp",
         "ndk_vendor/impl/utils.cpp",
-        "impl/ACameraMetadata.cpp",
-        "impl/ACameraCaptureSession.cpp",
-        "NdkCameraMetadata.cpp",
-        "NdkCameraCaptureSession.cpp",
-        "NdkCameraManager.cpp",
-        "NdkCameraDevice.cpp",
-        "NdkCaptureRequest.cpp",
     ],
 
     export_include_dirs: ["include"],
@@ -135,30 +135,30 @@
     ],
     local_include_dirs: [
         ".",
-        "include",
         "impl",
+        "include",
     ],
     cflags: [
-        "-fvisibility=hidden",
         "-DEXPORT=__attribute__((visibility(\"default\")))",
         "-D__ANDROID_VNDK__",
+        "-fvisibility=hidden",
     ],
 
     shared_libs: [
-        "libbinder_ndk",
-        "libfmq",
-        "libhidlbase",
-        "libhardware",
-        "libnativewindow",
-        "liblog",
-        "libutils",
-        "libstagefright_foundation",
-        "libcutils",
-        "libcamera_metadata",
-        "libmediandk",
         "android.frameworks.cameraservice.common-V1-ndk",
         "android.frameworks.cameraservice.device-V2-ndk",
         "android.frameworks.cameraservice.service-V2-ndk",
+        "libbinder_ndk",
+        "libcamera_metadata",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libmediandk",
+        "libnativewindow",
+        "libstagefright_foundation",
+        "libutils",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
@@ -175,19 +175,19 @@
     name: "ACameraNdkVendorTest",
     vendor: true,
     srcs: [
-        "ndk_vendor/tests/AImageReaderVendorTest.cpp",
         "ndk_vendor/tests/ACameraManagerTest.cpp",
+        "ndk_vendor/tests/AImageReaderVendorTest.cpp",
     ],
     shared_libs: [
         "libcamera2ndk_vendor",
         "libcamera_metadata",
+        "libcutils",
         "libhidlbase",
+        "liblog",
         "libmediandk",
         "libnativewindow",
-        "libutils",
         "libui",
-        "libcutils",
-        "liblog",
+        "libutils",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 645a3d4..7d234bb 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2287,12 +2287,11 @@
      * <p>When low light boost is enabled by setting the AE mode to
      * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
      * boost when the light level threshold is exceeded.</p>
-     * <p>This field is present in the CaptureResult when the AE mode is set to
-     * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'. Otherwise, the field is not present.</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)
             ACAMERA_CONTROL_START + 59,
@@ -2428,27 +2427,27 @@
      * </ul></p>
      *
      * <p>Flash strength level to use in capture mode i.e. when the applications control
-     * flash with either SINGLE or TORCH mode.</p>
+     * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p>
      * <p>Use ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
      * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL to check whether the device supports
      * flash strength control or not.
-     * If the values of android.flash.info.singleStrengthMaxLevel and
+     * If the values of ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
      * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1,
      * then the device supports manual flash strength control.</p>
-     * <p>If the ACAMERA_FLASH_MODE <code>==</code> TORCH the value must be &gt;= 1
+     * <p>If the ACAMERA_FLASH_MODE <code>==</code> <code>TORCH</code> the value must be &gt;= 1
      * and &lt;= ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL.
      * If the application doesn't set the key and
      * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL &gt; 1,
      * then the flash will be fired at the default level set by HAL in
      * ACAMERA_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL.
-     * If the ACAMERA_FLASH_MODE <code>==</code> SINGLE, then the value must be &gt;= 1
+     * If the ACAMERA_FLASH_MODE <code>==</code> <code>SINGLE</code>, then the value must be &gt;= 1
      * and &lt;= ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL.
      * If the application does not set this key and
      * ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL &gt; 1,
      * then the flash will be fired at the default level set by HAL
      * in ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL.
-     * If ACAMERA_CONTROL_AE_MODE is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
-     * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+     * 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>
      *
      * @see ACAMERA_CONTROL_AE_MODE
      * @see ACAMERA_FLASH_MODE
@@ -2460,7 +2459,7 @@
     ACAMERA_FLASH_STRENGTH_LEVEL =                              // int32
             ACAMERA_FLASH_START + 6,
     /**
-     * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+     * <p>Maximum flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
      *
      * <p>Type: int32</p>
      *
@@ -2470,7 +2469,7 @@
      * </ul></p>
      *
      * <p>Maximum flash brightness level in camera capture mode and
-     * ACAMERA_FLASH_MODE set to SINGLE.
+     * ACAMERA_FLASH_MODE set to <code>SINGLE</code>.
      * Value will be &gt; 1 if the manual flash strength control feature is supported,
      * otherwise the value will be equal to 1.
      * Note that this level is just a number of supported levels (the granularity of control).
@@ -2481,7 +2480,7 @@
     ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL =                   // int32
             ACAMERA_FLASH_START + 7,
     /**
-     * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+     * <p>Default flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
      *
      * <p>Type: int32</p>
      *
@@ -2500,7 +2499,7 @@
     ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL =               // int32
             ACAMERA_FLASH_START + 8,
     /**
-     * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+     * <p>Maximum flash brightness level for manual flash control in <code>TORCH</code> mode</p>
      *
      * <p>Type: int32</p>
      *
@@ -2510,7 +2509,7 @@
      * </ul></p>
      *
      * <p>Maximum flash brightness level in camera capture mode and
-     * ACAMERA_FLASH_MODE set to TORCH.
+     * ACAMERA_FLASH_MODE set to <code>TORCH</code>.
      * Value will be &gt; 1 if the manual flash strength control feature is supported,
      * otherwise the value will be equal to 1.</p>
      * <p>Note that this level is just a number of supported levels(the granularity of control).
@@ -2527,7 +2526,7 @@
     ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL =                    // int32
             ACAMERA_FLASH_START + 9,
     /**
-     * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+     * <p>Default flash brightness level for manual flash control in <code>TORCH</code> mode</p>
      *
      * <p>Type: int32</p>
      *
@@ -5875,10 +5874,16 @@
      *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
      * </ul></p>
      *
-     * <p>If TRUE, all images produced by the camera device in the RAW image formats will
-     * have lens shading correction already applied to it. If FALSE, the images will
-     * not be adjusted for lens shading correction.
-     * See android.request.maxNumOutputRaw for a list of RAW image formats.</p>
+     * <p>If <code>true</code>, all images produced by the camera device in the <code>RAW</code> image formats will have
+     * at least some lens shading correction already applied to it. If <code>false</code>, the images will
+     * not be adjusted for lens shading correction.  See android.request.maxNumOutputRaw for a
+     * list of RAW image formats.</p>
+     * <p>When <code>true</code>, the <code>lensShadingCorrectionMap</code> key may still have values greater than 1.0,
+     * and those will need to be applied to any captured RAW frames for them to match the shading
+     * correction of processed buffers such as <code>YUV</code> or <code>JPEG</code> images. This may occur, for
+     * example, when some basic fixed lens shading correction is applied by hardware to RAW data,
+     * and additional correction is done dynamically in the camera processing pipeline after
+     * demosaicing.</p>
      * <p>This key will be <code>null</code> for all devices do not report this information.
      * Devices with RAW capability will always report this information in this key.</p>
      */
@@ -8305,11 +8310,8 @@
      * <p>If the session configuration is not supported, the AE mode reported in the
      * CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.</p>
      * <p>When this AE mode is enabled, the CaptureResult field
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be present and not null. Otherwise, the
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE field will not be present in the CaptureResult.</p>
-     * <p>The application can observe the CaptureResult field
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE to determine when low light boost is 'ACTIVE' or
-     * 'INACTIVE'.</p>
+     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will indicate when low light boost is 'ACTIVE'
+     * or 'INACTIVE'. By default ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be 'INACTIVE'.</p>
      * <p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
      * upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.
      * This mode will be 'INACTIVE' once the scene lighting condition is greater than the
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index e26290f..5a2ab27 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -289,7 +289,7 @@
 
     std::string toString() const {
         std::stringstream ss;
-        ss << "Interpolator{mInterpolatorType=" << static_cast<int32_t>(mInterpolatorType);
+        ss << "Interpolator{mInterpolatorType=" << media::toString(mInterpolatorType);
         ss << ", mFirstSlope=" << mFirstSlope;
         ss << ", mLastSlope=" << mLastSlope;
         ss << ", {";
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 6208db3..26da363 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -116,6 +116,16 @@
             TYPE_SCALE,
         };
 
+        static std::string toString(Type type) {
+            switch (type) {
+                case TYPE_ID: return "TYPE_ID";
+                case TYPE_SCALE: return "TYPE_SCALE";
+                default:
+                    return std::string("Unknown Type: ")
+                            .append(std::to_string(static_cast<int>(type)));
+            }
+        }
+
         // Must match with VolumeShaper.java in frameworks/base.
         enum OptionFlag : int32_t {
             OPTION_FLAG_NONE           = 0,
@@ -125,6 +135,22 @@
             OPTION_FLAG_ALL            = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
         };
 
+        static std::string toString(OptionFlag flag) {
+            std::string s;
+            for (const auto& flagPair : std::initializer_list<std::pair<OptionFlag, const char*>>{
+                    {OPTION_FLAG_VOLUME_IN_DBFS, "OPTION_FLAG_VOLUME_IN_DBFS"},
+                    {OPTION_FLAG_CLOCK_TIME, "OPTION_FLAG_CLOCK_TIME"},
+                }) {
+                if (flag & flagPair.first) {
+                    if (!s.empty()) {
+                        s.append("|");
+                    }
+                    s.append(flagPair.second);
+                }
+            }
+            return s;
+        }
+
         // Bring from base class; must match with VolumeShaper.java in frameworks/base.
         using InterpolatorType = Interpolator<S, T>::InterpolatorType;
 
@@ -329,10 +355,10 @@
         // Returns a string for debug printing.
         std::string toString() const {
             std::stringstream ss;
-            ss << "VolumeShaper::Configuration{mType=" << static_cast<int32_t>(mType);
+            ss << "VolumeShaper::Configuration{mType=" << toString(mType);
             ss << ", mId=" << mId;
             if (mType != TYPE_ID) {
-                ss << ", mOptionFlags=" << static_cast<int32_t>(mOptionFlags);
+                ss << ", mOptionFlags=" << toString(mOptionFlags);
                 ss << ", mDurationMs=" << mDurationMs;
                 ss << ", " << Interpolator<S, T>::toString().c_str();
             }
@@ -414,6 +440,25 @@
                             | FLAG_CREATE_IF_NECESSARY),
         };
 
+        static std::string toString(Flag flag) {
+            std::string s;
+            for (const auto& flagPair : std::initializer_list<std::pair<Flag, const char*>>{
+                    {FLAG_REVERSE, "FLAG_REVERSE"},
+                    {FLAG_TERMINATE, "FLAG_TERMINATE"},
+                    {FLAG_JOIN, "FLAG_JOIN"},
+                    {FLAG_DELAY, "FLAG_DELAY"},
+                    {FLAG_CREATE_IF_NECESSARY, "FLAG_CREATE_IF_NECESSARY"},
+                }) {
+                if (flag & flagPair.first) {
+                    if (!s.empty()) {
+                        s.append("|");
+                    }
+                    s.append(flagPair.second);
+                }
+            }
+            return s;
+        }
+
         Operation()
             : Operation(FLAG_NONE, -1 /* replaceId */) {
         }
@@ -508,7 +553,7 @@
 
         std::string toString() const {
             std::stringstream ss;
-            ss << "VolumeShaper::Operation{mFlags=" << static_cast<int32_t>(mFlags) ;
+            ss << "VolumeShaper::Operation{mFlags=" << toString(mFlags);
             ss << ", mReplaceId=" << mReplaceId;
             ss << ", mXOffset=" << mXOffset;
             ss << "}";
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index 4c3e25a..c3ae59c 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -60,6 +60,13 @@
 }
 
 flag {
+    name: "music_fx_edge_to_edge"
+    namespace: "media_audio"
+    description: "Enable Edge-to-edge feature for MusicFx and handle insets"
+    bug: "336204940"
+}
+
+flag {
     name: "port_to_piid_simplification"
     namespace: "media_audio"
     description: "PAM only needs for each piid the last portId mapping"
diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig
index 94b60e2..39fa187 100644
--- a/media/audio/aconfig/audioserver.aconfig
+++ b/media/audio/aconfig/audioserver.aconfig
@@ -15,6 +15,13 @@
 }
 
 flag {
+    name: "effect_chain_callback_improve"
+    namespace: "media_audio"
+    description: "Improve effect chain callback mutex logic."
+    bug: "342413767"
+}
+
+flag {
     name: "fdtostring_timeout_fix"
     namespace: "media_audio"
     description: "Improve fdtostring implementation to properly handle timing out."
@@ -22,6 +29,14 @@
 }
 
 flag {
+    name: "fix_call_audio_patch"
+    namespace: "media_audio"
+    description:
+        "optimize creation and release of audio patches for call routing"
+    bug: "292492229"
+}
+
+flag {
     name: "fix_concurrent_playback_behavior_with_bit_perfect_client"
     namespace: "media_audio"
     description:
@@ -31,6 +46,15 @@
 }
 
 flag {
+    name: "fix_input_sharing_logic"
+    namespace: "media_audio"
+    description:
+        "Fix the audio policy logic that decides to reuse or close "
+        "input streams when resources are exhausted"
+    bug: "338446410"
+}
+
+flag {
     name: "mutex_priority_inheritance"
     namespace: "media_audio"
     description:
@@ -41,10 +65,9 @@
 }
 
 flag {
-    name: "fix_input_sharing_logic"
+    name: "use_bt_sco_for_media"
     namespace: "media_audio"
     description:
-        "Fix the audio policy logic that decides to reuse or close "
-        "input streams when resources are exhausted"
-    bug: "338446410"
+        "Play media strategy over Bluetooth SCO when active"
+    bug: "292037886"
 }
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 77418eb..9eaddce 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -1069,13 +1069,6 @@
             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]);
-            // special case for anonymized mac address:
-            // change anonymized bytes back from FD:FF:FF:FF to XX:XX:XX:XX
-            std::string address(addressBuffer);
-            if (address.compare(0, strlen("FD:FF:FF:FF"), "FD:FF:FF:FF") == 0) {
-                address.replace(0, strlen("FD:FF:FF:FF"), "XX:XX:XX:XX");
-            }
-            strcpy(addressBuffer, address.c_str());
         } break;
         case Tag::ipv4: {
             const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>();
@@ -1136,20 +1129,11 @@
     if (!legacyAddress.empty()) {
         switch (suggestDeviceAddressTag(aidl.type)) {
             case Tag::mac: {
-                // special case for anonymized mac address:
-                // change anonymized bytes so that they can be scanned as HEX bytes
-                // Use '01' for LSB bits 0 and 1 as Bluetooth MAC addresses are never multicast
-                // and universaly administered
-                std::string address = legacyAddress;
-                if (address.compare(0, strlen("XX:XX:XX:XX"), "XX:XX:XX:XX") == 0) {
-                    address.replace(0, strlen("XX:XX:XX:XX"), "FD:FF:FF:FF");
-                }
-
                 std::vector<uint8_t> mac(6);
-                int status = sscanf(address.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
+                int 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__, address.c_str());
+                    ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str());
                     return unexpected(BAD_VALUE);
                 }
                 aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::mac>(std::move(mac));
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 06a21f6..aec6523 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -712,6 +712,7 @@
         case kWhatStop: {
             int32_t err = thiz->onStop();
             thiz->mOutputBlockPool.reset();
+            mRunning = false;
             Reply(msg, &err);
             break;
         }
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index b95c09e..ea4d045 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -36,7 +36,7 @@
 #include <ostream>
 #include <sstream>
 
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
 #include <codec2/hidl/plugin/FilterPlugin.h>
 #include <dlfcn.h>
 #include <C2Config.h>
@@ -51,7 +51,7 @@
 namespace c2 {
 namespace utils {
 
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
 using ::android::DefaultFilterPlugin;
 using ::android::FilterWrapper;
 #endif
@@ -144,7 +144,15 @@
     ::android::SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -173,8 +181,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -189,7 +196,7 @@
     return mParameterCache;
 }
 
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
 // static
 std::shared_ptr<FilterWrapper> ComponentStore::GetFilterWrapper() {
     constexpr const char kPluginPath[] = "libc2filterplugin.so";
@@ -221,8 +228,13 @@
                 }
             }
             if (!isComponentSupportsLargeAudioFrame) {
+                // TODO - b/342269852: MultiAccessUnitInterface also needs to take multiple
+                // param reflectors. Currently filters work on video domain only,
+                // and the MultiAccessUnitHelper is only enabled on audio domain;
+                // thus we pass the component's param reflector, which is mParamReflectors[0].
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -250,7 +262,7 @@
             mStore->createComponent(name, &c2component);
 
     if (status == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
         c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
 #endif
         onInterfaceLoaded(c2component->intf());
@@ -284,7 +296,7 @@
     std::shared_ptr<C2ComponentInterface> c2interface;
     c2_status_t res = mStore->createInterface(name, &c2interface);
     if (res == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
         c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
 #endif
         onInterfaceLoaded(c2interface);
@@ -347,8 +359,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -401,6 +412,16 @@
     return ScopedAStatus::ok();
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index 746e1bf..b2158a6 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -118,7 +118,7 @@
 
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
@@ -135,6 +135,9 @@
     mutable std::mutex mComponentRosterMutex;
     std::map<Component*, ComponentStatus> mComponentRoster;
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     // Called whenever Component is created.
     void reportComponentBirth(Component* component);
     // Called only from the destructor of Component.
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index dbbabfe..f80809a 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -664,11 +664,10 @@
 
     int slotId;
     uint64_t outBufferAge;
-    ::android::FrameEventHistoryDelta outTimestamps;
     sp<Fence> fence;
 
     ::android::status_t status = igbp->dequeueBuffer(
-            &slotId, &fence, width, height, format, usage, &outBufferAge, &outTimestamps);
+            &slotId, &fence, width, height, format, usage, &outBufferAge, nullptr);
     if (status < ::android::OK) {
         if (status == ::android::TIMED_OUT || status == ::android::WOULD_BLOCK) {
             ALOGW("BQ might not be ready for dequeueBuffer()");
diff --git a/media/codec2/hal/hidl/1.0/utils/Component.cpp b/media/codec2/hal/hidl/1.0/utils/Component.cpp
index 0259d90..62f0e25 100644
--- a/media/codec2/hal/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/Component.cpp
@@ -521,7 +521,18 @@
 
 Return<Status> Component::stop() {
     InputBufferManager::unregisterFrameData(mListener);
-    return static_cast<Status>(mComponent->stop());
+    Status status = static_cast<Status>(mComponent->stop());
+    {
+        std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+        for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
+            if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+                std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+                        std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
+                bqPool->clearDeferredBlocks();
+            }
+        }
+    }
+    return status;
 }
 
 Return<Status> Component::reset() {
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index 988ab6f..1ba1889 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
     SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -168,8 +176,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -217,7 +224,8 @@
             }
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -339,8 +347,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -386,6 +393,16 @@
     return mConfigurable;
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
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 b5d85da..44b8ec1 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
@@ -117,9 +117,12 @@
     // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.1/utils/Component.cpp b/media/codec2/hal/hidl/1.1/utils/Component.cpp
index d34d84e..7f2c4dd 100644
--- a/media/codec2/hal/hidl/1.1/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/Component.cpp
@@ -527,7 +527,18 @@
 
 Return<Status> Component::stop() {
     InputBufferManager::unregisterFrameData(mListener);
-    return static_cast<Status>(mComponent->stop());
+    Status status = static_cast<Status>(mComponent->stop());
+    {
+        std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+        for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
+            if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+                std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+                        std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
+                bqPool->clearDeferredBlocks();
+            }
+        }
+    }
+    return status;
 }
 
 Return<Status> Component::reset() {
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index 46af809..1b86958 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
     SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -168,8 +176,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -218,7 +225,8 @@
 
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -340,8 +348,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -423,6 +430,16 @@
     return Void();
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
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 85862a9..52d2945 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
@@ -125,9 +125,12 @@
     // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.2/utils/Component.cpp b/media/codec2/hal/hidl/1.2/utils/Component.cpp
index f78e827..7b0aa9b 100644
--- a/media/codec2/hal/hidl/1.2/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/Component.cpp
@@ -523,7 +523,18 @@
 
 Return<Status> Component::stop() {
     InputBufferManager::unregisterFrameData(mListener);
-    return static_cast<Status>(mComponent->stop());
+    Status status = static_cast<Status>(mComponent->stop());
+    {
+        std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+        for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
+            if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+                std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+                        std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
+                bqPool->clearDeferredBlocks();
+            }
+        }
+    }
+    return status;
 }
 
 Return<Status> Component::reset() {
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index f89c835..2e0386f 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
     SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -168,8 +176,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -217,7 +224,8 @@
             }
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -338,8 +346,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -457,6 +464,16 @@
     return Void();
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
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 c08fce4..1b209e2 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
@@ -132,9 +132,12 @@
     // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/plugin/FilterWrapper.cpp b/media/codec2/hal/plugin/FilterWrapper.cpp
index b926150..ab6e3eb 100644
--- a/media/codec2/hal/plugin/FilterWrapper.cpp
+++ b/media/codec2/hal/plugin/FilterWrapper.cpp
@@ -1012,4 +1012,11 @@
     return mPlugin->queryParamsForPreviousComponent(intf, params);
 }
 
+std::shared_ptr<C2ParamReflector> FilterWrapper::getParamReflector() {
+    if (mInit != OK) {
+        return nullptr;
+    }
+    return mStore->getParamReflector();
+}
+
 }  // namespace android
diff --git a/media/codec2/hal/plugin/FilterWrapperStub.cpp b/media/codec2/hal/plugin/FilterWrapperStub.cpp
index 3fd5409..a21f6d0 100644
--- a/media/codec2/hal/plugin/FilterWrapperStub.cpp
+++ b/media/codec2/hal/plugin/FilterWrapperStub.cpp
@@ -57,4 +57,8 @@
     return CreateCodec2BlockPool(allocatorParam, component, pool);
 }
 
+std::shared_ptr<C2ParamReflector> FilterWrapper::getParamReflector() {
+    return nullptr;
+}
+
 }  // namespace android
diff --git a/media/codec2/hal/plugin/internal/FilterWrapper.h b/media/codec2/hal/plugin/internal/FilterWrapper.h
index dcffb5c..c27901e 100644
--- a/media/codec2/hal/plugin/internal/FilterWrapper.h
+++ b/media/codec2/hal/plugin/internal/FilterWrapper.h
@@ -104,6 +104,10 @@
             const std::shared_ptr<C2ComponentInterface> &intf,
             std::vector<std::unique_ptr<C2Param>> *params);
 
+    /**
+     * Return the param reflector of the filter plugin store.
+     */
+    std::shared_ptr<C2ParamReflector> getParamReflector();
 private:
     status_t mInit;
     std::unique_ptr<Plugin> mPlugin;
diff --git a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
index b5383ad..47412b7 100644
--- a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
@@ -37,6 +37,19 @@
                 kParamIndexColorAspects | C2Param::CoreIndex::IS_REQUEST_FLAG>
         C2StreamColorAspectsRequestInfo;
 
+// In practice the vendor parameters will be defined in a separate header file,
+// but for the purpose of this sample, we just define it here.
+
+// Vendor-specific type index for filters start from this value. 0x7000 is added to
+// avoid conflict with existing vendor type indices.
+constexpr uint32_t kTypeIndexFilterStart = C2Param::TYPE_INDEX_VENDOR_START + 0x7000;
+// Answer to the Ultimate Question of Life, the Universe, and Everything
+// (Reference to The Hitchhiker's Guide to the Galaxy by Douglas Adams)
+constexpr uint32_t kParamIndexVendorUltimateAnswer = kTypeIndexFilterStart + 0;
+typedef C2StreamParam<C2Info, C2Int32Value, kParamIndexVendorUltimateAnswer>
+        C2StreamVendorUltimateAnswerInfo;
+constexpr char C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER[] = "ultimate-answer";
+
 namespace android {
 
 using namespace std::literals::chrono_literals;
@@ -49,10 +62,9 @@
         static const std::string NAME;
         static const FilterPlugin_V1::Descriptor DESCRIPTOR;
 
-        explicit Interface(c2_node_id_t id)
+        Interface(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
             : mId(id),
-              mReflector(std::make_shared<C2ReflectorHelper>()),
-              mHelper(mReflector) {
+              mHelper(reflector) {
         }
         ~Interface() override = default;
         C2String getName() const override { return NAME; }
@@ -126,7 +138,6 @@
         }
     private:
         const c2_node_id_t mId;
-        std::shared_ptr<C2ReflectorHelper> mReflector;
         struct Helper : public C2InterfaceHelper {
             explicit Helper(std::shared_ptr<C2ReflectorHelper> reflector)
                 : C2InterfaceHelper(reflector) {
@@ -266,6 +277,15 @@
                         .build());
 
                 addParameter(
+                        DefineParam(mVendorUltimateAnswerInfo, C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER)
+                        .withDefault(new C2StreamVendorUltimateAnswerInfo::input(0u))
+                        .withFields({
+                            C2F(mVendorUltimateAnswerInfo, value).any(),
+                        })
+                        .withSetter(VendorUltimateAnswerSetter)
+                        .build());
+
+                addParameter(
                         DefineParam(mOutputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
                         .withDefault(new C2StreamColorAspectsInfo::output(0u))
                         .withFields({
@@ -336,6 +356,15 @@
                 return C2R::Ok();
             }
 
+            static C2R VendorUltimateAnswerSetter(
+                    bool mayBlock,
+                    C2P<C2StreamVendorUltimateAnswerInfo::input> &me) {
+                (void)mayBlock;
+                ALOGI("Answer to the Ultimate Question of Life, the Universe, and Everything "
+                      "set to %d", me.v.value);
+                return C2R::Ok();
+            }
+
             std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
 
             std::shared_ptr<C2ComponentNameSetting> mName;
@@ -362,11 +391,13 @@
             std::shared_ptr<C2StreamColorAspectsInfo::input> mInputColorAspectInfo;
             std::shared_ptr<C2StreamColorAspectsInfo::output> mOutputColorAspectInfo;
             std::shared_ptr<C2StreamColorAspectsRequestInfo::output> mColorAspectRequestInfo;
+
+            std::shared_ptr<C2StreamVendorUltimateAnswerInfo::input> mVendorUltimateAnswerInfo;
         } mHelper;
     };
 
-    explicit SampleToneMappingFilter(c2_node_id_t id)
-        : mIntf(std::make_shared<Interface>(id)) {
+    SampleToneMappingFilter(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
+        : mIntf(std::make_shared<Interface>(id, reflector)) {
     }
     ~SampleToneMappingFilter() override {
         if (mProcessingThread.joinable()) {
@@ -802,7 +833,10 @@
 // static
 const FilterPlugin_V1::Descriptor SampleToneMappingFilter::Interface::DESCRIPTOR = {
     // controlParams
-    { C2StreamColorAspectsRequestInfo::output::PARAM_TYPE },
+    {
+        C2StreamColorAspectsRequestInfo::output::PARAM_TYPE,
+        C2StreamVendorUltimateAnswerInfo::input::PARAM_TYPE,
+    },
     // affectedParams
     {
         C2StreamHdrStaticInfo::output::PARAM_TYPE,
@@ -815,7 +849,7 @@
     SampleC2ComponentStore()
         : mReflector(std::make_shared<C2ReflectorHelper>()),
           mIntf(mReflector),
-          mFactories(CreateFactories()) {
+          mFactories(CreateFactories(mReflector)) {
     }
     ~SampleC2ComponentStore() = default;
 
@@ -892,36 +926,46 @@
     template <class T>
     struct ComponentFactoryImpl : public ComponentFactory {
     public:
-        ComponentFactoryImpl(const std::shared_ptr<const C2Component::Traits> &traits)
-            : ComponentFactory(traits) {
+        ComponentFactoryImpl(
+                const std::shared_ptr<const C2Component::Traits> &traits,
+                const std::shared_ptr<C2ReflectorHelper> &reflector)
+            : ComponentFactory(traits),
+              mReflector(reflector) {
         }
         ~ComponentFactoryImpl() override = default;
         c2_status_t createComponent(
                 c2_node_id_t id,
                 std::shared_ptr<C2Component>* const component) const override {
-            *component = std::make_shared<T>(id);
+            *component = std::make_shared<T>(id, mReflector);
             return C2_OK;
         }
         c2_status_t createInterface(
                 c2_node_id_t id,
                 std::shared_ptr<C2ComponentInterface>* const interface) const override {
-            *interface = std::make_shared<typename T::Interface>(id);
+            *interface = std::make_shared<typename T::Interface>(id, mReflector);
             return C2_OK;
         }
+    private:
+        std::shared_ptr<C2ReflectorHelper> mReflector;
     };
 
     template <class T>
-    static void AddFactory(std::map<C2String, std::unique_ptr<ComponentFactory>> *factories) {
-        std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0)};
+    static void AddFactory(
+            std::map<C2String, 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));
+        factories->emplace(
+                traits->name,
+                new ComponentFactoryImpl<T>(traits, reflector));
     }
 
-    static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories() {
+    static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories(
+            const std::shared_ptr<C2ReflectorHelper> &reflector) {
         std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
-        AddFactory<SampleToneMappingFilter>(&factories);
+        AddFactory<SampleToneMappingFilter>(&factories, reflector);
         return factories;
     }
 
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index ca0aabb..39aadd7 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -2633,6 +2633,15 @@
     if (config->mInputSurface == nullptr
             && (property_get_bool("debug.stagefright.ccodec_delayed_params", false)
                     || comp->getName().find("c2.android.") == 0)) {
+        std::vector<std::unique_ptr<C2Param>> localConfigUpdate;
+        for (const std::unique_ptr<C2Param> &param : configUpdate) {
+            if (param && param->coreIndex().coreIndex() == C2StreamSurfaceScalingInfo::CORE_INDEX) {
+                localConfigUpdate.push_back(C2Param::Copy(*param));
+            }
+        }
+        if (!localConfigUpdate.empty()) {
+            (void)config->setParameters(comp, localConfigUpdate, C2_MAY_BLOCK);
+        }
         mChannel->setParameters(configUpdate);
     } else {
         sp<AMessage> outputFormat = config->mOutputFormat;
diff --git a/media/codec2/tests/Android.bp b/media/codec2/tests/Android.bp
index 02c356c..7d671a7 100644
--- a/media/codec2/tests/Android.bp
+++ b/media/codec2/tests/Android.bp
@@ -45,6 +45,11 @@
         "C2SampleComponent_test.cpp",
         "C2UtilTest.cpp",
         "vndk/C2BufferTest.cpp",
+        "vndk/C2FenceTest.cpp",
+    ],
+
+    static_libs: [
+        "libgmock",
     ],
 
     shared_libs: [
@@ -52,6 +57,7 @@
         "libcodec2_vndk",
         "libcutils",
         "liblog",
+        "libui",
         "libutils",
     ],
 
diff --git a/media/codec2/tests/vndk/C2FenceTest.cpp b/media/codec2/tests/vndk/C2FenceTest.cpp
new file mode 100644
index 0000000..9292381
--- /dev/null
+++ b/media/codec2/tests/vndk/C2FenceTest.cpp
@@ -0,0 +1,455 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <C2Buffer.h>
+#include <C2FenceFactory.h>
+
+#include <unistd.h>
+
+#include <android-base/unique_fd.h>
+#include <linux/kcmp.h>       /* Definition of KCMP_* constants */
+#include <sys/mman.h>
+#include <sys/syscall.h>      /* Definition of SYS_* constants */
+#include <ui/Fence.h>
+
+namespace android {
+
+static int fd_kcmp(int fd1, int fd2) {
+    static pid_t pid = getpid();
+
+    return syscall(SYS_kcmp, pid, pid, KCMP_FILE, fd1, fd2);
+}
+
+// matcher to check if value (arg) and fd refers to the same file
+MATCHER_P(RefersToTheSameFile, fd, "") {
+    return fd_kcmp(fd, arg) == 0;
+}
+
+// matcher to check if value (arg) is a dup of an fd
+MATCHER_P(IsDupOf, fd, "") {
+    return (ExplainMatchResult(::testing::Ne(-1), arg, result_listener) &&
+            ExplainMatchResult(::testing::Ne(fd), arg, result_listener) &&
+            ExplainMatchResult(RefersToTheSameFile(fd), arg, result_listener));
+}
+
+class C2FenceTest : public ::testing::Test {
+public:
+    C2FenceTest() = default;
+
+    ~C2FenceTest() = default;
+
+
+protected:
+    enum : int32_t {
+        SYNC_FENCE_DEPRECATED_MAGIC     = 3,
+        SYNC_FENCE_UNORDERED_MAGIC      = '\302fsu',
+        SYNC_FENCE_MAGIC                = '\302fso',
+    };
+
+    // Validate a null fence
+    void validateNullFence(const C2Fence &fence);
+
+    // Validate a single fd sync fence
+    void validateSingleFdFence(const C2Fence &fence, int fd);
+
+    // Validate a two fd unordered sync fence
+    void validateTwoFdUnorderedFence(const C2Fence &fence, int fd1, int fd2, int mergeFd);
+
+    // Validate a three fd sync fence
+    void validateThreeFdFence(const C2Fence &fence, int fd1, int fd2, int fd3);
+};
+
+TEST_F(C2FenceTest, IsDupOf_sanity) {
+    int fd1 = memfd_create("test1", 0 /* flags */);
+    int fd2 = memfd_create("test2", 0 /* flags */);
+    int fd3 = memfd_create("test3", 0 /* flags */);
+
+    EXPECT_THAT(fd1, ::testing::Not(IsDupOf(fd2)));
+    EXPECT_THAT(-1, ::testing::Not(IsDupOf(fd2)));
+    EXPECT_THAT(-1, ::testing::Not(IsDupOf(-1)));
+    EXPECT_THAT(fd3, ::testing::Not(IsDupOf(fd3)));
+
+    int fd4 = dup(fd3);
+    EXPECT_THAT(fd4, IsDupOf(fd3));
+    EXPECT_THAT(fd3, IsDupOf(fd4));
+
+    close(fd1);
+    close(fd2);
+    close(fd3);
+    close(fd4);
+}
+
+TEST_F(C2FenceTest, NullFence) {
+    validateNullFence(C2Fence());
+}
+
+void C2FenceTest::validateNullFence(const C2Fence &fence) {
+    // Verify that the fence is valid.
+    EXPECT_TRUE(fence.valid());
+    EXPECT_TRUE(fence.ready());
+    base::unique_fd fenceFd{fence.fd()};
+    EXPECT_EQ(fenceFd.get(), -1);
+    EXPECT_FALSE(fence.isHW()); // perhaps this should be false for a null fence
+
+    // A null fence has no fds
+    std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence);
+    EXPECT_THAT(fds, ::testing::IsEmpty());
+    for (int fd : fds) {
+        close(fd);
+    }
+
+    // A null fence has no native handle
+    native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence);
+    EXPECT_THAT(handle, ::testing::IsNull());
+    if (handle) {
+        native_handle_close(handle);
+        native_handle_delete(handle);
+    }
+}
+
+TEST_F(C2FenceTest, SyncFence_with_negative_fd) {
+    // Create a SyncFence with a negative fd.
+    C2Fence fence = _C2FenceFactory::CreateSyncFence(-1, false /* validate */);
+
+    validateNullFence(fence);
+}
+
+TEST_F(C2FenceTest, SyncFence_with_valid_fd) {
+    // Create a SyncFence with a valid fd. We cannot create an actual sync fd,
+    // so we cannot test wait(), but we can verify the ABI APIs
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    C2Fence fence = _C2FenceFactory::CreateSyncFence(fd, false /* validate */);
+    validateSingleFdFence(fence, fd);
+}
+
+void C2FenceTest::validateSingleFdFence(const C2Fence &fence, int fd) {
+    // EXPECT_TRUE(fence.valid()); // need a valid sync fd to test this
+    // EXPECT_TRUE(fence.ready());
+    // Verify that the fence says it is a HW sync fence.
+    EXPECT_TRUE(fence.isHW()); // FIXME this may be an implementation detail
+
+    // Verify that the fd returned is a duped version of the initial fd
+    base::unique_fd fenceFd{fence.fd()};
+    EXPECT_THAT(fenceFd.get(), IsDupOf(fd));
+
+    // Verify that fds returns a duped version of the initial fd
+    std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence);
+    EXPECT_THAT(fds, ::testing::SizeIs(1));
+    EXPECT_THAT(fds, ::testing::ElementsAre(IsDupOf(fd)));
+    for (int fd_i : fds) {
+        close(fd_i);
+    }
+
+    native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence);
+    EXPECT_THAT(handle, ::testing::NotNull());
+    if (handle) {
+        EXPECT_EQ(handle->numFds, 1);
+        EXPECT_EQ(handle->numInts, 1);
+        EXPECT_THAT(handle->data[0], IsDupOf(fd));
+        EXPECT_EQ(handle->data[1], SYNC_FENCE_MAGIC);
+
+        native_handle_close(handle);
+        native_handle_delete(handle);
+    }
+}
+
+TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_one_valid_test_fd) {
+    // Create a multi SyncFence with a single valid fd. This should create
+    // a single fd sync fence. We can only validate this through its public
+    // methods: fd/fds and verify the native handle ABI.
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    c2_status_t status = C2_BAD_VALUE;
+    C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence(
+        { -1, fd, -1 }, &status);
+    // if we only have one valid fd, we are not merging fences, so the test fd is not validated
+    EXPECT_EQ(status, C2_OK);
+
+    validateSingleFdFence(fence, fd);
+}
+
+TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_one_valid_test_fd_null_status) {
+    // Create a multi SyncFence with a single valid fd. This should create
+    // a single fd sync fence. We can only validate this through its public
+    // methods: fd/fds and verify the native handle ABI.
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence(
+        { -1, fd, -1 });
+
+    validateSingleFdFence(fence, fd);
+}
+
+TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_merge_failure) {
+    // Create a multi SyncFence with a multiple non-sync fence fds. This should
+    // result in a fence created, but also an error.
+
+    int fd1 = memfd_create("test1", 0 /* flags */);
+    int fd2 = memfd_create("test2", 0 /* flags */);
+    int fd3 = memfd_create("test3", 0 /* flags */);
+
+    c2_status_t status = C2_BAD_VALUE;
+    C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence(
+        { fd1, fd2, fd3 }, &status);
+    EXPECT_EQ(status, C2_CORRUPTED);
+
+    validateThreeFdFence(fence, fd1, fd2, fd3);
+}
+
+TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_merge_failure_null_status) {
+    // Create a multi SyncFence with a multiple non-sync fence fds. This should
+    // result in a fence created, but also an error.
+
+    int fd1 = memfd_create("test1", 0 /* flags */);
+    int fd2 = memfd_create("test2", 0 /* flags */);
+    int fd3 = memfd_create("test3", 0 /* flags */);
+
+    C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence(
+        { fd1, fd2, fd3 });
+
+    validateThreeFdFence(fence, fd1, fd2, fd3);
+}
+
+TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_multiple_fds) {
+    // We cannot create a true unordered multi sync fence as we can only
+    // create test fds and those cannot be merged. As such, we cannot
+    // test the factory method CreateUnorderedMultiSyncFence. We can however
+    // create a test fence from a constructed native handle.
+
+    // Technically, we need 3 fds as if we end up with only 2, we wouldn't
+    // actually need a 2nd (final fence fd) since it is equivalent to the
+    // first. In fact we will generate (and always generated) a single fd
+    // fence in that case.
+    int fd1 = memfd_create("test1", 0 /* flags */);
+    int fd2 = memfd_create("test2", 0 /* flags */);
+    int mergeFd = memfd_create("test3", 0 /* flags */);
+
+    native_handle_t *handle = native_handle_create(3 /* numfds */, 1 /* numints */);
+    handle->data[0] = fd1;
+    handle->data[1] = fd2;
+    handle->data[2] = mergeFd;
+    handle->data[3] = SYNC_FENCE_UNORDERED_MAGIC;
+    C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */);
+    native_handle_delete(handle);
+
+    validateTwoFdUnorderedFence(fence, fd1, fd2, mergeFd);
+}
+
+void C2FenceTest::validateTwoFdUnorderedFence(
+        const C2Fence &fence, int fd1, int fd2, int mergeFd) {
+    // EXPECT_TRUE(fence.valid()); // need a valid sync fd to test this
+    // EXPECT_TRUE(fence.ready());
+    // Verify that the fence says it is a HW sync fence.
+    EXPECT_TRUE(fence.isHW()); // FIXME this may be an implementation detail
+
+    // Verify that the fd returned is a duped version of the merge fd
+    base::unique_fd fenceFd{fence.fd()};
+    EXPECT_THAT(fenceFd.get(), IsDupOf(mergeFd));
+
+    // Verify that fds returns a duped versions of the initial fds (but not the merge fd)
+    std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence);
+    EXPECT_THAT(fds, ::testing::SizeIs(2));
+    EXPECT_THAT(fds, ::testing::ElementsAre(IsDupOf(fd1), IsDupOf(fd2)));
+    for (int fd_i : fds) {
+        close(fd_i);
+    }
+
+    native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence);
+    EXPECT_THAT(handle, ::testing::NotNull());
+    if (handle) {
+        EXPECT_EQ(handle->numFds, 3);
+        EXPECT_EQ(handle->numInts, 1);
+        EXPECT_THAT(handle->data[0], IsDupOf(fd1));
+        EXPECT_THAT(handle->data[1], IsDupOf(fd2));
+        EXPECT_THAT(handle->data[2], IsDupOf(mergeFd));
+        EXPECT_EQ(handle->data[3], SYNC_FENCE_UNORDERED_MAGIC);
+
+        native_handle_close(handle);
+        native_handle_delete(handle);
+    }
+}
+
+TEST_F(C2FenceTest, MultiSyncFence_with_one_valid_test_fd) {
+    // Create a multi SyncFence with a single valid fd. This should create
+    // a single fd sync fence. We can only validate this through its public
+    // methods: fd/fds and verify the native handle ABI.
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    c2_status_t status = C2_BAD_VALUE;
+    C2Fence fence = _C2FenceFactory::CreateMultiSyncFence(
+        { -1, fd, -1 }, &status);
+    // if we only have one valid fd, we are not merging fences, so the test fds are not validated
+    EXPECT_EQ(status, C2_OK);
+
+    validateSingleFdFence(fence, fd);
+}
+
+TEST_F(C2FenceTest, MultiSyncFence_with_one_valid_test_fd_null_status) {
+    // Create a multi SyncFence with a single valid fd. This should create
+    // a single fd sync fence. We can only validate this through its public
+    // methods: fd/fds and verify the native handle ABI.
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    C2Fence fence = _C2FenceFactory::CreateMultiSyncFence(
+        { -1, fd, -1 });
+
+    validateSingleFdFence(fence, fd);
+}
+
+TEST_F(C2FenceTest, MultiSyncFence_with_multiple_fds) {
+    int fd1 = memfd_create("test1", 0 /* flags */);
+    int fd2 = memfd_create("test2", 0 /* flags */);
+    int fd3 = memfd_create("test3", 0 /* flags */);
+
+    c2_status_t status = C2_BAD_VALUE;
+    C2Fence fence = _C2FenceFactory::CreateMultiSyncFence(
+        { fd1, fd2, fd3 }, &status);
+    // test fds are not validated
+    EXPECT_EQ(status, C2_OK);
+
+    validateThreeFdFence(fence, fd1, fd2, fd3);
+}
+
+void C2FenceTest::validateThreeFdFence(const C2Fence &fence, int fd1, int fd2, int fd3) {
+    // EXPECT_TRUE(fence.valid()); // need a valid sync fd to test this
+    // EXPECT_TRUE(fence.ready());
+    // Verify that the fence says it is a HW sync fence.
+    EXPECT_TRUE(fence.isHW()); // FIXME this may be an implementation detail
+
+    // Verify that the fd returned is a duped version of the final fd
+    base::unique_fd fenceFd{fence.fd()};
+    EXPECT_THAT(fenceFd.get(), IsDupOf(fd3));
+
+    // Verify that fds returns a duped versions of all 3 initial fds
+    std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence);
+    EXPECT_THAT(fds, ::testing::SizeIs(3));
+    EXPECT_THAT(fds, ::testing::ElementsAre(IsDupOf(fd1), IsDupOf(fd2), IsDupOf(fd3)));
+    for (int fd_i : fds) {
+        close(fd_i);
+    }
+
+    native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence);
+    EXPECT_THAT(handle, ::testing::NotNull());
+    if (handle) {
+        EXPECT_EQ(handle->numFds, 3);
+        EXPECT_EQ(handle->numInts, 1);
+        EXPECT_THAT(handle->data[0], IsDupOf(fd1));
+        EXPECT_THAT(handle->data[1], IsDupOf(fd2));
+        EXPECT_THAT(handle->data[2], IsDupOf(fd3));
+        EXPECT_EQ(handle->data[3], SYNC_FENCE_MAGIC);
+
+        native_handle_close(handle);
+        native_handle_delete(handle);
+    }
+}
+
+TEST_F(C2FenceTest, BackwardCompat_UDC_sync_fence) {
+    // Create a single SyncFence from a UDC native handle
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    native_handle_t *handle = native_handle_create(1 /* numfds */, 1 /* numints */);
+    handle->data[0] = fd;
+    handle->data[1] = SYNC_FENCE_DEPRECATED_MAGIC;
+    C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */);
+    native_handle_delete(handle);
+
+    validateSingleFdFence(fence, fd);
+}
+
+TEST_F(C2FenceTest, BackwardCompat_24Q1_single_fd_fence) {
+    // Create a single SyncFence from a 24Q1 native handle
+    // This had the same (albeit separately duped) fd twice, and used the legacy
+    // magic number.
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    native_handle_t *handle = native_handle_create(2 /* numfds */, 1 /* numints */);
+    handle->data[0] = fd;
+    handle->data[1] = dup(fd);
+    handle->data[2] = SYNC_FENCE_DEPRECATED_MAGIC;
+    C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */);
+    native_handle_delete(handle);
+
+    validateSingleFdFence(fence, fd);
+}
+
+TEST_F(C2FenceTest, BackwardCompat_24Q3_single_fd_fence) {
+    // Create a single SyncFence from the defined native handle
+
+    int fd = memfd_create("test", 0 /* flags */);
+
+    native_handle_t *handle = native_handle_create(1 /* numfds */, 1 /* numints */);
+    handle->data[0] = fd;
+    handle->data[1] = SYNC_FENCE_MAGIC;
+    C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */);
+    native_handle_delete(handle);
+
+    validateSingleFdFence(fence, fd);
+}
+
+TEST_F(C2FenceTest, BackwardCompat_24Q1_multi_fd_fence) {
+    // Create a single SyncFence from a 24Q1 era native handle with
+    // the legacy magic number.
+
+    int fd1 = memfd_create("test1", 0 /* flags */);
+    int fd2 = memfd_create("test2", 0 /* flags */);
+    int mergeFd = memfd_create("test3", 0 /* flags */);
+
+    native_handle_t *handle = native_handle_create(3 /* numfds */, 1 /* numints */);
+    handle->data[0] = fd1;
+    handle->data[1] = fd2;
+    handle->data[2] = mergeFd;
+    handle->data[3] = SYNC_FENCE_DEPRECATED_MAGIC;
+    C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */);
+    native_handle_delete(handle);
+
+    validateTwoFdUnorderedFence(fence, fd1, fd2, mergeFd);
+}
+
+// No need to create BackwardCompat_24Q3_unordered_multi_fd_fence because
+// we are creating that fence already from the 24Q3 native handle layout
+// in the UnorderedMultiSyncFence_with_multiple_fds test.
+
+TEST_F(C2FenceTest, BackwardCompat_24Q3_multi_fd_fence) {
+    // Create a single SyncFence from a 24Q1 era native handle with
+    // the legacy magic number.
+
+    int fd1 = memfd_create("test1", 0 /* flags */);
+    int fd2 = memfd_create("test2", 0 /* flags */);
+    int fd3 = memfd_create("test3", 0 /* flags */);
+
+    native_handle_t *handle = native_handle_create(3 /* numfds */, 1 /* numints */);
+    handle->data[0] = fd1;
+    handle->data[1] = fd2;
+    handle->data[2] = fd3;
+    handle->data[3] = SYNC_FENCE_MAGIC;
+    C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */);
+    native_handle_delete(handle);
+
+    validateThreeFdFence(fence, fd1, fd2, fd3);
+}
+
+} // namespace android
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 3438406..d28f926 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -28,16 +28,27 @@
 
 #include <utility>
 
-#define MAX_FENCE_FDS 1
+// support up to 32 sync fds (and an optional merged fd), and 1 int
+#define MAX_FENCE_FDS  33
+#define MAX_FENCE_INTS 1
 
 class C2Fence::Impl {
 public:
-    enum type_t : uint32_t {
-        INVALID_FENCE,
-        NULL_FENCE,
-        SURFACE_FENCE,
-        SYNC_FENCE,
-        PIPE_FENCE,
+    // These enums are not part of the ABI, so can be changed.
+    enum type_t : int32_t {
+        INVALID_FENCE     = -1,
+        NULL_FENCE        = 0,
+        SURFACE_FENCE     = 2,
+
+        SYNC_FENCE        = 3,
+        PIPE_FENCE        = 4,
+    };
+
+    // magic numbers for native handles
+    enum : int32_t {
+        SYNC_FENCE_DEPRECATED_MAGIC     = 3,
+        SYNC_FENCE_UNORDERED_MAGIC      = '\302fsu',
+        SYNC_FENCE_MAGIC                = '\302fso',
     };
 
     virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0;
@@ -54,7 +65,8 @@
 
     /**
      * Create a native handle for the fence so it can be marshalled.
-     * The native handle must store fence type in the first integer.
+     * All native handles must store fence type in the last integer.
+     * The created native handle (if not null) must be closed by the caller.
      *
      * \return a valid native handle if the fence can be marshalled, otherwise return null.
      */
@@ -64,11 +76,29 @@
 
     Impl() = default;
 
+    /**
+     * Get the type of the fence from the native handle.
+     *
+     * \param nh the native handle to get the type from.
+     * \return the type of the fence, or INVALID_FENCE if the native handle is
+     * invalid or malformed.
+     */
     static type_t GetTypeFromNativeHandle(const native_handle_t* nh) {
-        if (nh && nh->numFds >= 0 && nh->numFds <= MAX_FENCE_FDS && nh->numInts > 0) {
-            return static_cast<type_t>(nh->data[nh->numFds]);
+        if (!nh || nh->numFds < 0 || nh->numFds > MAX_FENCE_FDS
+                || nh->numInts < 1 || nh->numInts > MAX_FENCE_INTS) {
+            return INVALID_FENCE;
         }
-        return INVALID_FENCE;
+
+        // the magic number for Codec 2.0 native handles is the last integer
+        switch (nh->data[nh->numFds + nh->numInts - 1]) {
+            case SYNC_FENCE_MAGIC:
+            case SYNC_FENCE_UNORDERED_MAGIC:
+            case SYNC_FENCE_DEPRECATED_MAGIC:
+                return SYNC_FENCE;
+
+            default:
+                return INVALID_FENCE;
+        }
     }
 };
 
@@ -189,6 +219,53 @@
 
 using namespace android;
 
+/**
+ * Implementation for a sync fence.
+ *
+ * A sync fence is fundamentally a fence that is created from an android sync
+ * fd (which represents a HW fence).
+ *
+ * The native handle layout for a single sync fence is:
+ *   fd[0]  - sync fd
+ *   int[0] - magic (SYNC_FENCE_MAGIC (=`\302fso'))
+ *
+ * Note: Between Android T and 24Q3, the magic number was erroneously
+ * SYNC_FENCE (=3).
+ *
+ * Multi(ple) Sync Fences
+ *
+ * Since Android 24Q3, this implementation also supports a sequence of
+ * sync fences. When this is the case, there is an expectation that the last
+ * sync fence being ready will guarantee that all other sync fences are
+ * also ready. (This guarantees backward compatibility to a single fd sync fence,
+ * and mFence will be that final fence.)
+ *
+ * It is furthermore recommended that the fences be in order - either by
+ * expected signaling time, or by the order in which they need to be ready. The
+ * specific ordering is not specified or enforced, but it could be an
+ * implementation requirement of the specific use case in the future.
+ *
+ * This implementation also supports an unordered set of sync fences. In this
+ * case, it will merge all the fences into a single merged fence, which will
+ * be the backward compatible singular fence (stored in mFence).
+ *
+ * The native handle layout for an unordered multi-fence sync fence (from Android
+ * 24Q3) is:
+ *
+ *   fd[0]   - sync fd 1
+ *   ...
+ *   fd[n-1] - sync fd N
+ *   fd[n]   - merged fence fd
+ *   int[0]  - magic (SYNC_FENCE_UNORDERED_MAGIC (='\302fsu'))
+ *
+ * The native handle layout for an ordered multi-fence sync fence (from Android
+ * 24Q3) is:
+ *
+ *   fd[0]   - sync fd 1
+ *   ...
+ *   fd[n-1] - sync fd N
+ *   int[0]  - magic (SYNC_FENCE_MAGIC (='\302fso'))
+ */
 class _C2FenceFactory::SyncFenceImpl : public C2Fence::Impl {
 public:
     virtual c2_status_t wait(c2_nsecs_t timeoutNs) {
@@ -218,11 +295,19 @@
         return mFence->dup();
     }
 
+    /**
+     * Returns a duped list of fds used when creating this fence. It will
+     * not return the internally created merged fence fd.
+     */
     std::vector<int> fds() const {
         std::vector<int> retFds;
         for (int index = 0; index < mListFences.size(); index++) {
             retFds.push_back(mListFences[index]->dup());
         }
+        // ensure that at least one fd is returned
+        if (mListFences.empty()) {
+            retFds.push_back(mFence->dup());
+        }
         return retFds;
     }
 
@@ -236,7 +321,18 @@
 
     virtual native_handle_t *createNativeHandle() const {
         std::vector<int> nativeFds = fds();
-        nativeFds.push_back(fd());
+        int32_t magic = SYNC_FENCE_MAGIC;
+
+        // Also parcel the singular fence if it is not already part of the list.
+        // If this was a single-fd fence, mListFences will be empty, but fds()
+        // already returned that a list with that single fd.
+        if (!mListFences.empty() && mListFences.back() != mFence) {
+            nativeFds.push_back(fd());
+            if (!mListFences.empty()) {
+                magic = SYNC_FENCE_UNORDERED_MAGIC;
+            }
+        }
+
         native_handle_t* nh = native_handle_create(nativeFds.size(), 1);
         if (!nh) {
             ALOGE("Failed to allocate native handle for sync fence");
@@ -249,71 +345,122 @@
         for (int i = 0; i < nativeFds.size(); i++) {
             nh->data[i] = nativeFds[i];
         }
-        nh->data[nativeFds.size()] = type();
+        nh->data[nativeFds.size()] = magic;
         return nh;
     }
 
     virtual ~SyncFenceImpl() {};
 
+    /**
+     * Constructs a SyncFenceImpl from a single sync fd. No error checking is
+     * performed on the fd here as we cannot make this a null fence.
+     *
+     * \param fenceFd the fence fd to create the SyncFenceImpl from.
+     */
     SyncFenceImpl(int fenceFd) :
         mFence(sp<Fence>::make(fenceFd)) {
-        mListFences.clear();
-        if (mFence) {
-            mListFences.push_back(mFence);
-        }
     }
 
-    SyncFenceImpl(const std::vector<int>& fenceFds, int mergedFd) {
-        mListFences.clear();
-
-        for (int fenceFd : fenceFds) {
-            if (fenceFd < 0) {
-                continue;
-            } else {
-                mListFences.push_back(sp<Fence>::make(fenceFd));
-                if (!mListFences.back()) {
-                    mFence.clear();
-                    break;
-                }
-                if (mergedFd == -1) {
-                    mFence = (mFence == nullptr) ? (mListFences.back()) :
-                        (Fence::merge("syncFence", mFence, mListFences.back()));
-                }
-            }
-        }
-        if (mergedFd != -1)
-        {
-            mFence = sp<Fence>::make(mergedFd);
-        }
-        if (!mFence) {
-            mListFences.clear();
-        }
+    SyncFenceImpl(const sp<Fence> &fence) :
+        mFence(fence) {
     }
 
-    static std::shared_ptr<SyncFenceImpl> CreateFromNativeHandle(const native_handle_t* nh) {
-        if (!nh || nh->numFds < 1 || nh->numInts < 1) {
-            ALOGE("Invalid handle for sync fence");
+    /**
+     * Constructs a SyncFenceImpl from a list of sync fds.
+     *
+     * \param fenceFds the list of fence fds to create the SyncFenceImpl from.
+     * \param finalFence the singular fence for this multi-fd fence. This can
+     * be either the last fence in fences or a sepearate (merged) fence.
+     */
+    SyncFenceImpl(const std::vector<sp<Fence>>& fences, const sp<Fence> &finalFence) :
+        mListFences(fences),
+        mFence(finalFence) {
+    }
+
+    /**
+     * Creates a SyncFenceImpl from a native handle.
+     *
+     * \param nh the native handle to create the SyncFenceImpl from.
+     * \param takeOwnership if true, the SyncFenceImpl will take ownership of the
+     *                      file descriptors in the native handle. Otherwise,
+     *                      the SyncFenceImpl will dup the file descriptors.
+     *
+     * \return a shared_ptr to the SyncFenceImpl, or nullptr if the native
+     * handle is invalid or malformed.
+    */
+    static std::shared_ptr<SyncFenceImpl> CreateFromNativeHandle(
+            const native_handle_t* nh, bool takeOwnership) {
+        // we should only call this method if _C2FenceFactory::GetTypeFromNativeHandle
+        // returned SYNC_FENCE, but do these checks anyways to avoid overflows
+        // in case that does not happen.
+        if (!nh) {
+            ALOGE("Invalid handle for a sync fence (nullptr)");
+            return nullptr;
+        } else if (nh->numFds < 1 || nh->numInts < 1
+                || nh->numFds > MAX_FENCE_FDS || nh->numInts > MAX_FENCE_INTS) {
+            ALOGE("Invalid handle for a sync fence (%d fds, %d ints)", nh->numFds, nh->numInts);
             return nullptr;
         }
-        std::vector<int> fds;
-        for (int i = 0; i < nh->numFds-1; i++) {
-            fds.push_back(dup(nh->data[i]));
-        }
-        std::shared_ptr<SyncFenceImpl> p = (nh->numFds == 1)?
-                (std::make_shared<SyncFenceImpl>(fds.back())):
-                (std::make_shared<SyncFenceImpl>(fds, (dup(nh->data[nh->numFds-1]))));
-        if (!p) {
-            ALOGE("Failed to allocate sync fence impl");
-            for (int fd : fds) {
-                close(fd);
+        std::vector<sp<Fence>> fences;
+        for (int i = 0; i < nh->numFds; i++) {
+            int fd = nh->data[i];
+            if (!takeOwnership && fd >= 0) {
+                fd = dup(fd);
+            }
+            if (fd >= 0) {
+                sp<Fence> fence = sp<Fence>::make(fd);
+                if (fence) {
+                    fences.push_back(fence);
+                } else {
+                    ALOGW("Failed to create fence from fd %d", fd);
+                }
             }
         }
+
+        std::shared_ptr<SyncFenceImpl> p;
+        if (fences.size() == 0) {
+            ALOGE("No valid fences found in handle for a sync fence");
+            return nullptr;
+        } else if (fences.size() == 1) {
+            p = std::make_shared<SyncFenceImpl>(fences[0]);
+        } else {
+            int32_t magic = nh->data[nh->numFds + nh->numInts - 1];
+            if (magic != SYNC_FENCE_MAGIC) {
+                // The last fence is the merged fence. Separate it.
+                sp<Fence> finalFence = fences.back();
+                fences.pop_back();
+
+                // Special case: if we end up with only a single element list
+                // with another merged fence, that merged fence must be the
+                // same fence. This happened in an early version of multi fd
+                // support for single-fd sync fences.
+                if (fences.size() == 1) {
+                    // For single-fd fence the sp-s must be equal
+                    finalFence = fences.back();
+                }
+                p = std::make_shared<SyncFenceImpl>(fences, finalFence);
+            } else {
+                // Use the last fence as the standalone fence.
+                p = std::make_shared<SyncFenceImpl>(fences, fences.back());
+            }
+        }
+
+        ALOGE_IF(!p, "Failed to allocate sync fence impl");
         return p;
     }
 
 private:
+    /**
+     * The list of fences in case of a multi-fence sync fence. Otherwise, this
+     * list is empty.
+     */
     std::vector<sp<Fence>> mListFences;
-    sp<Fence> mFence;  //merged fence in case mListFences size > 0
+
+    /**
+     * The singular fence for this sync fence. For multi-fence sync fences,
+     * this could be a merged fence, or simply the final fence.
+     */
+    sp<Fence> mFence;
 };
 
 std::vector<int> ExtractFdsFromCodec2SyncFence(const C2Fence& fence) {
@@ -324,39 +471,155 @@
     return retFds;
 }
 
-C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd) {
+C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd, bool validate) {
     std::shared_ptr<C2Fence::Impl> p;
     if (fenceFd >= 0) {
         p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fenceFd);
         if (!p) {
             ALOGE("Failed to allocate sync fence impl");
             close(fenceFd);
-        } else if (!p->valid()) {
+        } else if (validate && (!p->valid() || p->ready())) {
+            // don't create a fence object if the sync fd already signaled or is invalid
             p.reset();
         }
     } else {
-        ALOGV("Create sync fence from invalid fd");
-        return C2Fence();
+        ALOGV("Won't create sync fence from invalid fd");
     }
     return C2Fence(p);
 }
 
-C2Fence _C2FenceFactory::CreateMultipleFdSyncFence(const std::vector<int>& fenceFds) {
-    std::shared_ptr<C2Fence::Impl> p;
-    if (fenceFds.size() > 0) {
-        p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fenceFds, -1);
-        if (!p) {
-            ALOGE("Failed to allocate sync fence impl closing FDs");
-            for (int fenceFd : fenceFds) {
-                close(fenceFd);
-            }
-        } else if (!p->valid()) {
-            ALOGE("Invalid sync fence created");
-            p.reset();
-        }
-    } else {
-        ALOGE("Create sync fence from invalid fd list of size 0");
+C2Fence _C2FenceFactory::CreateUnorderedMultiSyncFence(
+        const std::vector<int>& fenceFds, c2_status_t *status) {
+    if (status) {
+        *status = C2_OK;
     }
+
+    sp<Fence> finalFence;
+    std::vector<sp<Fence>> fences;
+
+    bool mergeFailed = false;
+    for (int fenceFd : fenceFds) {
+        if (fenceFd < 0) {
+            // ignore invalid fences
+            continue;
+        }
+        sp<Fence> fence = sp<Fence>::make(fenceFd);
+
+        // If we could not create an sp, further sp-s will also fail.
+        if (fence == nullptr) {
+            if (status) {
+                *status = C2_NO_MEMORY;
+            }
+            break;
+        }
+        fences.push_back(fence);
+
+        if (finalFence == nullptr) {
+            finalFence = fence;
+        } else {
+            sp<Fence> mergedFence = Fence::merge("syncFence", finalFence, fence);
+            if (mergedFence == nullptr || mergedFence == Fence::NO_FENCE) {
+                ALOGE_IF(!mergeFailed, "Could not merge fences for sync fence.");
+                mergeFailed = true;
+                if (status) {
+                    *status = (mergedFence == nullptr) ? C2_NO_MEMORY : C2_CORRUPTED;
+                }
+
+                if (mergedFence == nullptr) {
+                    break;
+                }
+                // If we cannot merge one of the fences, the best course of action
+                // is to keep going, as the alternative would be to clear all fences
+                // (making this a null fence) but that will always be ready.
+            } else {
+                finalFence = mergedFence;
+            }
+        }
+    }
+
+    // we may have ended up with a single or no fence due to merging failures or
+    // invalid fds.
+    if (fences.size() == 0) {
+        // we have no fds, we have a null fence.
+        return C2Fence();
+    }
+
+    std::shared_ptr<C2Fence::Impl> p;
+
+    if (fences.size() == 1) {
+        // We have a single sync fd. We don't need the merged fence, which is
+        // already simply that sole fence.
+        p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(finalFence);
+    } else {
+        // if we couldn't merge any fences just use the last one
+        if (finalFence == fences[0]) {
+            finalFence = fences.back();
+        }
+
+        p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fences, finalFence);
+    }
+
+    if (!p) {
+        ALOGE("Failed to allocate sync fence impl closing FDs");
+        // all fds were moved into Fence objects which will close them.
+        if (status) {
+            *status = C2_NO_MEMORY;
+        }
+        return C2Fence();
+    }
+
+    return C2Fence(p);
+}
+
+C2Fence _C2FenceFactory::CreateMultiSyncFence(
+        const std::vector<int>& fenceFds, c2_status_t *status) {
+    if (status) {
+        *status = C2_OK;
+    }
+
+    std::vector<sp<Fence>> fences;
+
+    for (int fenceFd : fenceFds) {
+        if (fenceFd < 0) {
+            // ignore invalid fences
+            continue;
+        }
+        sp<Fence> fence = sp<Fence>::make(fenceFd);
+
+        // If we could not create an sp, keep going with the existing fences.
+        if (fence == nullptr) {
+            if (status) {
+                *status = C2_NO_MEMORY;
+            }
+            break;
+        }
+        fences.push_back(fence);
+    }
+
+    // we may have ended up with a single or no fence due to invalid fds.
+    if (fences.size() == 0) {
+        // we have no fds, we have a null fence.
+        return C2Fence();
+    }
+
+    std::shared_ptr<C2Fence::Impl> p;
+
+    if (fences.size() == 1) {
+        // We have a single sync fd, this is a simple sync fence.
+        p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fences[0]);
+    } else {
+        p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fences, fences.back());
+    }
+
+    if (!p) {
+        ALOGE("Failed to allocate sync fence impl closing FDs");
+        // all fds were moved into Fence objects which will close them.
+        if (status) {
+            *status = C2_NO_MEMORY;
+        }
+        return C2Fence();
+    }
+
     return C2Fence(p);
 }
 
@@ -521,7 +784,8 @@
     return fence.mImpl? fence.mImpl->createNativeHandle() : nullptr;
 }
 
-C2Fence _C2FenceFactory::CreateFromNativeHandle(const native_handle_t* handle) {
+C2Fence _C2FenceFactory::CreateFromNativeHandle(
+        const native_handle_t* handle, bool takeOwnership) {
     if (!handle) {
         return C2Fence();
     }
@@ -529,11 +793,14 @@
     std::shared_ptr<C2Fence::Impl> p;
     switch (type) {
         case C2Fence::Impl::SYNC_FENCE:
-            p = SyncFenceImpl::CreateFromNativeHandle(handle);
+            p = SyncFenceImpl::CreateFromNativeHandle(handle, takeOwnership);
             break;
         default:
             ALOGV("Unsupported fence type %d", type);
-            // Nothing else to do. The handle is owned by the caller.
+            // Still close the handle here if taking ownership.
+            if (takeOwnership) {
+                (void) native_handle_close(handle);
+            }
             // return a null-fence in this case
             break;
     }
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index e7fd14f..0987da2 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -478,13 +478,25 @@
 
 class _C2BlockPoolCache {
 public:
-    _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
+    _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {
+        mBqPoolDeferDeallocAfterStop = false;
+#ifdef __ANDROID_APEX__
+        bool stopHalBeforeSurface = ::android::base::GetBoolProperty(
+                "debug.codec2.stop_hal_before_surface", false);
+        if (!stopHalBeforeSurface) {
+            mBqPoolDeferDeallocAfterStop =
+                    ::android::base::GetIntProperty(
+                            "debug.codec2.bqpool_dealloc_after_stop", 0) != 0;
+        }
+#endif
+    }
 
 private:
     c2_status_t _createBlockPool(
             C2PlatformAllocatorDesc &allocatorParam,
             std::vector<std::shared_ptr<const C2Component>> components,
             C2BlockPool::local_id_t poolId,
+            bool deferDeallocAfterStop,
             std::shared_ptr<C2BlockPool> *pool) {
         std::shared_ptr<C2AllocatorStore> allocatorStore =
                 GetCodec2PlatformAllocatorStore();
@@ -548,6 +560,11 @@
                 if (res == C2_OK) {
                     std::shared_ptr<C2BlockPool> ptr(
                             new C2BufferQueueBlockPool(allocator, poolId), deleter);
+                    if (deferDeallocAfterStop) {
+                        std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+                            std::static_pointer_cast<C2BufferQueueBlockPool>(ptr);
+                        bqPool->setDeferDeallocationAfterStop();
+                    }
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
                     mComponents[poolId].insert(
@@ -603,7 +620,8 @@
             std::vector<std::shared_ptr<const C2Component>> components,
             std::shared_ptr<C2BlockPool> *pool) {
         std::unique_lock lock(mMutex);
-        return _createBlockPool(allocator, components, mBlockPoolSeqId++, pool);
+        return _createBlockPool(allocator, components, mBlockPoolSeqId++,
+                                mBqPoolDeferDeallocAfterStop, pool);
     }
 
 
@@ -638,7 +656,7 @@
             C2PlatformAllocatorDesc allocator;
             allocator.allocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
             return _createBlockPool(
-                    allocator, {component}, blockPoolId, pool);
+                    allocator, {component}, blockPoolId, mBqPoolDeferDeallocAfterStop, pool);
         }
         return C2_NOT_FOUND;
     }
@@ -651,6 +669,8 @@
 
     std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
     std::map<C2BlockPool::local_id_t, std::vector<std::weak_ptr<const C2Component>>> mComponents;
+
+    bool mBqPoolDeferDeallocAfterStop;
 };
 
 static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index 320b192..1e8dd40 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -28,6 +28,24 @@
 class GraphicBuffer;
 }  // namespace android
 
+/**
+ * BufferQueue based BlockPool.
+ *
+ * This creates graphic blocks from BufferQueue. BufferQueue here is HIDL-ized IGBP.
+ * HIDL-ized IGBP enables vendor HAL to call IGBP interfaces via HIDL over process boundary.
+ * HIDL-ized IGBP is called as HGBP. HGBP had been used from multiple places in android,
+ * but now this is the only place HGBP is still used.
+ *
+ * Initially there is no HGBP configured, in the case graphic blocks are allocated
+ * from gralloc directly upon \fetchGraphicBlock() requests.
+ *
+ * HGBP can be configured as null as well, in the case graphic blocks are allocated
+ * from gralloc directly upon \fetchGraphicBlock() requests.
+ *
+ * If a specific HGBP is configured, the HGBP acts as an allocator for creating graphic blocks.
+ *
+ * TODO: add more ducumentation(graphic block life-cycle, waitable object and workaounds)
+ */
 class C2BufferQueueBlockPool : public C2BlockPool {
 public:
     C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
@@ -77,6 +95,8 @@
      * is configured as nullptr, unique id which is bundled in native_handle is zero.
      *
      * \param producer      the IGBP, which will be used to fetch blocks
+     *                      This could be null, in the case this blockpool will
+     *                      allocate backed GraphicBuffer via allocator(gralloc).
      */
     virtual void configureProducer(const android::sp<HGraphicBufferProducer> &producer);
 
@@ -89,6 +109,8 @@
      * is configured as nullptr, unique id which is bundled in native_handle is zero.
      *
      * \param producer      the IGBP, which will be used to fetch blocks
+     *                      This could be null, in the case this blockpool will
+     *                      allocate backed GraphicBuffer via allocator(gralloc).
      * \param syncMemory    Shared memory for synchronization of allocation & deallocation.
      * \param bqId          Id of IGBP
      * \param generationId  Generation Id for rendering output
@@ -110,6 +132,26 @@
      */
     virtual void invalidate();
 
+    /**
+     * Defer deallocation of cached blocks.
+     *
+     * Deallocation of cached blocks will be deferred until
+     * \clearDeferredBlocks() is called. Or a new block allocation is
+     * requested by \fetchGraphicBlock().
+     */
+    void setDeferDeallocationAfterStop();
+
+
+    /**
+     * Clear deferred blocks.
+     *
+     * Deallocation of cached blocks can be deferred by
+     * \setDeferDeallocationAfterStop().
+     * clear(deallocate) those deferred cached blocks explicitly.
+     * Use this interface, if the blockpool could be inactive indefinitely.
+     */
+    void clearDeferredBlocks();
+
 private:
     const std::shared_ptr<C2Allocator> mAllocator;
     const local_id_t mLocalId;
diff --git a/media/codec2/vndk/include/C2FenceFactory.h b/media/codec2/vndk/include/C2FenceFactory.h
index 4f974ca..cabd5d9 100644
--- a/media/codec2/vndk/include/C2FenceFactory.h
+++ b/media/codec2/vndk/include/C2FenceFactory.h
@@ -23,13 +23,19 @@
 #include <android-base/unique_fd.h>
 
 /*
- * Create a list of fds from fence
+ * Extract a list of sync fence fds from a potentially multi-sync C2Fence.
+ * This will return dupped file descriptors of the fences used to creating the
+ * sync fence. Specifically, for an unordered mult-sync fence, the merged
+ * singular fence will not be returned even though it is created aspart of
+ * constructing the C2Fence object. On the other hand, for a single fd sync
+ * fence, the returned list will contain the sole file descriptor.
  *
  * \param fence   C2Fence object from which associated
  *                file descriptors need to be extracted
- * \return a vector of fds otherwise return vector of size 0
+ * \return a vector of sync fence fds. This will be a vector of size 0 if C2Fence
+ *         is not a sync fence. The caller is responsible for closing the
+ *         fds in the returned vector.
  */
-
 std::vector<int> ExtractFdsFromCodec2SyncFence(const C2Fence& fence);
 
 class C2SurfaceSyncMemory;
@@ -54,20 +60,76 @@
             uint32_t waitId);
 
     /*
-     * Create C2Fence from a fence file fd.
+     * Create C2Fence from a sync fence fd.
      *
-     * \param fenceFd           Fence file descriptor.
+     * \param fenceFd           Sync fence file descriptor.
      *                          It will be owned and closed by the returned fence object.
+     * \param validate          If true, the fence fd will be validated to ensure
+     *                          it is a valid pending sync fence fd.
      */
-    static C2Fence CreateSyncFence(int fenceFd);
+    static C2Fence CreateSyncFence(int fenceFd, bool validate = true);
 
     /*
-     * Create C2Fence from list of fence file fds.
+     * Create C2Fence from list of sync fence fds, while also merging them to
+     * create a singular fence, which can be used as a backward compatible sync
+     * fence.
      *
-     * \param fenceFds          Vector of file descriptor for fence.
-     *                          It will be owned and closed by the returned fence object.
+     * \param fenceFds   Vector of sync fence file descriptors.
+     *                   All file descriptors will be owned (and closed) by
+     *                   the returned fence object.
      */
-    static C2Fence CreateMultipleFdSyncFence(const std::vector<int>& fenceFds);
+    [[deprecated("Use CreateUnorderedMultiSyncFence instead.")]]
+    static C2Fence CreateMultipleFdSyncFence(const std::vector<int>& fenceFds) {
+        return CreateUnorderedMultiSyncFence(fenceFds);
+    }
+
+    /*
+     * Create C2Fence from a list of unordered sync fence fds, while also merging
+     * them to create a singular fence, which can be used as a backward compatible
+     * sync fence.
+     *
+     * \param fenceFds   Vector of sync fence file descriptors.
+     *                   All file descriptors will be owned (and closed) by
+     *                   the returned fence object.
+     * \param status     Optional pointer to a status field. If not null, it will be
+     *                   updated with the status of the operation. Possible values
+     *                   are:
+     *                   - C2_OK: The operation succeeded.
+     *                   - C2_NO_MEMORY: The operation failed because of lack of
+     *                     memory.
+     *                   - C2_CORRUPTED: The operation failed because the sync
+     *                     fence fds could bot be merged.
+     * \return           A C2Fence object representing the sync fence fds, or
+     *                   an empty C2Fence if the no C2Fence could be created.
+     *                   It is possible for the operation to fail but still return
+     *                   a possibly viable C2Fence object, e.g. if the merge
+     *                   operation failed only partially. Similarly, it is possible
+     *                   for the operation to succeed but still return an empty
+     *                   C2Fence object, e.g. if all fence fds were invalid.
+     */
+    static C2Fence CreateUnorderedMultiSyncFence(
+            const std::vector<int>& fenceFds, c2_status_t *status = nullptr /* nullable */);
+
+    /*
+     * Create C2Fence from a list of sync fence fds. Waiting for the last fence
+     * must guarantee that all other fences are also signaled.
+     *
+     * \param fenceFds   Vector of sync fence file descriptors.
+     *                   All file descriptors will be owned (and closed) by
+     *                   the returned fence object.
+     * \param status     Optional pointer to a status field. If not null, it will be
+     *                   updated with the status of the operation. Possible values
+     *                   are:
+     *                   - C2_OK: The operation succeeded.
+     *                   - C2_NO_MEMORY: The operation failed because of lack of
+     *                     memory.
+     * \return           A C2Fence object representing the sync fence fds, or
+     *                   an empty C2Fence if the operation failed.  It is possible
+     *                   for the operation to succeed but still return an empty
+     *                   C2Fence object, e.g. if all fence fds were invalid.
+     */
+    static C2Fence CreateMultiSyncFence(
+            const std::vector<int>& fenceFds, c2_status_t *status = nullptr /* nullable */);
 
     /*
      * Create C2Fence from an fd created by pipe()/pipe2() syscall.
@@ -97,13 +159,18 @@
 
     /*
      * Create C2Fence from a native handle.
-
+     *
      * \param handle           A native handle representing a fence
-     *                         The fd in the native handle will be duplicated, so the caller will
-     *                         still own the handle and have to close it.
+     * \param takeOwnership    If true, the native handle and the file descriptors
+     *                         within will be owned by the returned fence object.
+     *                         If false (default), the caller will still own the
+     *                         handle and its file descriptors and will have to
+     *                         close it.
+     *                         In either case the caller is responsible for
+     *                         deleting the native handle.
      */
-    static C2Fence CreateFromNativeHandle(const native_handle_t* handle);
+    static C2Fence CreateFromNativeHandle(
+            const native_handle_t* handle, bool takeOwnership = false);
 };
 
-
 #endif // STAGEFRIGHT_CODEC2_FENCE_FACTORY_H_
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 48157c8..665f9fc 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -588,11 +588,22 @@
         return C2_BAD_VALUE;
     }
 
+    void clearDeferredBlocks_l() {
+        if (mHavingDeallocationDeferred) {
+            mHavingDeallocationDeferred = false;
+            for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
+                mBuffersWithDeallocationDeferred[i].clear();
+            }
+        }
+    }
+
 public:
     Impl(const std::shared_ptr<C2Allocator> &allocator)
         : mInit(C2_OK), mProducerId(0), mGeneration(0),
           mConsumerUsage(0), mDqFailure(0), mLastDqTs(0),
-          mLastDqLogTs(0), mAllocator(allocator), mIgbpValidityToken(std::make_shared<int>(0)) {
+          mLastDqLogTs(0), mAllocator(allocator),
+          mDeferDeallocationAfterStop(false),
+          mHavingDeallocationDeferred(false), mIgbpValidityToken(std::make_shared<int>(0)) {
     }
 
     ~Impl() {
@@ -634,6 +645,7 @@
             }
         }
         if (mProducerId == 0) {
+            clearDeferredBlocks_l();
             std::shared_ptr<C2GraphicAllocation> alloc;
             c2_status_t err = mAllocator->newGraphicAllocation(
                     width, height, format, usage, &alloc);
@@ -692,6 +704,7 @@
                            uint32_t generation,
                            uint64_t usage,
                            bool bqInformation) {
+        bool toNullSurface = false;
         std::shared_ptr<C2SurfaceSyncMemory> c2SyncMem;
         if (syncHandle) {
             if (!producer) {
@@ -714,6 +727,9 @@
                 mProducerId = producerId;
                 mGeneration = bqInformation ? generation : 0;
             } else {
+                if (mProducer) {
+                    toNullSurface = true;
+                }
                 mProducer = nullptr;
                 mProducerId = 0;
                 mGeneration = 0;
@@ -760,6 +776,17 @@
                 // old buffers should not be cancelled since the associated IGBP
                 // is no longer valid.
                 mIgbpValidityToken = std::make_shared<int>(0);
+                if (mDeferDeallocationAfterStop) {
+                    if (toNullSurface) {
+                        mHavingDeallocationDeferred = true;
+                        for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
+                            mBuffersWithDeallocationDeferred[i] = mBuffers[i];
+                        }
+                    }
+                }
+            }
+            if (!toNullSurface) {
+                clearDeferredBlocks_l();
             }
             if (mInvalidated) {
                 mIgbpValidityToken = std::make_shared<int>(0);
@@ -811,6 +838,16 @@
         }
     }
 
+    void setDeferDeallocationAfterStop() {
+        std::scoped_lock<std::mutex> lock(mMutex);
+        mDeferDeallocationAfterStop = true;
+    }
+
+    void clearDeferredBlocks() {
+        std::scoped_lock<std::mutex> lock(mMutex);
+        clearDeferredBlocks_l();
+    }
+
 private:
     friend struct C2BufferQueueBlockPoolData;
 
@@ -833,6 +870,14 @@
     sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
     std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
 
+    // In order to workaround b/322731059,
+    // deallocating buffers due to stop using the current surface
+    // could be deferred until the component calling stop or a
+    // new allocation being requested.
+    bool mDeferDeallocationAfterStop;
+    bool mHavingDeallocationDeferred;
+    sp<GraphicBuffer> mBuffersWithDeallocationDeferred[NUM_BUFFER_SLOTS];
+
     std::mutex mSyncMemMutex;
     std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
     std::shared_ptr<C2SurfaceSyncMemory> mOldMem;
@@ -1178,3 +1223,15 @@
     }
 }
 
+void C2BufferQueueBlockPool::setDeferDeallocationAfterStop() {
+    if (mImpl) {
+        mImpl->setDeferDeallocationAfterStop();
+    }
+}
+
+void C2BufferQueueBlockPool::clearDeferredBlocks() {
+    if (mImpl) {
+        mImpl->clearDeferredBlocks();
+    }
+}
+
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index b2e93f0..fa3f5a0 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -620,17 +620,19 @@
                                                  audio_port_handle_t *portHandle) {
     ALOGV("%s() called", __func__);
     if (getServiceHandle() == AAUDIO_HANDLE_INVALID) {
+        ALOGE("%s() getServiceHandle() is invalid", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }
     aaudio_result_t result =  mServiceInterface.startClient(mServiceStreamHandleInfo,
                                                             client, attr, portHandle);
-    ALOGV("%s(%d) returning %d", __func__, *portHandle, result);
+    ALOGV("%s(), got %d, returning %d", __func__, *portHandle, result);
     return result;
 }
 
 aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t portHandle) {
     ALOGV("%s(%d) called", __func__, portHandle);
     if (getServiceHandle() == AAUDIO_HANDLE_INVALID) {
+        ALOGE("%s(%d) getServiceHandle() is invalid", __func__, portHandle);
         return AAUDIO_ERROR_INVALID_STATE;
     }
     aaudio_result_t result = mServiceInterface.stopClient(mServiceStreamHandleInfo, portHandle);
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 8595308..255bd0f 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -261,6 +261,11 @@
 
 void AudioStreamLegacy::onAudioDeviceUpdate(audio_io_handle_t /* audioIo */,
             audio_port_handle_t deviceId) {
+    // Check for an invalid deviceId. Why change to UNSPECIFIED?
+    if (deviceId == AAUDIO_UNSPECIFIED) {
+        ALOGE("%s(, deviceId = AAUDIO_UNSPECIFIED)! Why?", __func__);
+        return;
+    }
     // Device routing is a common source of errors and DISCONNECTS.
     // Please leave this log in place. If there is a bug then this might
     // get called after the stream has been deleted so log before we
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6772201..85cc9bd 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1174,6 +1174,13 @@
     mSampleRate = rate;
     mProxy->setSampleRate(effectiveSampleRate);
 
+    mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETSAMPLERATE)
+            .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE AMEDIAMETRICS_PROP_SAMPLERATE,
+                    static_cast<int32_t>(effectiveSampleRate))
+            .set(AMEDIAMETRICS_PROP_SAMPLERATE, static_cast<int32_t>(rate))
+            .record();
+
     return NO_ERROR;
 }
 
@@ -3035,6 +3042,7 @@
         const sp<VolumeShaper::Configuration>& configuration,
         const sp<VolumeShaper::Operation>& operation)
 {
+    const int64_t beginNs = systemTime();
     AutoMutex lock(mLock);
     mVolumeHandler->setIdIfNecessary(configuration);
     media::VolumeShaperConfiguration config;
@@ -3042,6 +3050,18 @@
     media::VolumeShaperOperation op;
     operation->writeToParcelable(&op);
     VolumeShaper::Status status;
+
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER)
+                .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
+                .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+                .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+                .set(AMEDIAMETRICS_PROP_TOSTRING, configuration->toString()
+                                 .append(" ")
+                                 .append(operation->toString()))
+                .record(); });
+
     mAudioTrack->applyVolumeShaper(config, op, &status);
 
     if (status == DEAD_OBJECT) {
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 9c3ad44..ddf14a3 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -134,6 +134,9 @@
         "libaudiomanager",
         "libaudiopolicy",
     ],
+    cflags: [
+        "-Wthread-safety",
+    ],
     data: ["bbb*.raw"],
     srcs: [
         "audio_test_utils.cpp",
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index 0be1d7e..7f55e48 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -483,28 +483,8 @@
                                  AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>(
                                          std::vector<int32_t>{1, 2}))));
 
-TEST(AnonymizedBluetoothAddressRoundTripTest, Legacy2Aidl2Legacy) {
-    const std::vector<uint8_t> sAnonymizedAidlAddress =
-            std::vector<uint8_t>{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/audio_test_utils.cpp b/media/libaudioclient/tests/audio_test_utils.cpp
index 9a202cc3..745c7d1 100644
--- a/media/libaudioclient/tests/audio_test_utils.cpp
+++ b/media/libaudioclient/tests/audio_test_utils.cpp
@@ -28,25 +28,35 @@
 
 void OnAudioDeviceUpdateNotifier::onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                                       audio_port_handle_t deviceId) {
-    std::unique_lock<std::mutex> lock{mMutex};
     ALOGI("%s: audioIo=%d deviceId=%d", __func__, audioIo, deviceId);
-    mAudioIo = audioIo;
-    mDeviceId = deviceId;
+    {
+        std::lock_guard lock(mMutex);
+        mAudioIo = audioIo;
+        mDeviceId = deviceId;
+    }
     mCondition.notify_all();
 }
 
 status_t OnAudioDeviceUpdateNotifier::waitForAudioDeviceCb(audio_port_handle_t expDeviceId) {
-    std::unique_lock<std::mutex> lock{mMutex};
+    std::unique_lock lock(mMutex);
+    android::base::ScopedLockAssertion lock_assertion(mMutex);
     if (mAudioIo == AUDIO_IO_HANDLE_NONE ||
         (expDeviceId != AUDIO_PORT_HANDLE_NONE && expDeviceId != mDeviceId)) {
         mCondition.wait_for(lock, std::chrono::milliseconds(500));
         if (mAudioIo == AUDIO_IO_HANDLE_NONE ||
-            (expDeviceId != AUDIO_PORT_HANDLE_NONE && expDeviceId != mDeviceId))
+            (expDeviceId != AUDIO_PORT_HANDLE_NONE && expDeviceId != mDeviceId)) {
             return TIMED_OUT;
+        }
     }
     return OK;
 }
 
+std::pair<audio_io_handle_t, audio_port_handle_t>
+OnAudioDeviceUpdateNotifier::getLastPortAndDevice() const {
+    std::lock_guard lock(mMutex);
+    return {mAudioIo, mDeviceId};
+}
+
 AudioPlayback::AudioPlayback(uint32_t sampleRate, audio_format_t format,
                              audio_channel_mask_t channelMask, audio_output_flags_t flags,
                              audio_session_t sessionId, AudioTrack::transfer_type transferType,
@@ -147,9 +157,8 @@
 }
 
 void AudioPlayback::onBufferEnd() {
-    std::unique_lock<std::mutex> lock{mMutex};
+    std::lock_guard lock(mMutex);
     mStopPlaying = true;
-    mCondition.notify_all();
 }
 
 status_t AudioPlayback::fillBuffer() {
@@ -187,7 +196,12 @@
     const int maxTries = MAX_WAIT_TIME_MS / WAIT_PERIOD_MS;
     int counter = 0;
     size_t totalFrameCount = mMemCapacity / mTrack->frameSize();
-    while (!mStopPlaying && counter < maxTries) {
+    bool stopPlaying;
+    {
+        std::lock_guard lock(mMutex);
+        stopPlaying = mStopPlaying;
+    }
+    while (!stopPlaying && counter < maxTries) {
         uint32_t currPosition;
         mTrack->getPosition(&currPosition);
         if (currPosition >= totalFrameCount) counter++;
@@ -213,7 +227,10 @@
             mTrack->start();
         }
         std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_PERIOD_MS));
+        std::lock_guard lock(mMutex);
+        stopPlaying = mStopPlaying;
     }
+    std::lock_guard lock(mMutex);
     if (!mStopPlaying && counter == maxTries) return TIMED_OUT;
     return OK;
 }
@@ -228,8 +245,10 @@
 }
 
 void AudioPlayback::stop() {
-    std::unique_lock<std::mutex> lock{mMutex};
-    mStopPlaying = true;
+    {
+        std::lock_guard lock(mMutex);
+        mStopPlaying = true;
+    }
     if (mState != PLAY_STOPPED && mState != PLAY_NO_INIT) {
         int32_t msec = 0;
         (void)mTrack->pendingDuration(&msec);
@@ -257,10 +276,13 @@
         return 0;
     }
 
-    // no more frames to read
-    if (mNumFramesReceived >= mNumFramesToRecord || mStopRecording) {
-        mStopRecording = true;
-        return 0;
+    {
+        std::lock_guard l(mMutex);
+        // no more frames to read
+        if (mNumFramesReceived >= mNumFramesToRecord || mStopRecording) {
+            mStopRecording = true;
+            return 0;
+        }
     }
 
     int64_t timeUs = 0, position = 0, timeNs = 0;
@@ -324,9 +346,12 @@
     }
 
     if (tmpQueue.size() > 0) {
-        std::unique_lock<std::mutex> lock{mMutex};
-        for (auto it = tmpQueue.begin(); it != tmpQueue.end(); it++)
-            mBuffersReceived.push_back(std::move(*it));
+        {
+            std::lock_guard lock(mMutex);
+            mBuffersReceived.insert(mBuffersReceived.end(),
+                                    std::make_move_iterator(tmpQueue.begin()),
+                                    std::make_move_iterator(tmpQueue.end()));
+        }
         mCondition.notify_all();
     }
     return buffer.size();
@@ -484,7 +509,10 @@
 
 status_t AudioCapture::stop() {
     status_t status = OK;
-    mStopRecording = true;
+    {
+        std::lock_guard l(mMutex);
+        mStopRecording = true;
+    }
     if (mState != REC_STOPPED && mState != REC_NO_INIT) {
         if (mInputSource != AUDIO_SOURCE_DEFAULT) {
             bool state = false;
@@ -530,7 +558,8 @@
     if (REC_STARTED != mState) return INVALID_OPERATION;
     const int maxTries = MAX_WAIT_TIME_MS / WAIT_PERIOD_MS;
     int counter = 0;
-    std::unique_lock<std::mutex> lock{mMutex};
+    std::unique_lock lock(mMutex);
+    android::base::ScopedLockAssertion lock_assertion(mMutex);
     while (mBuffersReceived.empty() && !mStopRecording && counter < maxTries) {
         mCondition.wait_for(lock, std::chrono::milliseconds(WAIT_PERIOD_MS));
         counter++;
diff --git a/media/libaudioclient/tests/audio_test_utils.h b/media/libaudioclient/tests/audio_test_utils.h
index 76e4642..40c3365 100644
--- a/media/libaudioclient/tests/audio_test_utils.h
+++ b/media/libaudioclient/tests/audio_test_utils.h
@@ -19,14 +19,13 @@
 
 #include <sys/stat.h>
 #include <unistd.h>
-#include <atomic>
-#include <chrono>
-#include <cinttypes>
 #include <deque>
 #include <memory>
 #include <mutex>
 #include <thread>
+#include <utility>
 
+#include <android-base/thread_annotations.h>
 #include <binder/MemoryDealer.h>
 #include <media/AidlConversion.h>
 #include <media/AudioRecord.h>
@@ -63,13 +62,15 @@
 
 class OnAudioDeviceUpdateNotifier : public AudioSystem::AudioDeviceCallback {
   public:
-    audio_io_handle_t mAudioIo = AUDIO_IO_HANDLE_NONE;
-    audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE;
-    std::mutex mMutex;
-    std::condition_variable mCondition;
-
-    void onAudioDeviceUpdate(audio_io_handle_t audioIo, audio_port_handle_t deviceId);
+    void onAudioDeviceUpdate(audio_io_handle_t audioIo, audio_port_handle_t deviceId) override;
     status_t waitForAudioDeviceCb(audio_port_handle_t expDeviceId = AUDIO_PORT_HANDLE_NONE);
+    std::pair<audio_io_handle_t, audio_port_handle_t> getLastPortAndDevice() const;
+
+  private:
+    audio_io_handle_t mAudioIo GUARDED_BY(mMutex) = AUDIO_IO_HANDLE_NONE;
+    audio_port_handle_t mDeviceId GUARDED_BY(mMutex) = AUDIO_PORT_HANDLE_NONE;
+    mutable std::mutex mMutex;
+    std::condition_variable mCondition;
 };
 
 // Simple AudioPlayback class.
@@ -86,15 +87,14 @@
     status_t create();
     sp<AudioTrack> getAudioTrackHandle();
     status_t start();
-    status_t waitForConsumption(bool testSeek = false);
+    status_t waitForConsumption(bool testSeek = false) EXCLUDES(mMutex);
     status_t fillBuffer();
     status_t onProcess(bool testSeek = false);
-    virtual void onBufferEnd() override;
-    void stop();
+    void onBufferEnd() override EXCLUDES(mMutex);
+    void stop() EXCLUDES(mMutex);
 
-    bool mStopPlaying;
-    std::mutex mMutex;
-    std::condition_variable mCondition;
+    bool mStopPlaying GUARDED_BY(mMutex);
+    mutable std::mutex mMutex;
 
     enum State {
         PLAY_NO_INIT,
@@ -144,7 +144,7 @@
                  AudioRecord::transfer_type transferType = AudioRecord::TRANSFER_CALLBACK,
                  const audio_attributes_t* attributes = nullptr);
     ~AudioCapture();
-    size_t onMoreData(const AudioRecord::Buffer& buffer) override;
+    size_t onMoreData(const AudioRecord::Buffer& buffer) override EXCLUDES(mMutex);
     void onOverrun() override;
     void onMarker(uint32_t markerPosition) override;
     void onNewPos(uint32_t newPos) override;
@@ -156,10 +156,10 @@
     sp<AudioRecord> getAudioRecordHandle();
     status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
                    audio_session_t triggerSession = AUDIO_SESSION_NONE);
-    status_t obtainBufferCb(RawBuffer& buffer);
+    status_t obtainBufferCb(RawBuffer& buffer) EXCLUDES(mMutex);
     status_t obtainBuffer(RawBuffer& buffer);
     status_t audioProcess();
-    status_t stop();
+    status_t stop() EXCLUDES(mMutex);
 
     uint32_t mFrameCount;
     uint32_t mNotificationFrames;
@@ -192,13 +192,13 @@
     size_t mMaxBytesPerCallback = 2048;
     sp<AudioRecord> mRecord;
     State mState;
-    bool mStopRecording;
+    bool mStopRecording GUARDED_BY(mMutex);
     std::string mFileName;
     int mOutFileFd = -1;
 
-    std::mutex mMutex;
+    mutable std::mutex mMutex;
     std::condition_variable mCondition;
-    std::deque<RawBuffer> mBuffersReceived;
+    std::deque<RawBuffer> mBuffersReceived GUARDED_BY(mMutex);
 };
 
 #endif  // AUDIO_TEST_UTILS_H_
diff --git a/media/libaudioclient/tests/audiorecord_tests.cpp b/media/libaudioclient/tests/audiorecord_tests.cpp
index be6c581..9908f33 100644
--- a/media/libaudioclient/tests/audiorecord_tests.cpp
+++ b/media/libaudioclient/tests/audiorecord_tests.cpp
@@ -120,10 +120,12 @@
     EXPECT_EQ(OK, mAC->getAudioRecordHandle()->addAudioDeviceCallback(cb));
     EXPECT_EQ(OK, mAC->start()) << "record creation failed";
     EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
-    EXPECT_EQ(AUDIO_IO_HANDLE_NONE, cbOld->mAudioIo);
-    EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, cbOld->mDeviceId);
-    EXPECT_NE(AUDIO_IO_HANDLE_NONE, cb->mAudioIo);
-    EXPECT_NE(AUDIO_PORT_HANDLE_NONE, cb->mDeviceId);
+    const auto [oldAudioIo, oldDeviceId] = cbOld->getLastPortAndDevice();
+    EXPECT_EQ(AUDIO_IO_HANDLE_NONE, oldAudioIo);
+    EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, oldDeviceId);
+    const auto [audioIo, deviceId] = cb->getLastPortAndDevice();
+    EXPECT_NE(AUDIO_IO_HANDLE_NONE, audioIo);
+    EXPECT_NE(AUDIO_PORT_HANDLE_NONE, deviceId);
     EXPECT_EQ(BAD_VALUE, mAC->getAudioRecordHandle()->removeAudioDeviceCallback(nullptr));
     EXPECT_EQ(INVALID_OPERATION, mAC->getAudioRecordHandle()->removeAudioDeviceCallback(cbOld));
     EXPECT_EQ(OK, mAC->getAudioRecordHandle()->removeAudioDeviceCallback(cb));
@@ -174,6 +176,7 @@
             << "getMarkerPosition() failed";
     EXPECT_EQ(OK, mAC->start()) << "start recording failed";
     EXPECT_EQ(OK, mAC->audioProcess()) << "audioProcess failed";
+    // TODO(b/348658586): Properly synchronize callback updates with the test thread.
     EXPECT_EQ(marker, mAC->mMarkerPosition)
             << "configured marker and received marker are different";
     EXPECT_EQ(mAC->mReceivedCbMarkerAtPosition, mAC->mMarkerPosition)
@@ -189,6 +192,7 @@
             << "getPositionUpdatePeriod() failed";
     EXPECT_EQ(OK, mAC->start()) << "start recording failed";
     EXPECT_EQ(OK, mAC->audioProcess()) << "audioProcess failed";
+    // TODO(b/348658586): Properly synchronize callback updates with the test thread.
     EXPECT_EQ(marker, mAC->mMarkerPeriod) << "configured marker and received marker are different";
     EXPECT_EQ(mAC->mReceivedCbMarkerCount, mAC->mNumFramesToRecord / mAC->mMarkerPeriod)
             << "configured marker and received cb marker are different";
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 3b2285e..8151d39 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -64,16 +64,17 @@
         EXPECT_EQ(OK, ap->start()) << "audio track start failed";
         EXPECT_EQ(OK, ap->onProcess());
         EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
-        EXPECT_TRUE(checkPatchPlayback(cb->mAudioIo, cb->mDeviceId));
+        const auto [audioIo, deviceId] = cb->getLastPortAndDevice();
+        EXPECT_TRUE(checkPatchPlayback(audioIo, deviceId));
         EXPECT_NE(0, ap->getAudioTrackHandle()->getFlags() & output_flags[i]);
         audio_patch patch;
-        EXPECT_EQ(OK, getPatchForOutputMix(cb->mAudioIo, patch));
+        EXPECT_EQ(OK, getPatchForOutputMix(audioIo, patch));
         if (output_flags[i] != AUDIO_OUTPUT_FLAG_FAST) {
             // A "normal" output can still have a FastMixer, depending on the buffer size.
             // Thus, a fast track can be created on a mix port which does not have the FAST flag.
             for (auto j = 0; j < patch.num_sources; j++) {
                 if (patch.sources[j].type == AUDIO_PORT_TYPE_MIX &&
-                    patch.sources[j].ext.mix.handle == cb->mAudioIo) {
+                    patch.sources[j].ext.mix.handle == audioIo) {
                     SCOPED_TRACE(dumpPortConfig(patch.sources[j]));
                     EXPECT_NE(0, patch.sources[j].flags.output & output_flags[i])
                             << "expected output flag "
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index 03c15f4..db998cd 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -108,30 +108,32 @@
 // UNIT TESTS
 TEST_F(AudioSystemTest, CheckServerSideValues) {
     ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
-    EXPECT_GT(mAF->sampleRate(mCbPlayback->mAudioIo), 0);
-    EXPECT_NE(mAF->format(mCbPlayback->mAudioIo), AUDIO_FORMAT_INVALID);
-    EXPECT_GT(mAF->frameCount(mCbPlayback->mAudioIo), 0);
+    const auto [pbAudioIo, _] = mCbPlayback->getLastPortAndDevice();
+    EXPECT_GT(mAF->sampleRate(pbAudioIo), 0);
+    EXPECT_NE(mAF->format(pbAudioIo), AUDIO_FORMAT_INVALID);
+    EXPECT_GT(mAF->frameCount(pbAudioIo), 0);
     size_t frameCountHal, frameCountHalCache;
-    frameCountHal = mAF->frameCountHAL(mCbPlayback->mAudioIo);
+    frameCountHal = mAF->frameCountHAL(pbAudioIo);
     EXPECT_GT(frameCountHal, 0);
-    EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(mCbPlayback->mAudioIo, &frameCountHalCache));
+    EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(pbAudioIo, &frameCountHalCache));
     EXPECT_EQ(frameCountHal, frameCountHalCache);
-    EXPECT_GT(mAF->latency(mCbPlayback->mAudioIo), 0);
+    EXPECT_GT(mAF->latency(pbAudioIo), 0);
     // client side latency is at least server side latency
-    EXPECT_LE(mAF->latency(mCbPlayback->mAudioIo), mPlayback->getAudioTrackHandle()->latency());
+    EXPECT_LE(mAF->latency(pbAudioIo), mPlayback->getAudioTrackHandle()->latency());
 
     ASSERT_NO_FATAL_FAILURE(createRecordSession());
-    EXPECT_GT(mAF->sampleRate(mCbRecord->mAudioIo), 0);
-    // EXPECT_NE(mAF->format(mCbRecord->mAudioIo), AUDIO_FORMAT_INVALID);
-    EXPECT_GT(mAF->frameCount(mCbRecord->mAudioIo), 0);
-    EXPECT_GT(mAF->frameCountHAL(mCbRecord->mAudioIo), 0);
-    frameCountHal = mAF->frameCountHAL(mCbRecord->mAudioIo);
+    const auto [recAudioIo, __] = mCbRecord->getLastPortAndDevice();
+    EXPECT_GT(mAF->sampleRate(recAudioIo), 0);
+    // EXPECT_NE(mAF->format(recAudioIo), AUDIO_FORMAT_INVALID);
+    EXPECT_GT(mAF->frameCount(recAudioIo), 0);
+    EXPECT_GT(mAF->frameCountHAL(recAudioIo), 0);
+    frameCountHal = mAF->frameCountHAL(recAudioIo);
     EXPECT_GT(frameCountHal, 0);
-    EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(mCbRecord->mAudioIo, &frameCountHalCache));
+    EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(recAudioIo, &frameCountHalCache));
     EXPECT_EQ(frameCountHal, frameCountHalCache);
-    // EXPECT_GT(mAF->latency(mCbRecord->mAudioIo), 0);
+    // EXPECT_GT(mAF->latency(recAudioIo), 0);
     // client side latency is at least server side latency
-    // EXPECT_LE(mAF->latency(mCbRecord->mAudioIo), mCapture->getAudioRecordHandle()->latency());
+    // EXPECT_LE(mAF->latency(recAudioIo), mCapture->getAudioRecordHandle()->latency());
 
     EXPECT_GT(AudioSystem::getPrimaryOutputSamplingRate(), 0);  // first fast mixer sample rate
     EXPECT_GT(AudioSystem::getPrimaryOutputFrameCount(), 0);    // fast mixer frame count
@@ -200,8 +202,9 @@
 TEST_F(AudioSystemTest, GetStreamVolume) {
     ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
     float origStreamVol;
-    EXPECT_EQ(NO_ERROR, AudioSystem::getStreamVolume(AUDIO_STREAM_MUSIC, &origStreamVol,
-                                                     mCbPlayback->mAudioIo));
+    const auto [pbAudioIo, _] = mCbPlayback->getLastPortAndDevice();
+    EXPECT_EQ(NO_ERROR,
+              AudioSystem::getStreamVolume(AUDIO_STREAM_MUSIC, &origStreamVol, pbAudioIo));
 }
 
 TEST_F(AudioSystemTest, GetStreamMute) {
diff --git a/media/libaudioclient/tests/audiotrack_tests.cpp b/media/libaudioclient/tests/audiotrack_tests.cpp
index cb667a0..cf7d926 100644
--- a/media/libaudioclient/tests/audiotrack_tests.cpp
+++ b/media/libaudioclient/tests/audiotrack_tests.cpp
@@ -157,18 +157,20 @@
     EXPECT_EQ(OK, ap->start()) << "audio track start failed";
     EXPECT_EQ(OK, ap->onProcess());
     EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
-    EXPECT_EQ(AUDIO_IO_HANDLE_NONE, cbOld->mAudioIo);
-    EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, cbOld->mDeviceId);
-    EXPECT_NE(AUDIO_IO_HANDLE_NONE, cb->mAudioIo);
-    EXPECT_NE(AUDIO_PORT_HANDLE_NONE, cb->mDeviceId);
-    EXPECT_EQ(cb->mAudioIo, ap->getAudioTrackHandle()->getOutput());
-    EXPECT_EQ(cb->mDeviceId, ap->getAudioTrackHandle()->getRoutedDeviceId());
+    const auto [oldAudioIo, oldDeviceId] = cbOld->getLastPortAndDevice();
+    EXPECT_EQ(AUDIO_IO_HANDLE_NONE, oldAudioIo);
+    EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, oldDeviceId);
+    const auto [audioIo, deviceId] = cb->getLastPortAndDevice();
+    EXPECT_NE(AUDIO_IO_HANDLE_NONE, audioIo);
+    EXPECT_NE(AUDIO_PORT_HANDLE_NONE, deviceId);
+    EXPECT_EQ(audioIo, ap->getAudioTrackHandle()->getOutput());
+    EXPECT_EQ(deviceId, ap->getAudioTrackHandle()->getRoutedDeviceId());
     String8 keys;
     keys = ap->getAudioTrackHandle()->getParameters(keys);
     if (!keys.empty()) {
         std::cerr << "track parameters :: " << keys << std::endl;
     }
-    EXPECT_TRUE(checkPatchPlayback(cb->mAudioIo, cb->mDeviceId));
+    EXPECT_TRUE(checkPatchPlayback(audioIo, deviceId));
     EXPECT_EQ(BAD_VALUE, ap->getAudioTrackHandle()->removeAudioDeviceCallback(nullptr));
     EXPECT_EQ(INVALID_OPERATION, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cbOld));
     EXPECT_EQ(OK, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cb));
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 1990858..024589b 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -460,13 +460,17 @@
     args.portConfigId = mixPortConfig.id;
     const bool isOffload = isBitPositionFlagSet(
             aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
+    const bool isHwAvSync = isBitPositionFlagSet(
+            aidlOutputFlags, AudioOutputFlags::HW_AV_SYNC);
     std::shared_ptr<OutputStreamCallbackAidl> streamCb;
     if (isOffload) {
         streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
     }
     auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
-    if (isOffload) {
+    if (isOffload || isHwAvSync) {
         args.offloadInfo = aidlConfig.offloadInfo;
+    }
+    if (isOffload) {
         args.callback = streamCb;
     }
     args.bufferSizeFrames = aidlConfig.frameCount;
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index cbade70..052522f 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -37,6 +37,7 @@
 using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioGainConfig;
 using aidl::android::media::audio::common::AudioInputFlags;
 using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOutputFlags;
@@ -325,8 +326,8 @@
 }
 
 status_t Hal2AidlMapper::findOrCreateDevicePortConfig(
-        const AudioDevice& device, const AudioConfig* config, AudioPortConfig* portConfig,
-        bool* created) {
+        const AudioDevice& device, const AudioConfig* config, const AudioGainConfig* gainConfig,
+        AudioPortConfig* portConfig, bool* created) {
     if (auto portConfigIt = findPortConfig(device); portConfigIt == mPortConfigs.end()) {
         auto portsIt = findPort(device);
         if (portsIt == mPorts.end()) {
@@ -339,12 +340,18 @@
         if (config != nullptr) {
             setPortConfigFromConfig(&requestedPortConfig, *config);
         }
+        if (gainConfig != nullptr) {
+            requestedPortConfig.gain = *gainConfig;
+        }
         return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
     } else {
         AudioPortConfig requestedPortConfig = portConfigIt->second;
         if (config != nullptr) {
             setPortConfigFromConfig(&requestedPortConfig, *config);
         }
+        if (gainConfig != nullptr) {
+            requestedPortConfig.gain = *gainConfig;
+        }
 
         if (requestedPortConfig != portConfigIt->second) {
             return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
@@ -447,18 +454,26 @@
                 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
                 portConfig, created);
     } else if (requestedPortConfig.ext.getTag() == Tag::device) {
-        if (const auto& p = requestedPortConfig;
-                p.sampleRate.has_value() && p.channelMask.has_value() &&
-                p.format.has_value()) {
-            AudioConfig config;
-            setConfigFromPortConfig(&config, requestedPortConfig);
+        const auto& p = requestedPortConfig;
+        const bool hasAudioConfig =
+                p.sampleRate.has_value() && p.channelMask.has_value() && p.format.has_value();
+        const bool hasGainConfig = p.gain.has_value();
+        if (hasAudioConfig || hasGainConfig) {
+            AudioConfig config, *configPtr = nullptr;
+            if (hasAudioConfig) {
+                setConfigFromPortConfig(&config, requestedPortConfig);
+                configPtr = &config;
+            }
+            const AudioGainConfig* gainConfigPtr = nullptr;
+            if (hasGainConfig) gainConfigPtr = &(*(p.gain));
             return findOrCreateDevicePortConfig(
-                    requestedPortConfig.ext.get<Tag::device>().device, &config,
+                    requestedPortConfig.ext.get<Tag::device>().device, configPtr, gainConfigPtr,
                     portConfig, created);
         } else {
+            ALOGD("%s: device port config does not have audio or gain config specified", __func__);
             return findOrCreateDevicePortConfig(
                     requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
-                    portConfig, created);
+                    nullptr /*gainConfig*/, portConfig, created);
         }
     }
     ALOGW("%s: unsupported audio port config: %s",
@@ -769,7 +784,7 @@
     // then find / create a patch between them, and open a stream on the mix port.
     AudioPortConfig devicePortConfig;
     bool created = false;
-    RETURN_STATUS_IF_ERROR(findOrCreateDevicePortConfig(device, config,
+    RETURN_STATUS_IF_ERROR(findOrCreateDevicePortConfig(device, config, nullptr /*gainConfig*/,
                     &devicePortConfig, &created));
     LOG_ALWAYS_FATAL_IF(devicePortConfig.id == 0);
     if (created) {
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
index c70c8af..710b43e 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.h
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -163,6 +163,7 @@
     status_t findOrCreateDevicePortConfig(
             const ::aidl::android::media::audio::common::AudioDevice& device,
             const ::aidl::android::media::audio::common::AudioConfig* config,
+            const ::aidl::android::media::audio::common::AudioGainConfig* gainConfig,
             ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
             bool* created);
     // If the resulting 'portConfig->id' is 0, that means the config was not created,
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
index ca6ff88..7879200 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
@@ -17,6 +17,7 @@
 #include <cstdint>
 #include <cstring>
 #include <optional>
+#include <unordered_set>
 #define LOG_TAG "AidlConversionEQ"
 //#define LOG_NDEBUG 0
 
@@ -262,10 +263,21 @@
         }
         case EQ_PARAM_GET_NUM_OF_PRESETS: {
             Parameter aidlParam = VALUE_OR_RETURN_STATUS(getAidlParameter(Equalizer::presets));
-            const auto& presets = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
+            auto presets = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
                     aidlParam, Equalizer, equalizer, Equalizer::presets,
                     std::vector<Equalizer::Preset>));
-            uint16_t num = presets.size();
+            // it was assumed the presets index in the range of [0, NUM_OF_PRESETS - 1], so
+            // filter out presets out of this range (one example is preset {-1, "custom"})
+            std::erase_if(presets, [](const auto& preset) { return preset.index < 0; });
+            // validate remaining indexes are unique [0, num - 1]
+            std::unordered_set<uint16_t> uniqueIndices;
+            const uint16_t num = presets.size();
+            for (const auto& preset : presets) {
+                if (preset.index >= num || 0 != uniqueIndices.count(preset.index)) {
+                    return BAD_VALUE;
+                }
+                uniqueIndices.insert(preset.index);
+            }
             return param.writeToValue(&num);
         }
         case EQ_PARAM_GET_PRESET_NAME: {
diff --git a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
index 0bd6fb0..50b748e 100644
--- a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
+++ b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
@@ -29,6 +29,7 @@
 #include <aidl/android/hardware/audio/core/BnModule.h>
 #include <aidl/android/hardware/audio/core/BnStreamCommon.h>
 #include <aidl/android/media/audio/BnHalAdapterVendorExtension.h>
+#include <aidl/android/media/audio/common/AudioGainMode.h>
 #include <aidl/android/media/audio/common/Int.h>
 #include <utils/Log.h>
 
@@ -44,6 +45,8 @@
 using ::aidl::android::media::audio::common::AudioDeviceType;
 using ::aidl::android::media::audio::common::AudioFormatDescription;
 using ::aidl::android::media::audio::common::AudioFormatType;
+using ::aidl::android::media::audio::common::AudioGainConfig;
+using ::aidl::android::media::audio::common::AudioGainMode;
 using ::aidl::android::media::audio::common::AudioIoFlags;
 using ::aidl::android::media::audio::common::AudioPort;
 using ::aidl::android::media::audio::common::AudioPortConfig;
@@ -179,6 +182,11 @@
     primaryInMix.profiles = standardPcmAudioProfiles;
     c.ports.push_back(primaryInMix);
 
+    AudioPort speakerOutDevice = createPort(c.nextPortId++, "Speaker", 0, false,
+                                            createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0));
+    speakerOutDevice.profiles = standardPcmAudioProfiles;
+    c.ports.push_back(speakerOutDevice);
+
     AudioPort btOutDevice =
             createPort(c.nextPortId++, "BT A2DP Out", 0, false,
                        createPortDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
@@ -209,6 +217,13 @@
         getAudioPatches(&result);
         return result;
     }
+    std::optional<AudioPortConfig> getPortConfig(int32_t id) {
+        auto iter = findById<AudioPortConfig>(mConfig.portConfigs, id);
+        if (iter != mConfig.portConfigs.end()) {
+            return *iter;
+        }
+        return std::nullopt;
+    }
 
   private:
     ndk::ScopedAStatus setModuleDebug(
@@ -646,6 +661,19 @@
 }
 }  // namespace aidl::android::hardware::audio::core
 
+namespace aidl::android::media::audio::common {
+template <typename P>
+std::enable_if_t<std::is_function_v<typename mf_traits<decltype(&P::toString)>::member_type>,
+                 std::ostream&>
+operator<<(std::ostream& os, const P& p) {
+    return os << p.toString();
+}
+template <typename E>
+std::enable_if_t<std::is_enum_v<E>, std::ostream&> operator<<(std::ostream& os, const E& e) {
+    return os << toString(e);
+}
+}  // namespace aidl::android::media::audio::common
+
 using namespace android;
 
 namespace {
@@ -1214,3 +1242,55 @@
     EXPECT_EQ(std::vector<int32_t>{backMicPortConfig.id}, patchIt->sourcePortConfigIds);
     EXPECT_EQ(std::vector<int32_t>{mixPortConfig.id}, patchIt->sinkPortConfigIds);
 }
+
+TEST_F(Hal2AidlMapperTest, SetAudioPortConfigGainChangeExistingPortConfig) {
+    // First set config, then update gain.
+    AudioPortConfig speakerPortConfig;
+    speakerPortConfig.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
+    speakerPortConfig.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+            AudioChannelLayout::LAYOUT_STEREO);
+    speakerPortConfig.format =
+            AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
+    speakerPortConfig.sampleRate = ::aidl::android::media::audio::common::Int(48000);
+    AudioPortConfig resultingPortConfig;
+    ASSERT_EQ(OK,
+              mMapper->setPortConfig(speakerPortConfig, std::set<int32_t>(), &resultingPortConfig));
+    EXPECT_NE(0, resultingPortConfig.id);
+    EXPECT_NE(0, resultingPortConfig.portId);
+
+    AudioPortConfig gainUpdate;
+    gainUpdate.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
+    AudioGainConfig gainConfig{.index = -1,
+                               .mode = 1 << static_cast<int>(AudioGainMode::JOINT),
+                               .channelMask = AudioChannelLayout{},
+                               .values = std::vector<int32_t>{-3200},
+                               .rampDurationMs = 0};
+    gainUpdate.gain = gainConfig;
+    AudioPortConfig resultingGainUpdate;
+    ASSERT_EQ(OK, mMapper->setPortConfig(gainUpdate, std::set<int32_t>(), &resultingGainUpdate));
+    EXPECT_EQ(resultingPortConfig.id, resultingGainUpdate.id);
+    auto updatedPortConfig = mModule->getPortConfig(resultingGainUpdate.id);
+    ASSERT_TRUE(updatedPortConfig.has_value());
+    ASSERT_TRUE(updatedPortConfig->gain.has_value());
+    EXPECT_EQ(gainConfig, updatedPortConfig->gain);
+}
+
+TEST_F(Hal2AidlMapperTest, SetAudioPortConfigGainChangeFromScratch) {
+    // Set gain as the first operation, the HAL should suggest the rest of the configuration.
+    AudioPortConfig gainSet;
+    gainSet.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
+    AudioGainConfig gainConfig{.index = -1,
+                               .mode = 1 << static_cast<int>(AudioGainMode::JOINT),
+                               .channelMask = AudioChannelLayout{},
+                               .values = std::vector<int32_t>{-3200},
+                               .rampDurationMs = 0};
+    gainSet.gain = gainConfig;
+    AudioPortConfig resultingPortConfig;
+    ASSERT_EQ(OK, mMapper->setPortConfig(gainSet, std::set<int32_t>(), &resultingPortConfig));
+    EXPECT_NE(0, resultingPortConfig.id);
+    EXPECT_NE(0, resultingPortConfig.portId);
+    auto portConfig = mModule->getPortConfig(resultingPortConfig.id);
+    ASSERT_TRUE(portConfig.has_value());
+    ASSERT_TRUE(portConfig->gain.has_value());
+    EXPECT_EQ(gainConfig, portConfig->gain);
+}
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index fff2feb..d5e3cf7 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -185,7 +185,6 @@
     }
     RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
                     RetCode::ERROR_EFFECT_LIB_ERROR, "failSetControlParams");
-    mEnabled = false;
     return limitLevel();
 }
 
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index daabdb7..e5373f3 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -65,9 +65,9 @@
          {5, 3, -1, 3, 5}}}; /* Rock Preset */
 
 static const std::vector<Equalizer::Preset> kEqPresets = {
-        {0, "Normal"},      {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
-        {5, "Heavy Metal"}, {6, "Hip Hop"},   {7, "Jazz"},  {8, "Pop"},  {9, "Rock"}};
-
+        {-1, "Custom"}, {0, "Normal"}, {1, "Classical"},   {2, "Dance"},
+        {3, "Flat"},    {4, "Folk"},   {5, "Heavy Metal"}, {6, "Hip Hop"},
+        {7, "Jazz"},    {8, "Pop"},    {9, "Rock"}};
 
 const std::vector<Range::EqualizerRange> kEqRanges = {
         MAKE_RANGE(Equalizer, preset, 0, MAX_NUM_PRESETS - 1),
diff --git a/media/liberror/include/error/BinderResult.h b/media/liberror/include/error/BinderResult.h
new file mode 100644
index 0000000..1f1211c
--- /dev/null
+++ b/media/liberror/include/error/BinderResult.h
@@ -0,0 +1,48 @@
+/*
+ * 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 <binder/Status.h>
+#include <error/expected_utils.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace error {
+
+/**
+ * A convenience short-hand for base::expected, where the error type is a binder::Status, for use
+ * when implementing binder services.
+ * Clients need to link against libbinder, since this library is header only.
+ */
+template <typename T>
+using BinderResult = base::expected<T, binder::Status>;
+
+inline base::unexpected<binder::Status> unexpectedExceptionCode(int32_t exceptionCode,
+                                                                const char* s) {
+    return base::unexpected{binder::Status::fromExceptionCode(exceptionCode, s)};
+}
+
+inline base::unexpected<binder::Status> unexpectedServiceException(int32_t serviceSpecificCode,
+                                                                   const char* s) {
+    return base::unexpected{binder::Status::fromServiceSpecificError(serviceSpecificCode, s)};
+}
+
+}  // namespace error
+}  // namespace android
+
+inline std::string errorToString(const ::android::binder::Status& status) {
+    return std::string{status.toString8().c_str()};
+}
diff --git a/media/liberror/include/error/BinderStatusMatcher.h b/media/liberror/include/error/BinderStatusMatcher.h
new file mode 100644
index 0000000..11d9e65
--- /dev/null
+++ b/media/liberror/include/error/BinderStatusMatcher.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+
+#include <binder/Status.h>
+
+namespace android::error {
+
+class BinderStatusMatcher {
+  public:
+    using is_gtest_matcher = void;
+
+    explicit BinderStatusMatcher(binder::Status status) : status_(std::move(status)) {}
+
+    static BinderStatusMatcher hasException(binder::Status::Exception ex) {
+        return BinderStatusMatcher(binder::Status::fromExceptionCode(ex));
+    }
+
+    static BinderStatusMatcher isOk() { return BinderStatusMatcher(binder::Status::ok()); }
+
+    bool MatchAndExplain(const binder::Status& value,
+                         ::testing::MatchResultListener* listener) const {
+        if (status_.exceptionCode() == value.exceptionCode() &&
+            status_.transactionError() == value.transactionError() &&
+            status_.serviceSpecificErrorCode() == value.serviceSpecificErrorCode()) {
+            return true;
+        }
+        *listener << "received binder status: " << value;
+        return false;
+    }
+
+    void DescribeTo(std::ostream* os) const { *os << "contains binder status " << status_; }
+
+    void DescribeNegationTo(std::ostream* os) const {
+        *os << "does not contain binder status " << status_;
+    }
+
+  private:
+    const binder::Status status_;
+};
+}  // namespace android::error
diff --git a/media/liberror/include/error/ExpectedMatchers.h b/media/liberror/include/error/ExpectedMatchers.h
new file mode 100644
index 0000000..b81adbf
--- /dev/null
+++ b/media/liberror/include/error/ExpectedMatchers.h
@@ -0,0 +1,136 @@
+/*
+ * 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+#include <type_traits>
+
+namespace android::error {
+
+/**
+ * Example Usage:
+ * Given a function with signature
+ *       Result<T, U> foo()
+ * Matchers can be used as follows:
+ *       EXPECT_THAT(foo(), IsOkAnd(Eq(T{})));
+ *       EXPECT_THAT(foo(), IsErrorAnd(Eq(U{})));
+ */
+template <typename ExpectedT>
+class IsOkAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+  public:
+    using ValueT = std::remove_reference_t<ExpectedT>::value_type;
+
+    template <typename InnerMatcher>
+    explicit IsOkAndImpl(InnerMatcher innerMatcher)
+        : inner_matcher_(::testing::SafeMatcherCast<const ValueT&>(
+                  std::forward<InnerMatcher>(innerMatcher))) {}
+
+    bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+        if (!val.has_value()) {
+            *listener << "which has error " << ::testing::PrintToString(val.error());
+            return false;
+        }
+        const auto res = inner_matcher_.MatchAndExplain(val.value(), listener);
+        if (!res) {
+            *listener << "which has value " << ::testing::PrintToString(val.value());
+        }
+        return res;
+    }
+
+    void DescribeTo(std::ostream* os) const {
+        *os << "contains expected value which ";
+        inner_matcher_.DescribeTo(os);
+    }
+
+    void DescribeNegationTo(std::ostream* os) const {
+        *os << "does not contain expected, or contains expected value which ";
+        inner_matcher_.DescribeNegationTo(os);
+    }
+
+  private:
+    ::testing::Matcher<const ValueT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsOkAnd {
+  public:
+    explicit IsOkAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+    template <typename T>
+    operator ::testing::Matcher<T>() const {
+        return ::testing::Matcher<T>{new IsOkAndImpl<const T&>(inner_matcher_)};
+    }
+
+  private:
+    InnerMatcher inner_matcher_;
+};
+
+template <typename ExpectedT>
+class IsErrorAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+  public:
+    using ErrorT = typename std::remove_reference_t<ExpectedT>::error_type;
+
+    template <typename InnerMatcher>
+    explicit IsErrorAndImpl(InnerMatcher innerMatcher)
+        : inner_matcher_(::testing::SafeMatcherCast<const ErrorT&>(
+                  std::forward<InnerMatcher>(innerMatcher))) {}
+
+    bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+        if (val.has_value()) {
+            *listener << "which has value " << ::testing::PrintToString(val.value());
+            return false;
+        }
+
+        const auto res = inner_matcher_.MatchAndExplain(val.error(), listener);
+        if (!res) {
+            *listener << "which has error " << ::testing::PrintToString(val.error());
+        }
+        return res;
+    }
+
+    void DescribeTo(std::ostream* os) const {
+        *os << "contains error value which ";
+        inner_matcher_.DescribeTo(os);
+    }
+
+    void DescribeNegationTo(std::ostream* os) const {
+        *os << "does not contain error value, or contains error value which ";
+        inner_matcher_.DescribeNegationTo(os);
+    }
+
+  private:
+    ::testing::Matcher<const ErrorT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsErrorAnd {
+  public:
+    explicit IsErrorAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+    template <typename T>
+    operator ::testing::Matcher<T>() const {
+        return ::testing::Matcher<T>{new IsErrorAndImpl<const T&>(inner_matcher_)};
+    }
+
+  private:
+    InnerMatcher inner_matcher_;
+};
+
+}  // namespace android::error
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 9cd0e6e..e5323a6 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -364,7 +364,6 @@
         "av-types-aidl-cpp",
         "liblog",
         "libcutils",
-        "libprocessgroup",
         "libutils",
         "libbinder",
         "libbinder_ndk",
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index cdb1837..ef6250f 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -23,7 +23,6 @@
 #include <binder/Parcel.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaMetadataRetriever.h>
-#include <processgroup/sched_policy.h>
 #include <utils/String8.h>
 #include <utils/KeyedVector.h>
 
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 26aa375..f367a3e 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -213,6 +213,7 @@
                                                              // format to transport packets.
                                                              // Raw byte streams are used if this
                                                              // is false.
+#define AMEDIAMETRICS_PROP_TOSTRING "toString"             // string
 #define AMEDIAMETRICS_PROP_TOTALINPUTBYTES "totalInputBytes" // int32 (MIDI)
 #define AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES "totalOutputBytes" // int32 (MIDI)
 #define AMEDIAMETRICS_PROP_THREADID       "threadId"       // int32 value io handle
@@ -243,6 +244,7 @@
 // Values are strings accepted for a given property.
 
 // An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER "applyVolumeShaper"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE      "close"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE     "create"
@@ -265,6 +267,7 @@
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETLOGSESSIONID  "setLogSessionId" // AudioTrack, Record
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM "setPlaybackParam" // AudioTrack
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYERIID "setPlayerIId" // AudioTrack
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETSAMPLERATE "setSampleRate" // AudioTrack
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETSTARTTHRESHOLD "setStartThreshold" // AudioTrack
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME   "setVoiceVolume" // AudioFlinger
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME  "setVolume"  // AudioTrack
diff --git a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
index 652b1ee..15265bf 100644
--- a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
@@ -51,6 +51,69 @@
 
 enum DataSourceType { HTTP, FD, STREAM, FILETYPE, SOCKET, kMaxValue = SOCKET };
 
+constexpr audio_flags_mask_t kAudioFlagsMasks[] = {AUDIO_FLAG_NONE,
+                                                   AUDIO_FLAG_AUDIBILITY_ENFORCED,
+                                                   AUDIO_FLAG_SECURE,
+                                                   AUDIO_FLAG_SCO,
+                                                   AUDIO_FLAG_BEACON,
+                                                   AUDIO_FLAG_HW_AV_SYNC,
+                                                   AUDIO_FLAG_HW_HOTWORD,
+                                                   AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY,
+                                                   AUDIO_FLAG_BYPASS_MUTE,
+                                                   AUDIO_FLAG_LOW_LATENCY,
+                                                   AUDIO_FLAG_DEEP_BUFFER,
+                                                   AUDIO_FLAG_NO_MEDIA_PROJECTION,
+                                                   AUDIO_FLAG_MUTE_HAPTIC,
+                                                   AUDIO_FLAG_NO_SYSTEM_CAPTURE,
+                                                   AUDIO_FLAG_CAPTURE_PRIVATE,
+                                                   AUDIO_FLAG_CONTENT_SPATIALIZED,
+                                                   AUDIO_FLAG_NEVER_SPATIALIZE,
+                                                   AUDIO_FLAG_CALL_REDIRECTION};
+
+constexpr audio_content_type_t kAudioContentTypes[] = {
+        AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_CONTENT_TYPE_SPEECH,       AUDIO_CONTENT_TYPE_MUSIC,
+        AUDIO_CONTENT_TYPE_MOVIE,   AUDIO_CONTENT_TYPE_SONIFICATION, AUDIO_CONTENT_TYPE_ULTRASOUND};
+
+constexpr audio_source_t kAudioSources[] = {AUDIO_SOURCE_INVALID,
+                                            AUDIO_SOURCE_DEFAULT,
+                                            AUDIO_SOURCE_MIC,
+                                            AUDIO_SOURCE_VOICE_UPLINK,
+                                            AUDIO_SOURCE_VOICE_DOWNLINK,
+                                            AUDIO_SOURCE_VOICE_CALL,
+                                            AUDIO_SOURCE_CAMCORDER,
+                                            AUDIO_SOURCE_VOICE_RECOGNITION,
+                                            AUDIO_SOURCE_VOICE_COMMUNICATION,
+                                            AUDIO_SOURCE_REMOTE_SUBMIX,
+                                            AUDIO_SOURCE_UNPROCESSED,
+                                            AUDIO_SOURCE_VOICE_PERFORMANCE,
+                                            AUDIO_SOURCE_ECHO_REFERENCE,
+                                            AUDIO_SOURCE_FM_TUNER,
+                                            AUDIO_SOURCE_HOTWORD,
+                                            AUDIO_SOURCE_ULTRASOUND};
+
+constexpr audio_usage_t kAudioUsages[] = {AUDIO_USAGE_UNKNOWN,
+                                          AUDIO_USAGE_MEDIA,
+                                          AUDIO_USAGE_VOICE_COMMUNICATION,
+                                          AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                                          AUDIO_USAGE_ALARM,
+                                          AUDIO_USAGE_NOTIFICATION,
+                                          AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+                                          AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                                          AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                                          AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                                          AUDIO_USAGE_NOTIFICATION_EVENT,
+                                          AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+                                          AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                                          AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+                                          AUDIO_USAGE_GAME,
+                                          AUDIO_USAGE_VIRTUAL_SOURCE,
+                                          AUDIO_USAGE_ASSISTANT,
+                                          AUDIO_USAGE_CALL_ASSISTANT,
+                                          AUDIO_USAGE_EMERGENCY,
+                                          AUDIO_USAGE_SAFETY,
+                                          AUDIO_USAGE_VEHICLE_STATUS,
+                                          AUDIO_USAGE_ANNOUNCEMENT};
+
 constexpr PixelFormat kPixelFormat[] = {
         PIXEL_FORMAT_UNKNOWN,       PIXEL_FORMAT_NONE,        PIXEL_FORMAT_CUSTOM,
         PIXEL_FORMAT_TRANSLUCENT,   PIXEL_FORMAT_TRANSPARENT, PIXEL_FORMAT_OPAQUE,
@@ -354,7 +417,18 @@
                 [&]() { mMediaPlayer->attachAuxEffect(mFdp.ConsumeIntegral<int32_t>()); },
                 [&]() {
                     int32_t key = mFdp.PickValueInArray(kMediaParamKeys);
-                    request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
+                    request.writeInt32((audio_usage_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_USAGE_UNKNOWN, AUDIO_USAGE_ANNOUNCEMENT) /* usage */);
+                    request.writeInt32((audio_content_type_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_CONTENT_TYPE_UNKNOWN,
+                            AUDIO_CONTENT_TYPE_ULTRASOUND) /* content_type */);
+                    request.writeInt32((audio_source_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_SOURCE_INVALID, AUDIO_SOURCE_ULTRASOUND) /* source */);
+                    request.writeInt32((audio_flags_mask_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_FLAG_NONE, AUDIO_FLAG_CALL_REDIRECTION) /* flags */);
+                    request.writeInt32(mFdp.ConsumeBool() /* hasFlattenedTag */);
+                    request.writeString16(
+                            String16((mFdp.ConsumeRandomLengthString()).c_str()) /* tags */);
                     request.setDataPosition(0);
                     mMediaPlayer->setParameter(key, request);
                     key = mFdp.PickValueInArray(kMediaParamKeys);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 72785d5..4e4aa75 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -882,7 +882,6 @@
 inline constexpr int32_t CRYPTO_MODE_AES_CBC     = 2;
 inline constexpr int32_t CRYPTO_MODE_AES_CTR     = 1;
 inline constexpr int32_t CRYPTO_MODE_UNENCRYPTED = 0;
-inline constexpr int32_t INFO_OUTPUT_BUFFERS_CHANGED = -3;
 inline constexpr int32_t INFO_OUTPUT_FORMAT_CHANGED  = -2;
 inline constexpr int32_t INFO_TRY_AGAIN_LATER        = -1;
 inline constexpr int32_t VIDEO_SCALING_MODE_SCALE_TO_FIT               = 1;
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
index 9f46a74..b29429a 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
@@ -21,105 +21,256 @@
 #include <media/stagefright/MPEG2TSWriter.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/OggWriter.h>
-
-#include "MediaMimeTypes.h"
-
 #include <webm/WebmWriter.h>
 
 namespace android {
-std::string genMimeType(FuzzedDataProvider *dataProvider) {
-    uint8_t idx = dataProvider->ConsumeIntegralInRange<uint8_t>(0, kMimeTypes.size() - 1);
-    return std::string(kMimeTypes[idx]);
-}
 
-sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, std::string mimeType,
-                                      uint16_t maxDataAmount) {
-    uint32_t dataBlobSize = dataProvider->ConsumeIntegralInRange<uint16_t>(0, maxDataAmount);
-    std::vector<uint8_t> data = dataProvider->ConsumeBytes<uint8_t>(dataBlobSize);
-    // data:[<mediatype>][;base64],<data>
-    std::string uri("data:");
-    uri += mimeType;
-    // Currently libstagefright only accepts base64 uris
-    uri += ";base64,";
-    android::AString out;
-    android::encodeBase64(data.data(), data.size(), &out);
-    uri += out.c_str();
-
-    sp<DataSource> source =
-        DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri.c_str());
-
-    if (source == NULL) {
-        return NULL;
-    }
-
-    return MediaExtractorFactory::Create(source);
-}
-
-sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize) {
-    std::string mime = genMimeType(dataProvider);
-    sp<IMediaExtractor> extractor = genMediaExtractor(dataProvider, mime, maxMediaBlobSize);
-
-    if (extractor == NULL) {
-        return NULL;
-    }
-
-    for (size_t i = 0; i < extractor->countTracks(); ++i) {
-        sp<MetaData> meta = extractor->getTrackMetaData(i);
-
-        std::string trackMime = dataProvider->PickValueInArray(kTestedMimeTypes);
-        if (!strcasecmp(mime.c_str(), trackMime.c_str())) {
-            sp<IMediaSource> track = extractor->getTrack(i);
-            if (track == NULL) {
-                return NULL;
-            }
-            return new CallbackMediaSource(track);
-        }
-    }
-
-    return NULL;
-}
-
-sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> fileMeta) {
+sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> writerMeta,
+                             FuzzedDataProvider* fdp) {
     sp<MediaWriter> writer;
+
+    if (fdp->ConsumeBool()) {
+        writerMeta->setInt32(kKeyRealTimeRecording, fdp->ConsumeBool());
+    }
+
     switch (writerType) {
-        case OGG:
-            writer = new OggWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
-            break;
         case AAC:
-            writer = new AACWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+            writer = sp<AACWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+            }
             break;
         case AAC_ADTS:
-            writer = new AACWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
-            break;
-        case WEBM:
-            writer = new WebmWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
-            break;
-        case MPEG4:
-            writer = new MPEG4Writer(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+            writer = sp<AACWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+            }
             break;
         case AMR_NB:
-            writer = new AMRWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+            writer = sp<AMRWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+            }
             break;
         case AMR_WB:
-            writer = new AMRWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+            writer = sp<AMRWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+            }
             break;
         case MPEG2TS:
-            writer = new MPEG2TSWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+            writer = sp<MPEG2TSWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+            }
             break;
-        default:
-            return nullptr;
+        case MPEG4:
+            writer = sp<MPEG4Writer>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+            } else if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_HEIF);
+            } else if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_THREE_GPP);
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKey2ByteNalLength, fdp->ConsumeBool());
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyTimeScale,
+                                     fdp->ConsumeIntegralInRange<int32_t>(600, 96000));
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKey4BitTrackIds, fdp->ConsumeBool());
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt64(kKeyTrackTimeStatus, fdp->ConsumeIntegral<int64_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyRotation, fdp->ConsumeIntegralInRange<uint8_t>(0, 3) * 90);
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt64(kKeyTime, fdp->ConsumeIntegral<int64_t>());
+            }
+            break;
+        case OGG:
+            writer = sp<OggWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+            }
+            break;
+        case WEBM:
+            writer = sp<WebmWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyTimeScale,
+                                     fdp->ConsumeIntegralInRange<int32_t>(600, 96000));
+            }
+            break;
     }
-    if (writer != nullptr) {
-        fileMeta->setInt32(kKeyRealTimeRecording, false);
-    }
+
     return writer;
 }
+
+sp<FuzzSource> createSource(StandardWriters writerType, FuzzedDataProvider* fdp) {
+    sp<MetaData> meta = sp<MetaData>::make();
+
+    switch (writerType) {
+        case AAC:
+        case AAC_ADTS:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+            meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegralInRange<uint8_t>(1, 7));
+            meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyAACProfile, fdp->ConsumeIntegral<int32_t>());
+            }
+            break;
+        case AMR_NB:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
+            meta->setInt32(kKeyChannelCount, 1);
+            meta->setInt32(kKeySampleRate, 8000);
+            break;
+        case AMR_WB:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
+            meta->setInt32(kKeyChannelCount, 1);
+            meta->setInt32(kKeySampleRate, 16000);
+            break;
+        case MPEG2TS:
+            if (fdp->ConsumeBool()) {
+                meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+                meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+            } else {
+                meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+                // The +1s ensure a minimum height and width of 1.
+                meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+                meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+            }
+            break;
+        case MPEG4: {
+            auto mime = fdp->PickValueInArray<std::string>(kMpeg4MimeTypes);
+            meta->setCString(kKeyMIMEType, mime.c_str());
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyBackgroundMode, fdp->ConsumeBool());
+            }
+
+            if (!strncasecmp(mime.c_str(), "audio/", 6)) {
+                meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+
+            } else {
+                // The +1s ensure a minimum height and width of 1.
+                meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+                meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyDisplayWidth, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyDisplayHeight, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyTileWidth, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyTileHeight, fdp->ConsumeIntegral<uint16_t>());
+                }
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<uint8_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<uint8_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyTemporalLayerCount, fdp->ConsumeIntegral<int32_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<uint16_t>());
+                }
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyBitRate, fdp->ConsumeIntegral<int32_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyMaxBitRate, fdp->ConsumeIntegral<int32_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyTrackIsDefault, fdp->ConsumeBool());
+            }
+            break;
+        }
+        case OGG:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+            }
+            break;
+        case WEBM:
+            if (fdp->ConsumeBool()) {
+                if (fdp->ConsumeBool()) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8);
+                } else {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP9);
+                }
+
+                if (fdp->ConsumeBool()) {
+                    // The +1s ensure a minimum height and width of 1.
+                    meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+                    meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+                }
+            } else {
+                if (fdp->ConsumeBool()) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
+                } else {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+                }
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+            }
+
+            break;
+    }
+
+    return sp<FuzzSource>::make(meta, fdp);
+}
 }  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
index 6856ac0..ad1218b 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
@@ -15,20 +15,52 @@
  */
 
 #pragma once
-#include <datasource/DataSourceFactory.h>
+
 #include <fuzzer/FuzzedDataProvider.h>
-#include <android/IMediaExtractor.h>
-#include <media/IMediaHTTPService.h>
-#include <media/mediarecorder.h>
-#include <media/stagefright/CallbackMediaSource.h>
+
+#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MediaWriter.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/foundation/base64.h>
-#include <utils/StrongPointer.h>
 
 namespace android {
+class FuzzSource : public MediaSource {
+  public:
+    FuzzSource(sp<MetaData> meta, FuzzedDataProvider* fdp) : mMetaData(meta), mFdp(fdp) {}
+
+    status_t start(MetaData*) { return OK; }
+
+    virtual status_t stop() { return OK; }
+
+    status_t read(MediaBufferBase** buffer, const ReadOptions*) {
+        // Ensuring that mBuffer has at least two bytes to avoid check failure
+        // in MPEG2TSWriter::SourceInfo::onMessageReceived().
+        if (mFdp->remaining_bytes() > 2) {
+            auto size = mFdp->ConsumeIntegralInRange<uint8_t>(2, INT8_MAX);
+            mBuffer = mFdp->ConsumeBytes<uint8_t>(size);
+            MediaBufferBase* mbb = new MediaBuffer(mBuffer.data(), mBuffer.size());
+
+            size_t length = mFdp->ConsumeIntegralInRange<size_t>(2, mbb->size());
+            size_t offset = mFdp->ConsumeIntegralInRange<size_t>(0, mbb->size() - length);
+            mbb->set_range(offset, length);
+
+            mbb->meta_data().setInt32(kKeyIsEndOfStream, mFdp->ConsumeBool());
+            mbb->meta_data().setInt64(kKeyTime, mFdp->ConsumeIntegral<uint32_t>() / 2);
+            *buffer = mbb;
+
+            return OK;
+        }
+
+        return ERROR_END_OF_STREAM;
+    }
+
+    sp<MetaData> getFormat() { return mMetaData; }
+
+  private:
+    sp<MetaData> mMetaData = nullptr;
+    FuzzedDataProvider* mFdp = nullptr;
+    std::vector<uint8_t> mBuffer;
+};
+
 enum StandardWriters {
     OGG,
     AAC,
@@ -42,54 +74,22 @@
     kMaxValue = MPEG2TS,
 };
 
-static std::string kTestedMimeTypes[] = {"audio/3gpp",
-                                         "audio/amr-wb",
-                                         "audio/vorbis",
-                                         "audio/opus",
-                                         "audio/mp4a-latm",
-                                         "audio/mpeg",
-                                         "audio/mpeg-L1",
-                                         "audio/mpeg-L2",
-                                         "audio/midi",
-                                         "audio/qcelp",
-                                         "audio/g711-alaw",
-                                         "audio/g711-mlaw",
-                                         "audio/flac",
-                                         "audio/aac-adts",
-                                         "audio/gsm",
-                                         "audio/ac3",
-                                         "audio/eac3",
-                                         "audio/eac3-joc",
-                                         "audio/ac4",
-                                         "audio/scrambled",
-                                         "audio/alac",
-                                         "audio/x-ms-wma",
-                                         "audio/x-adpcm-ms",
-                                         "audio/x-adpcm-dvi-ima",
-                                         "video/avc",
-                                         "video/hevc",
-                                         "video/mp4v-es",
-                                         "video/3gpp",
-                                         "video/x-vnd.on2.vp8",
-                                         "video/x-vnd.on2.vp9",
-                                         "video/av01",
-                                         "video/mpeg2",
-                                         "video/dolby-vision",
-                                         "video/scrambled",
-                                         "video/divx",
-                                         "video/divx3",
-                                         "video/xvid",
-                                         "video/x-motion-jpeg",
-                                         "text/3gpp-tt",
-                                         "application/x-subrip",
-                                         "text/vtt",
-                                         "text/cea-608",
-                                         "text/cea-708",
-                                         "application/x-id3v4"};
+static const uint32_t kSampleRateTable[] = {
+        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000,
+};
+static const std::string kMpeg4MimeTypes[] = {
+        MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, MEDIA_MIMETYPE_IMAGE_AVIF,
 
-std::string genMimeType(FuzzedDataProvider *dataProvider);
-sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, uint16_t dataAmount);
-sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize);
+        MEDIA_MIMETYPE_VIDEO_AV1,          MEDIA_MIMETYPE_VIDEO_AVC,
+        MEDIA_MIMETYPE_VIDEO_HEVC,         MEDIA_MIMETYPE_VIDEO_MPEG4,
+        MEDIA_MIMETYPE_VIDEO_H263,         MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
 
-sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> fileMeta);
+        MEDIA_MIMETYPE_AUDIO_AMR_NB,       MEDIA_MIMETYPE_AUDIO_AMR_WB,
+        MEDIA_MIMETYPE_AUDIO_AAC,
+};
+
+sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> writerMeta,
+                             FuzzedDataProvider* fdp);
+
+sp<FuzzSource> createSource(StandardWriters writerType, FuzzedDataProvider* fdp);
 }  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
index 97d1160..cd0a866 100644
--- a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
@@ -13,216 +13,49 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// Authors: corbin.souffrant@leviathansecurity.com
-//          dylan.katz@leviathansecurity.com
-
-#include <android-base/file.h>
-#include <android/content/AttributionSourceState.h>
-#include <ctype.h>
-#include <media/mediarecorder.h>
-#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <stdlib.h>
-#include <utils/StrongPointer.h>
-#include <utils/Vector.h>
-
-#include <functional>
-#include <string>
 
 #include "FuzzerMediaUtility.h"
-#include "fuzzer/FuzzedDataProvider.h"
-
-static constexpr uint16_t kMaxOperations = 5000;
-static constexpr uint8_t kMaxPackageNameLen = 50;
-// For other strings in mpeg we want a higher limit.
-static constexpr uint16_t kMaxMPEGStrLen = 1000;
-static constexpr uint16_t kMaxMediaBlobSize = 1000;
 
 namespace android {
 
-using android::content::AttributionSourceState;
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
 
-std::string getFourCC(FuzzedDataProvider *fdp) {
-    std::string fourCC = fdp->ConsumeRandomLengthString(4);
-    // Replace any existing nulls
-    for (size_t pos = 0; pos < fourCC.length(); pos++) {
-        if (fourCC.at(pos) == '\0') {
-            fourCC.replace(pos, 1, "a");
-        }
+    // memfd_create() creates an anonymous file and returns a file
+    // descriptor that refers to it. MFD_ALLOW_SEALING allows sealing
+    // operations on this file.
+    int32_t fd = memfd_create("WriterFuzzer", MFD_ALLOW_SEALING);
+    if (fd == -1) {
+        ALOGE("memfd_create() failed: %s", strerror(errno));
+        return 0;
     }
 
-    // If our string is too short, fill the remainder with "a"s.
-    while (fourCC.length() < 4) {
-        fourCC += 'a';
-    }
-    return fourCC;
-}
+    StandardWriters writerType = fdp.ConsumeEnum<StandardWriters>();
+    sp<MetaData> writerMeta = sp<MetaData>::make();
 
-typedef std::vector<std::function<void(FuzzedDataProvider*,
-                                    sp<MediaWriter>, sp<MetaData>, int tmpFileFd)>> OperationVec;
-typedef std::vector<std::function<void(FuzzedDataProvider*, MPEG4Writer*)>> MPEG4OperationVec;
-static const OperationVec operations = {
-    [](FuzzedDataProvider*, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->pause();
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
-        bool valid_fd = dataProvider->ConsumeBool();
-        int fd = -1;
-        if (valid_fd) {
-            fd = tmpFd;
-        }
-        // Args don't seem to be used
-        Vector<String16> args;
-        mediaWriter->dump(fd, args);
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
-        bool valid_fd = dataProvider->ConsumeBool();
-        int fd = -1;
-        if (valid_fd) {
-            fd = tmpFd;
-        }
-        mediaWriter->setNextFd(fd);
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setCaptureRate(dataProvider->ConsumeFloatingPoint<float>());
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setStartTimeOffsetMs(dataProvider->ConsumeIntegral<int>());
-
-        // Likely won't do much, but might as well as do a quick check
-        // while we're here.
-        mediaWriter->getStartTimeOffsetMs();
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
-    },
-};
-
-static const MPEG4OperationVec mpeg4Operations = {
-    [](FuzzedDataProvider*, MPEG4Writer *mediaWriter) { mediaWriter->notifyApproachingLimit(); },
-    // Lower level write methods.
-    // High-level startBox/endBox/etc are all called elsewhere,
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint8_t val = dataProvider->ConsumeIntegral<uint8_t>();
-        mediaWriter->writeInt8(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint16_t val = dataProvider->ConsumeIntegral<uint16_t>();
-        mediaWriter->writeInt16(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint32_t val = dataProvider->ConsumeIntegral<uint32_t>();
-        mediaWriter->writeInt32(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint64_t val = dataProvider->ConsumeIntegral<uint64_t>();
-        mediaWriter->writeInt64(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        std::string strVal = dataProvider->ConsumeRandomLengthString(kMaxMPEGStrLen);
-        mediaWriter->writeCString(strVal.c_str());
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        std::string fourCC = getFourCC(dataProvider);
-        mediaWriter->writeFourcc(fourCC.c_str());
-    },
-
-    // Misc setters
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint32_t layers = dataProvider->ConsumeIntegral<uint32_t>();
-        mediaWriter->setTemporalLayerCount(layers);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint32_t duration = dataProvider->ConsumeIntegral<uint32_t>();
-        mediaWriter->setInterleaveDuration(duration);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        int lat = dataProvider->ConsumeIntegral<int>();
-        int lon = dataProvider->ConsumeIntegral<int>();
-        mediaWriter->setGeoData(lat, lon);
-    },
-};
-
-// Not all writers can always add new sources, so we'll need additional checks.
-void addSource(FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter) {
-    sp<MediaSource> mediaSource = genMediaSource(dataProvider, kMaxMediaBlobSize);
-    if (mediaSource == NULL) {
-        // There's a static check preventing NULLs in addSource.
-        return;
-    }
-    mediaWriter->addSource(mediaSource);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
-    FuzzedDataProvider dataProvider(data, size);
-    TemporaryFile tf;
-    sp<MetaData> fileMeta = new MetaData;
-    StandardWriters writerType = dataProvider.ConsumeEnum<StandardWriters>();
-    sp<MediaWriter> writer = createWriter(tf.fd, writerType, fileMeta);
-
-    AttributionSourceState attributionSource;
-    attributionSource.packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
-    attributionSource.uid = dataProvider.ConsumeIntegral<int32_t>();
-    attributionSource.pid = dataProvider.ConsumeIntegral<int32_t>();
-    attributionSource.token = sp<BBinder>::make();
-    sp<MediaRecorder> mr = new MediaRecorder(attributionSource);
-    writer->setListener(mr);
-
-    uint8_t baseOpLen = operations.size();
-    uint8_t totalLen = baseOpLen;
-    uint8_t maxSources;
-    // Different writers support different amounts of sources.
-    switch (writerType) {
-        case StandardWriters::AAC:
-        case StandardWriters::AAC_ADTS:
-        case StandardWriters::AMR_NB:
-        case StandardWriters::AMR_WB:
-        case StandardWriters::OGG:
-            maxSources = 1;
-            break;
-        case StandardWriters::WEBM:
-            maxSources = 2;
-            break;
-        default:
-            maxSources = UINT8_MAX;
-            break;
-    }
-    // Initialize some number of sources and add them to our writer.
-    uint8_t sourceCount = dataProvider.ConsumeIntegralInRange<uint8_t>(0, maxSources);
-    for (uint8_t i = 0; i < sourceCount; i++) {
-        addSource(&dataProvider, writer);
+    sp<MediaWriter> writer = createWriter(fd, writerType, writerMeta, &fdp);
+    if (writer == nullptr) {
+        close(fd);
+        return 0;
     }
 
-    // Increase our range if additional operations are implemented.
-    // Currently only MPEG4 has additiona public operations on their writer.
-    if (writerType == StandardWriters::MPEG4) {
-        totalLen += mpeg4Operations.size();
+    if (writerType == StandardWriters::WEBM) {
+        // This range is set to avoid CHECK failure in WEBMWriter::reset() -> EbmlVoid::EBmlVoid().
+        writer->setMaxFileSize(fdp.ConsumeIntegralInRange<int64_t>(5 * 1024 * 1024, INT64_MAX));
+    } else {
+        writer->setMaxFileSize(fdp.ConsumeIntegral<int64_t>());
     }
+    writer->setMaxFileDuration(fdp.ConsumeIntegral<int64_t>());
+    writer->setCaptureRate(fdp.ConsumeFloatingPoint<float>());
 
-    // Many operations require the writer to be started.
-    writer->start(fileMeta.get());
-    for (size_t ops_run = 0; dataProvider.remaining_bytes() > 0 && ops_run < kMaxOperations - 1;
-            ops_run++) {
-        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, totalLen - 1);
-        if (op < baseOpLen) {
-            operations[op](&dataProvider, writer, fileMeta, tf.fd);
-        } else if (writerType == StandardWriters::MPEG4) {
-            mpeg4Operations[op - baseOpLen](&dataProvider, (MPEG4Writer*)writer.get());
-        } else {
-            // Here just in case, will error out.
-            operations[op](&dataProvider, writer, fileMeta, tf.fd);
-        }
-    }
+    sp<MediaSource> source = createSource(writerType, &fdp);
+    writer->addSource(source);
+    writer->start(writerMeta.get());
+    writer->pause();
     writer->stop();
 
-    writer.clear();
-    writer = nullptr;
+    close(fd);
+
     return 0;
 }
 }  // namespace android
diff --git a/media/module/bufferpool/2.0/AccessorImpl.cpp b/media/module/bufferpool/2.0/AccessorImpl.cpp
index 202d803..b9483bf 100644
--- a/media/module/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/module/bufferpool/2.0/AccessorImpl.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "BufferPoolAccessor2.0"
 //#define LOG_NDEBUG 0
 
+#include <android-base/no_destructor.h>
+
 #include <sys/types.h>
 #include <stdint.h>
 #include <time.h>
@@ -147,7 +149,25 @@
 #endif
 
 static constexpr uint32_t kSeqIdMax = 0x7fffffff;
-uint32_t Accessor::Impl::sSeqId = time(nullptr) & kSeqIdMax;
+
+Accessor::Impl::ConnectionIdGenerator::ConnectionIdGenerator() {
+    mSeqId = static_cast<uint32_t>(time(nullptr) & kSeqIdMax);
+    mPid = static_cast<int32_t>(getpid());
+}
+
+ConnectionId Accessor::Impl::ConnectionIdGenerator::getConnectionId() {
+    uint32_t seq;
+    {
+        std::lock_guard<std::mutex> l(mLock);
+        seq = mSeqId;
+        if (mSeqId == kSeqIdMax) {
+            mSeqId = 0;
+        } else {
+            ++mSeqId;
+        }
+    }
+    return (int64_t)mPid << 32 | seq | kSeqIdVndkBit;
+}
 
 Accessor::Impl::Impl(
         const std::shared_ptr<BufferPoolAllocator> &allocator)
@@ -163,13 +183,14 @@
         uint32_t *pMsgId,
         const StatusDescriptor** statusDescPtr,
         const InvalidationDescriptor** invDescPtr) {
+    static ::android::base::NoDestructor<ConnectionIdGenerator> sConIdGenerator;
     sp<Connection> newConnection = new Connection();
     ResultStatus status = ResultStatus::CRITICAL_ERROR;
     {
         std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
         if (newConnection) {
             int32_t pid = getpid();
-            ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
+            ConnectionId id = sConIdGenerator->getConnectionId();
             status = mBufferPool.mObserver.open(id, statusDescPtr);
             if (status == ResultStatus::OK) {
                 newConnection->initialize(accessor, id);
@@ -179,11 +200,6 @@
                 mBufferPool.mConnectionIds.insert(id);
                 mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
                 mBufferPool.mInvalidation.onConnect(id, observer);
-                if (sSeqId == kSeqIdMax) {
-                   sSeqId = 0;
-                } else {
-                    ++sSeqId;
-                }
             }
 
         }
diff --git a/media/module/bufferpool/2.0/AccessorImpl.h b/media/module/bufferpool/2.0/AccessorImpl.h
index 3d39941..2366177 100644
--- a/media/module/bufferpool/2.0/AccessorImpl.h
+++ b/media/module/bufferpool/2.0/AccessorImpl.h
@@ -77,7 +77,14 @@
 private:
     // ConnectionId = pid : (timestamp_created + seqId)
     // in order to guarantee uniqueness for each connection
-    static uint32_t sSeqId;
+    struct ConnectionIdGenerator {
+        int32_t mPid;
+        uint32_t mSeqId;
+        std::mutex mLock;
+
+        ConnectionIdGenerator();
+        ConnectionId getConnectionId();
+    };
 
     const std::shared_ptr<BufferPoolAllocator> mAllocator;
 
diff --git a/media/module/bufferpool/2.0/Android.bp b/media/module/bufferpool/2.0/Android.bp
index bdab103..c40603c 100644
--- a/media/module/bufferpool/2.0/Android.bp
+++ b/media/module/bufferpool/2.0/Android.bp
@@ -21,6 +21,9 @@
     export_include_dirs: [
         "include",
     ],
+    header_libs: [
+        "libbase_headers",
+    ],
     shared_libs: [
         "libcutils",
         "libfmq",
diff --git a/media/module/foundation/tests/AData_test.cpp b/media/module/foundation/tests/AData_test.cpp
index 2628a47..87b69a6 100644
--- a/media/module/foundation/tests/AData_test.cpp
+++ b/media/module/foundation/tests/AData_test.cpp
@@ -392,7 +392,7 @@
     EXPECT_EQ(2L, _shared.use_count()); // still both u and _shared contains the object
 
     EXPECT_TRUE(u.clear());
-    EXPECT_TRUE(_shared.unique()); // now only _shared contains the object
+    EXPECT_EQ(1L, _shared.use_count()); // now only _shared contains the object
 
     EXPECT_TRUE(u.set(_constShared));
     EXPECT_EQ(2L, _constShared.use_count()); // even though it is const, we can add a use count
@@ -591,7 +591,7 @@
     EXPECT_EQ(2L, _shared.use_count()); // still both u and _shared contains the object
 
     EXPECT_TRUE(u.clear());
-    EXPECT_TRUE(_shared.unique()); // now only _shared contains the object
+    EXPECT_EQ(1L, _shared.use_count()); // now only _shared contains the object
 
     EXPECT_TRUE(u.set(_constShared));
     EXPECT_EQ(2L, _constShared.use_count()); // even though it is const, we can add a use count
diff --git a/media/mtp/tests/MtpFuzzer/Android.bp b/media/mtp/tests/MtpFuzzer/Android.bp
index acae06a..2e9c58b 100644
--- a/media/mtp/tests/MtpFuzzer/Android.bp
+++ b/media/mtp/tests/MtpFuzzer/Android.bp
@@ -29,7 +29,6 @@
         "liblog",
         "libutils",
     ],
-    static_libs: ["libc++fs",],
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 4b0192a..7bec8cf 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -47,7 +47,6 @@
 static const String16 sModifyPhoneState("android.permission.MODIFY_PHONE_STATE");
 static const String16 sModifyAudioRouting("android.permission.MODIFY_AUDIO_ROUTING");
 static const String16 sCallAudioInterception("android.permission.CALL_AUDIO_INTERCEPTION");
-static const String16 sAndroidPermissionBluetoothConnect("android.permission.BLUETOOTH_CONNECT");
 
 static String16 resolveCallingPackage(PermissionController& permissionController,
         const std::optional<String16> opPackageName, uid_t uid) {
@@ -393,48 +392,6 @@
     return NO_ERROR;
 }
 
-/**
- * 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& caller) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
-    if (isAudioServerOrSystemServerUid(uid)) {
-        return false;
-    }
-    const std::optional<AttributionSourceState> resolvedAttributionSource =
-            resolveAttributionSource(attributionSource, DEVICE_ID_DEFAULT);
-    if (!resolvedAttributionSource.has_value()) {
-        return true;
-    }
-    permission::PermissionChecker permissionChecker;
-    return permissionChecker.checkPermissionForPreflightFromDatasource(
-            sAndroidPermissionBluetoothConnect, resolvedAttributionSource.value(), caller,
-            AppOpsManager::OP_BLUETOOTH_CONNECT)
-                != permission::PermissionChecker::PERMISSION_GRANTED;
-}
-
-/**
- * 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 anonymzation 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) {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 9c02cd4..e0fabfd 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -113,10 +113,6 @@
 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();
diff --git a/media/utils/tests/static_string_view_tests.cpp b/media/utils/tests/static_string_view_tests.cpp
index c00de68..1dd2370 100644
--- a/media/utils/tests/static_string_view_tests.cpp
+++ b/media/utils/tests/static_string_view_tests.cpp
@@ -37,14 +37,12 @@
     // const std::array<char,2> nonstatic = {'a', 'b'};
     // static_assert(can_assign<nonstatic>::value == false);
     static std::array<char, 2> nonconst = {'a', 'b'};
-    static const std::array<char, 2> nonconstexpr = {'a', 'b'};
     static constexpr std::array<int, 2> nonchar = {1, 2};
     static constexpr size_t nonarray = 2;
 
     static_assert(CanCreate<nonconst>::value == false);
     static_assert(CanCreate<nonarray>::value == false);
     static_assert(CanCreate<nonchar>::value == false);
-    static_assert(CanCreate<nonconstexpr>::value == false);
 
     static constexpr std::array<char, 2> scoped = {'a', 'b'};
     constexpr StaticStringView Ticket1 = StaticStringView::create<global>();
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 09edf68..60be37d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3948,7 +3948,8 @@
                                                        patchRecord->bufferSize(),
                                                        outputFlags,
                                                        0ns /* timeout */,
-                                                       frameCountToBeReady);
+                                                       frameCountToBeReady,
+                                                       track->getSpeed());
         status = patchTrack->initCheck();
         if (status != NO_ERROR) {
             ALOGE("Secondary output patchTrack init failed: %d", status);
@@ -4566,6 +4567,10 @@
             if ((pt->type() == IAfThreadBase::MIXER || pt->type() == IAfThreadBase::OFFLOAD) &&
                     ((sessionType & IAfThreadBase::EFFECT_SESSION) != 0)) {
                 srcThread = pt.get();
+                if (srcThread == dstThread) {
+                    ALOGD("%s() same dst and src threads, ignoring move", __func__);
+                    return NO_ERROR;
+                }
                 ALOGW("%s() found srcOutput %d hosting AUDIO_SESSION_OUTPUT_MIX", __func__,
                       pt->id());
                 break;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index ad043c8..8356339 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1358,15 +1358,16 @@
     }
 }
 
-status_t EffectModule::setVolume(uint32_t* left, uint32_t* right, bool controller, bool force) {
+status_t EffectModule::setVolume_l(uint32_t* left, uint32_t* right, bool controller, bool force) {
     AutoLockReentrant _l(mutex(), mSetVolumeReentrantTid);
     if (mStatus != NO_ERROR) {
         return mStatus;
     }
     status_t status = NO_ERROR;
     // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
-    // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
-    if ((isProcessEnabled() || force) &&
+    // if controller flag is set (Note that controller == TRUE => the volume controller effect in
+    // the effect chain)
+    if (((isOffloadedOrDirect_l() ? isEnabled() : isProcessEnabled()) || force) &&
             ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL ||
              (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND ||
              (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_MONITOR)) {
@@ -1377,7 +1378,8 @@
 
 status_t EffectModule::setVolumeInternal(
         uint32_t *left, uint32_t *right, bool controller) {
-    if (mVolume.has_value() && *left == mVolume.value()[0] && *right == mVolume.value()[1]) {
+    if (mVolume.has_value() && *left == mVolume.value()[0] && *right == mVolume.value()[1] &&
+            !controller) {
         LOG_ALWAYS_FATAL_IF(
                 !mReturnedVolume.has_value(),
                 "The cached returned volume must not be null when the cached volume has value");
@@ -1387,14 +1389,14 @@
     }
     LOG_ALWAYS_FATAL_IF(mEffectInterface == nullptr, "%s", mEffectInterfaceDebug.c_str());
     uint32_t volume[2] = {*left, *right};
-    uint32_t *pVolume = controller ? volume : nullptr;
+    uint32_t* pVolume = isVolumeControl() ? volume : nullptr;
     uint32_t size = sizeof(volume);
     status_t status = mEffectInterface->command(EFFECT_CMD_SET_VOLUME,
                                                 size,
                                                 volume,
                                                 &size,
                                                 pVolume);
-    if (controller && status == NO_ERROR && size == sizeof(volume)) {
+    if (pVolume && status == NO_ERROR && size == sizeof(volume)) {
         mVolume = {*left, *right}; // Cache the value that has been set
         *left = volume[0];
         *right = volume[1];
@@ -2425,7 +2427,7 @@
             // volume will be set from setVolume_l.
             uint32_t left = 0;
             uint32_t right = 0;
-            effect->setVolume(&left, &right, true /*controller*/, true /*force*/);
+            effect->setVolume_l(&left, &right, true /*controller*/, true /*force*/);
         }
     }
 
@@ -2623,6 +2625,7 @@
 
     // first update volume controller
     const auto volumeControlIndex = findVolumeControl_l(0, size);
+    // index of the effect chain volume controller
     const int ctrlIdx = volumeControlIndex.value_or(-1);
     const sp<IAfEffectModule> volumeControlEffect =
             volumeControlIndex.has_value() ? mEffects[ctrlIdx] : nullptr;
@@ -2639,12 +2642,15 @@
     mVolumeControlEffect = volumeControlEffect;
 
     for (int i = 0; i < ctrlIdx; ++i) {
-        // For all volume control effects before the effect that controls volume, set the volume
+        // For all effects before the effect that controls volume, they are not controlling the
+        // effect chain volume, if these effects has the volume control capability, set the volume
         // to maximum to avoid double attenuation.
         if (mEffects[i]->isVolumeControl()) {
             uint32_t leftMax = 1 << 24;
             uint32_t rightMax = 1 << 24;
-            mEffects[i]->setVolume(&leftMax, &rightMax, true /*controller*/, true /*force*/);
+            mEffects[i]->setVolume_l(&leftMax, &rightMax,
+                                     false /* not an effect chain volume controller */,
+                                     true /* force */);
         }
     }
 
@@ -2653,7 +2659,8 @@
 
     // second get volume update from volume controller
     if (ctrlIdx >= 0) {
-        mEffects[ctrlIdx]->setVolume(&newLeft, &newRight, true);
+        mEffects[ctrlIdx]->setVolume_l(&newLeft, &newRight,
+                                       true /* effect chain volume controller */);
         mNewLeftVolume = newLeft;
         mNewRightVolume = newRight;
     }
@@ -2674,9 +2681,11 @@
         }
         // Pass requested volume directly if this is volume monitor module
         if (mEffects[i]->isVolumeMonitor()) {
-            mEffects[i]->setVolume(left, right, false);
+            mEffects[i]->setVolume_l(left, right,
+                                     false /* not an effect chain volume controller */);
         } else {
-            mEffects[i]->setVolume(&lVol, &rVol, false);
+            mEffects[i]->setVolume_l(&lVol, &rVol,
+                                     false /* not an effect chain volume controller */);
         }
     }
     *left = newLeft;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index b516c37..d107543 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -217,7 +217,8 @@
     }
     status_t setDevices(const AudioDeviceTypeAddrVector& devices) final EXCLUDES_EffectBase_Mutex;
     status_t setInputDevice(const AudioDeviceTypeAddr& device) final EXCLUDES_EffectBase_Mutex;
-    status_t setVolume(uint32_t *left, uint32_t *right, bool controller, bool force) final;
+    status_t setVolume_l(uint32_t* left, uint32_t* right, bool controller, bool force) final
+            REQUIRES(audio_utils::EffectChain_Mutex);
     status_t setMode(audio_mode_t mode) final EXCLUDES_EffectBase_Mutex;
     status_t setAudioSource(audio_source_t source) final EXCLUDES_EffectBase_Mutex;
     status_t start_l() final REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
@@ -265,8 +266,8 @@
                 ? EFFECT_BUFFER_ACCESS_WRITE : EFFECT_BUFFER_ACCESS_ACCUMULATE;
     }
 
-    status_t setVolumeInternal(uint32_t *left, uint32_t *right, bool controller);
-
+    status_t setVolumeInternal(uint32_t* left, uint32_t* right,
+                               bool controller /* the volume controller effect of the chain */);
 
     effect_config_t     mConfig;    // input and output audio configuration
     sp<EffectHalInterface> mEffectInterface; // Effect module HAL
diff --git a/services/audioflinger/IAfEffect.h b/services/audioflinger/IAfEffect.h
index b9bb18c..2bf252a 100644
--- a/services/audioflinger/IAfEffect.h
+++ b/services/audioflinger/IAfEffect.h
@@ -163,8 +163,9 @@
     virtual int16_t *inBuffer() const = 0;
     virtual status_t setDevices(const AudioDeviceTypeAddrVector &devices) = 0;
     virtual status_t setInputDevice(const AudioDeviceTypeAddr &device) = 0;
-    virtual status_t setVolume(uint32_t *left, uint32_t *right, bool controller,
-                               bool force = false) = 0;
+    virtual status_t setVolume_l(uint32_t* left, uint32_t* right,
+                                 bool controller /* effect controlling chain volume */,
+                                 bool force = false) REQUIRES(audio_utils::EffectChain_Mutex) = 0;
     virtual status_t setOffloaded_l(bool offloaded, audio_io_handle_t io) = 0;
     virtual bool isOffloaded_l() const = 0;
 
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 4518d48..a7da658 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -19,8 +19,9 @@
 #include <android/media/IAudioTrackCallback.h>
 #include <android/media/IEffectClient.h>
 #include <audiomanager/IAudioManager.h>
-#include <audio_utils/mutex.h>
+#include <audio_utils/DeferredExecutor.h>
 #include <audio_utils/MelProcessor.h>
+#include <audio_utils/mutex.h>
 #include <binder/MemoryDealer.h>
 #include <datapath/AudioStreamIn.h>
 #include <datapath/AudioStreamOut.h>
@@ -395,6 +396,12 @@
     // avoid races.
     virtual void waitWhileThreadBusy_l(audio_utils::unique_lock& ul)
             REQUIRES(mutex()) = 0;
+
+    // The ThreadloopExecutor is used to defer functors or dtors
+    // to when the Threadloop does not hold any mutexes (at the end of the
+    // processing period cycle).
+    virtual audio_utils::DeferredExecutor& getThreadloopExecutor() = 0;
+
     // Dynamic cast to derived interface
     virtual sp<IAfDirectOutputThread> asIAfDirectOutputThread() { return nullptr; }
     virtual sp<IAfDuplicatingThread> asIAfDuplicatingThread() { return nullptr; }
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index 168bcca..a9c87ad 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -579,10 +579,11 @@
             size_t bufferSize,
             audio_output_flags_t flags,
             const Timeout& timeout = {},
-            size_t frameCountToBeReady = 1 /** Default behaviour is to start
+            size_t frameCountToBeReady = 1, /** Default behaviour is to start
                                              *  as soon as possible to have
                                              *  the lowest possible latency
-                                             *  even if it might glitch. */);
+                                             *  even if it might glitch. */
+            float speed = 1.0f);
 };
 
 class IAfPatchRecord : public virtual IAfRecordTrack, public virtual IAfPatchTrackBase {
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 4333cc8..f57470f 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -646,7 +646,8 @@
                                            tempRecordTrack->bufferSize(),
                                            outputFlags,
                                            {} /*timeout*/,
-                                           frameCountToBeReady);
+                                           frameCountToBeReady,
+                                           1.0f);
     status = mPlayback.checkTrack(tempPatchTrack.get());
     if (status != NO_ERROR) {
         return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1e1b6d2..2cc6236 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -455,7 +455,7 @@
     void                queueBuffer(Buffer& inBuffer);
     void                clearBufferQueue();
 
-    void                restartIfDisabled();
+    void restartIfDisabled() override;
 
     // Maximum number of pending buffers allocated by OutputTrack::write()
     static const uint8_t kMaxOverFlowBuffers = 10;
@@ -497,10 +497,11 @@
                                    size_t bufferSize,
                                    audio_output_flags_t flags,
                                    const Timeout& timeout = {},
-                                   size_t frameCountToBeReady = 1 /** Default behaviour is to start
+                                   size_t frameCountToBeReady = 1, /** Default behaviour is to start
                                                                     *  as soon as possible to have
                                                                     *  the lowest possible latency
-                                                                    *  even if it might glitch. */);
+                                                                    *  even if it might glitch. */
+                                   float speed = 1.0f);
     ~PatchTrack() override;
 
     size_t framesReady() const final;
@@ -518,7 +519,7 @@
     void releaseBuffer(Proxy::Buffer* buffer) final;
 
 private:
-            void restartIfDisabled();
+    void restartIfDisabled() override;
 };  // end of PatchTrack
 
 } // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 66e89e4..5c0ca5e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4646,7 +4646,11 @@
 
         // FIXME Note that the above .clear() is no longer necessary since effectChains
         // is now local to this block, but will keep it for now (at least until merge done).
+
+        mThreadloopExecutor.process();
     }
+    mThreadloopExecutor.process(); // process any remaining deferred actions.
+    // deferred actions after this point are ignored.
 
     threadLoop_exit();
 
@@ -7185,14 +7189,11 @@
 {
     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 {
@@ -8670,6 +8671,9 @@
 
         // loop over each active track
         for (size_t i = 0; i < size; i++) {
+            if (activeTrack) {  // ensure track release is outside lock.
+                oldActiveTracks.emplace_back(std::move(activeTrack));
+            }
             activeTrack = activeTracks[i];
 
             // skip fast tracks, as those are handled directly by FastCapture
@@ -8813,11 +8817,14 @@
             mIoJitterMs.add(jitterMs);
             mProcessTimeMs.add(processMs);
         }
+       mThreadloopExecutor.process();
         // update timing info.
         mLastIoBeginNs = lastIoBeginNs;
         mLastIoEndNs = lastIoEndNs;
         lastLoopCountRead = loopCount;
     }
+    mThreadloopExecutor.process(); // process any remaining deferred actions.
+    // deferred actions after this point are ignored.
 
     standbyIfNotAlreadyInStandby();
 
@@ -10603,7 +10610,10 @@
         unlockEffectChains(effectChains);
         // Effect chains will be actually deleted here if they were removed from
         // mEffectChains list during mixing or effects processing
+        mThreadloopExecutor.process();
     }
+    mThreadloopExecutor.process(); // process any remaining deferred actions.
+    // deferred actions after this point are ignored.
 
     threadLoop_exit();
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 4b2ade4..654b841 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -571,6 +571,10 @@
     void stopMelComputation_l() override
             REQUIRES(audio_utils::AudioFlinger_Mutex);
 
+    audio_utils::DeferredExecutor& getThreadloopExecutor() override {
+        return mThreadloopExecutor;
+    }
+
 protected:
 
                 // entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -877,6 +881,14 @@
 
                 SimpleLog mLocalLog;  // locked internally
 
+    // mThreadloopExecutor contains deferred functors and object (dtors) to
+    // be executed at the end of the processing period, without any
+    // mutexes held.
+    //
+    // mThreadloopExecutor is locked internally, so its methods are thread-safe
+    // for access.
+    audio_utils::DeferredExecutor mThreadloopExecutor;
+
     private:
     void dumpBase_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
     void dumpEffectChains_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 5708c61..a0b85f7 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -333,6 +333,9 @@
                                     // true for Track, false for RecordTrack,
                                     // this could be a track type if needed later
 
+    void deferRestartIfDisabled();
+    virtual void restartIfDisabled() {}
+
     const wp<IAfThreadBase> mThread;
     const alloc_type     mAllocType;
     /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f8cfc12..f5f11cc 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -314,6 +314,17 @@
     return NO_ERROR;
 }
 
+void TrackBase::deferRestartIfDisabled()
+{
+    const auto thread = mThread.promote();
+    if (thread == nullptr) return;
+    thread->getThreadloopExecutor().defer(
+            [track = wp<TrackBase>::fromExisting(this)] {
+            const auto actual = track.promote();
+            if (actual) actual->restartIfDisabled();
+        });
+}
+
 PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
         IAfThreadBase* thread, const Timeout& timeout)
     : mProxy(proxy)
@@ -2310,7 +2321,7 @@
                 waitTimeLeftMs = 0;
             }
             if (status == NOT_ENOUGH_DATA) {
-                restartIfDisabled();
+                deferRestartIfDisabled();
                 continue;
             }
         }
@@ -2322,7 +2333,7 @@
         buf.mFrameCount = outFrames;
         buf.mRaw = NULL;
         mClientProxy->releaseBuffer(&buf);
-        restartIfDisabled();
+        deferRestartIfDisabled();
         pInBuffer->frameCount -= outFrames;
         pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize;
         mOutBuffer.frameCount -= outFrames;
@@ -2449,10 +2460,11 @@
         size_t bufferSize,
         audio_output_flags_t flags,
         const Timeout& timeout,
-        size_t frameCountToBeReady /** Default behaviour is to start
+        size_t frameCountToBeReady, /** Default behaviour is to start
                                          *  as soon as possible to have
                                          *  the lowest possible latency
-                                         *  even if it might glitch. */)
+                                         *  even if it might glitch. */
+        float speed)
 {
     return sp<PatchTrack>::make(
             playbackThread,
@@ -2465,7 +2477,8 @@
             bufferSize,
             flags,
             timeout,
-            frameCountToBeReady);
+            frameCountToBeReady,
+            speed);
 }
 
 PatchTrack::PatchTrack(IAfPlaybackThread* playbackThread,
@@ -2478,17 +2491,26 @@
                                                      size_t bufferSize,
                                                      audio_output_flags_t flags,
                                                      const Timeout& timeout,
-                                                     size_t frameCountToBeReady)
+                                                     size_t frameCountToBeReady,
+                                                     float speed)
     :   Track(playbackThread, NULL, streamType,
               audio_attributes_t{} /* currently unused for patch track */,
               sampleRate, format, channelMask, frameCount,
               buffer, bufferSize, nullptr /* sharedBuffer */,
               AUDIO_SESSION_NONE, getpid(), audioServerAttributionSource(getpid()), flags,
-              TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
-        PatchTrackBase(mCblk ? new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true)
-                        : nullptr,
+              TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady, speed),
+        PatchTrackBase(mCblk ? new AudioTrackClientProxy(mCblk, mBuffer, frameCount, mFrameSize,
+                        true /*clientInServer*/) : nullptr,
                        playbackThread, timeout)
 {
+    if (mProxy != nullptr) {
+        sp<AudioTrackClientProxy>::cast(mProxy)->setPlaybackRate({
+                /* .mSpeed = */ speed,
+                /* .mPitch = */ AUDIO_TIMESTRETCH_PITCH_NORMAL,
+                /* .mStretchMode = */ AUDIO_TIMESTRETCH_STRETCH_DEFAULT,
+                /* .mFallbackMode = */ AUDIO_TIMESTRETCH_FALLBACK_FAIL
+        });
+    }
     ALOGV("%s(%d): sampleRate %d mPeerTimeout %d.%03d sec",
                                       __func__, mId, sampleRate,
                                       (int)mPeerTimeout.tv_sec,
@@ -2566,7 +2588,7 @@
     const size_t originalFrameCount = buffer->mFrameCount;
     do {
         if (status == NOT_ENOUGH_DATA) {
-            restartIfDisabled();
+            deferRestartIfDisabled();
             buffer->mFrameCount = originalFrameCount; // cleared on error, must be restored.
         }
         status = mProxy->obtainBuffer(buffer, timeOut);
@@ -2577,7 +2599,7 @@
 void PatchTrack::releaseBuffer(Proxy::Buffer* buffer)
 {
     mProxy->releaseBuffer(buffer);
-    restartIfDisabled();
+    deferRestartIfDisabled();
 
     // Check if the PatchTrack has enough data to write once in releaseBuffer().
     // If not, prevent an underrun from occurring by moving the track into FS_FILLING;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index e91e2a3..deb7345 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -294,8 +294,7 @@
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
                                       audio_port_handle_t *portId,
-                                      uid_t uid,
-                                      bool internal = false) = 0;
+                                      uid_t uid) = 0;
     virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
 
     virtual status_t setMasterMono(bool mono) = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index 6167f95..3edd4de 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -47,13 +47,17 @@
 
     if (active) {
         // On MMAP IOs, the preferred device is selected by the first client (virtual client
-        // created when the mmap stream is opened). This client is never active.
+        // created when the mmap stream is opened). This client is never active and we only
+        // consider the Filter criteria, not the active state.
         // On non MMAP IOs, the preferred device is honored only if all active clients have
         // a preferred device in which case the first client drives the selection.
         if (desc->isMmap()) {
-            // The client list is never empty on a MMAP IO
-            return devices.getDeviceFromId(
-                    desc->clientsList(false /*activeOnly*/)[0]->preferredDeviceId());
+            auto matchingClients = desc->clientsList(
+                    false /*activeOnly*/, filter, true /*preferredDevice*/);
+            if (matchingClients.empty()) {
+                return nullptr;
+            }
+            return devices.getDeviceFromId(matchingClients[0]->preferredDeviceId());
         } else {
             auto activeClientsWithRoute =
                 desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index c26ea10..0f2fe24 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -41,7 +41,8 @@
 {
 public:
     AudioInputDescriptor(const sp<IOProfile>& profile,
-                         AudioPolicyClientInterface *clientInterface);
+                         AudioPolicyClientInterface *clientInterface,
+                         bool isPreemptor);
 
     virtual ~AudioInputDescriptor() = default;
 
@@ -127,6 +128,8 @@
     // active use case
     void checkSuspendEffects();
 
+    bool isPreemptor() const { return mIsPreemptor; }
+
  private:
 
     void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
@@ -145,6 +148,7 @@
     int32_t mGlobalActiveCount = 0;  // non-client-specific activity ref count
     EffectDescriptorCollection mEnabledEffects;
     audio_input_flags_t& mFlags = AudioPortConfig::mFlags.input;
+    bool mIsPreemptor; // true if this input was opened after preemting another one
 };
 
 class AudioInputCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index a596c43..60da405 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -63,6 +63,8 @@
      * HW Audio Source.
      */
     virtual bool isInternal() const { return false; }
+    virtual bool isCallRx() const { return false; }
+    virtual bool isCallTx() const { return false; }
     audio_port_handle_t portId() const { return mPortId; }
     uid_t uid() const { return mUid; }
     audio_session_t session() const { return mSessionId; };
@@ -236,7 +238,7 @@
                            const sp<DeviceDescriptor>& srcDevice,
                            audio_stream_type_t stream, product_strategy_t strategy,
                            VolumeSource volumeSource,
-                           bool isInternal);
+                           bool isInternal, bool isCallRx, bool isCallTx);
 
     ~SourceClientDescriptor() override = default;
 
@@ -263,6 +265,8 @@
     wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
     void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
     bool isInternal() const override { return mIsInternal; }
+    bool isCallRx() const override { return mIsCallRx; }
+    bool isCallTx() const override { return mIsCallTx; }
 
     using ClientDescriptor::dump;
     void dump(String8 *dst, int spaces) const override;
@@ -294,6 +298,8 @@
      * requester to prevent rerouting SwOutput involved in raw patches.
      */
     bool mIsInternal = false;
+    bool mIsCallRx = false;
+    bool mIsCallTx = false;
 };
 
 class SourceClientCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 44f84b9..5a0fd97 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -30,9 +30,10 @@
 namespace android {
 
 AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile,
-                                           AudioPolicyClientInterface *clientInterface)
+                                           AudioPolicyClientInterface *clientInterface,
+                                           bool isPreemptor)
     : mProfile(profile)
-    ,  mClientInterface(clientInterface)
+    ,  mClientInterface(clientInterface), mIsPreemptor(isPreemptor)
 {
     if (profile != NULL) {
         profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -275,6 +276,9 @@
                             "%s invalid profile active count %u",
                             __func__, mProfile->curActiveCount);
         mProfile->curActiveCount--;
+        // allow preemption again now that at least one client was able to
+        // capture on this input
+        mIsPreemptor = false;
     }
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 667c189..ad6977b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -96,12 +96,14 @@
 SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
          audio_attributes_t attributes, const struct audio_port_config &config,
          const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
-         product_strategy_t strategy, VolumeSource volumeSource, bool isInternal) :
+         product_strategy_t strategy, VolumeSource volumeSource,
+         bool isInternal, bool isCallRx, bool isCallTx) :
     TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
         {config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
         stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
         {} /* Sources do not support secondary outputs*/, nullptr),
-    mSrcDevice(srcDevice), mIsInternal(isInternal)
+    mSrcDevice(srcDevice), mIsInternal(isInternal),
+    mIsCallRx(isCallRx), mIsCallTx(isCallTx)
 {
 }
 
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 799b8d9..aec8c16 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -30,6 +30,7 @@
         "libaudiopolicyengine_config",
     ],
     shared_libs: [
+        "com.android.media.audioserver-aconfig-cc",
         "libaudio_aidl_conversion_common_cpp",
         "libaudiofoundation",
         "libaudiopolicy",
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 13cc165..7666a2b 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -30,6 +30,7 @@
 #include <PolicyAudioPort.h>
 #include <IOProfile.h>
 #include <AudioIODescriptorInterface.h>
+#include <com_android_media_audioserver.h>
 #include <policy.h>
 #include <media/AudioContainers.h>
 #include <utils/String8.h>
@@ -154,12 +155,58 @@
     return EngineBase::setForceUse(usage, config);
 }
 
+bool Engine::isBtScoActive(DeviceVector& availableOutputDevices,
+                           const SwAudioOutputCollection &outputs) const {
+    if (availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+        return false;
+    }
+    // SCO is active if:
+    // 1) we are in a call and SCO is the preferred device for PHONE strategy
+    if (isInCall() && audio_is_bluetooth_out_sco_device(
+            getPreferredDeviceTypeForLegacyStrategy(availableOutputDevices, STRATEGY_PHONE))) {
+        return true;
+    }
+
+    // 2) A strategy for which the preferred device is SCO is active
+    for (const auto &ps : getOrderedProductStrategies()) {
+        if (outputs.isStrategyActive(ps) &&
+            !getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps)
+                .getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+            return true;
+        }
+    }
+    // 3) a ringtone is active and SCO is used for ringing
+    if (outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_RING))
+          && (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
+                    == AUDIO_POLICY_FORCE_BT_SCO)) {
+        return true;
+    }
+    // 4) an active input is routed from SCO
+    DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+    const auto &inputs = getApmObserver()->getInputs();
+    if (inputs.activeInputsCountOnDevices(availableInputDevices.getDevicesFromType(
+            AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) > 0) {
+        return true;
+    }
+    return false;
+}
+
 void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
                                             DeviceVector& availableOutputDevices,
                                             const SwAudioOutputCollection &outputs) const
 {
     DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
 
+    if (com::android::media::audioserver::use_bt_sco_for_media()) {
+        // remove A2DP and LE Audio devices whenever BT SCO is in use
+        if (isBtScoActive(availableOutputDevices, outputs)) {
+            availableOutputDevices.remove(
+                availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllA2dpSet()));
+            availableOutputDevices.remove(
+                availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllBleSet()));
+        }
+    }
+
     switch (strategy) {
     case STRATEGY_SONIFICATION_RESPECTFUL: {
         if (!(isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
@@ -381,10 +428,12 @@
 
         // LE audio broadcast device is only used if:
         // - No call is active
-        // - either MEDIA or SONIFICATION_RESPECTFUL is the highest priority active strategy
-        //   OR the LE audio unicast device is not active
+        // - either MEDIA, SONIFICATION_RESPECTFUL or SONIFICATION is the highest priority
+        // active strategy
+        // OR the LE audio unicast device is not active
         if (devices2.isEmpty() && !isInCall()
-                && (strategy == STRATEGY_MEDIA || strategy == STRATEGY_SONIFICATION_RESPECTFUL)) {
+                && (strategy == STRATEGY_MEDIA || strategy == STRATEGY_SONIFICATION_RESPECTFUL
+                      || strategy == STRATEGY_SONIFICATION)) {
             legacy_strategy topActiveStrategy = STRATEGY_NONE;
             for (const auto &ps : getOrderedProductStrategies()) {
                 if (outputs.isStrategyActive(ps)) {
@@ -396,6 +445,7 @@
 
             if (topActiveStrategy == STRATEGY_NONE || topActiveStrategy == STRATEGY_MEDIA
                     || topActiveStrategy == STRATEGY_SONIFICATION_RESPECTFUL
+                    || topActiveStrategy == STRATEGY_SONIFICATION
                     || !outputs.isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet())) {
                 devices2 =
                         availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST);
@@ -418,15 +468,27 @@
                         getLastRemovableMediaDevices(GROUP_WIRED, excludedDevices));
             }
         }
+
+        if (com::android::media::audioserver::use_bt_sco_for_media()) {
+            if (devices2.isEmpty() && isBtScoActive(availableOutputDevices, outputs)) {
+                devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+                        { AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
+                          AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+                          AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+            }
+        }
+
         if ((devices2.isEmpty()) &&
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
             devices2 = availableOutputDevices.getDevicesFromType(
                     AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
         }
+
         if (devices2.isEmpty()) {
             devices2 = availableOutputDevices.getFirstDevicesFromTypes({
                         AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_SPEAKER});
         }
+
         DeviceVector devices3;
         if (strategy == STRATEGY_MEDIA) {
             // ARC, SPDIF and AUX_LINE can co-exist with others.
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 878bca9..a6090cf 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -109,6 +109,9 @@
     DeviceVector getDisabledDevicesForInputSource(
             const DeviceVector& availableInputDevices, audio_source_t inputSource) const;
 
+    bool isBtScoActive(DeviceVector& availableOutputDevices,
+                       const SwAudioOutputCollection &outputs) const;
+
     std::map<product_strategy_t, legacy_strategy> mLegacyStrategyMap;
 };
 } // namespace audio_policy
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 6a94c81..7d2dfbc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -66,6 +66,7 @@
 using android::media::audio::common::AudioDeviceAddress;
 using android::media::audio::common::AudioPortDeviceExt;
 using android::media::audio::common::AudioPortExt;
+using com::android::media::audioserver::fix_call_audio_patch;
 using content::AttributionSourceState;
 
 //FIXME: workaround for truncated touch sounds
@@ -704,8 +705,10 @@
     audio_attributes_t attr = { .source = AUDIO_SOURCE_VOICE_COMMUNICATION };
     auto txSourceDevice = mEngine->getInputDeviceForAttributes(attr);
 
-    disconnectTelephonyAudioSource(mCallRxSourceClient);
-    disconnectTelephonyAudioSource(mCallTxSourceClient);
+    if (!fix_call_audio_patch()) {
+        disconnectTelephonyAudioSource(mCallRxSourceClient);
+        disconnectTelephonyAudioSource(mCallTxSourceClient);
+    }
 
     if (rxDevices.isEmpty()) {
         ALOGW("%s() no selected output device", __func__);
@@ -758,6 +761,9 @@
     // Use legacy routing method for voice calls via setOutputDevice() on primary output.
     // Otherwise, create two audio patches for TX and RX path.
     if (!createRxPatch) {
+        if (fix_call_audio_patch()) {
+            disconnectTelephonyAudioSource(mCallRxSourceClient);
+        }
         if (!hasPrimaryOutput()) {
             ALOGW("%s() no primary output available", __func__);
             return INVALID_OPERATION;
@@ -780,6 +786,8 @@
             }
         }
         connectTelephonyTxAudioSource(txSourceDevice, txSinkDevice, delayMs);
+    } else if (fix_call_audio_patch()) {
+        disconnectTelephonyAudioSource(mCallTxSourceClient);
     }
     if (waitMs != nullptr) {
         *waitMs = muteWaitMs;
@@ -801,17 +809,38 @@
 
 void AudioPolicyManager::connectTelephonyRxAudioSource()
 {
-    disconnectTelephonyAudioSource(mCallRxSourceClient);
+    const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
+
+    if (fix_call_audio_patch()) {
+        if (mCallRxSourceClient != nullptr) {
+            DeviceVector rxDevices =
+                  mEngine->getOutputDevicesForAttributes(aa, nullptr, false /*fromCache*/);
+            ALOG_ASSERT(!rxDevices.isEmpty() || !mCallRxSourceClient->isConnected(),
+                        "connectTelephonyRxAudioSource(): no device found for call RX source");
+            sp<DeviceDescriptor> rxDevice = rxDevices.itemAt(0);
+            if (mCallRxSourceClient->isConnected()
+                    && mCallRxSourceClient->sinkDevice()->equals(rxDevice)) {
+                return;
+            }
+            disconnectTelephonyAudioSource(mCallRxSourceClient);
+        }
+    } else {
+        disconnectTelephonyAudioSource(mCallRxSourceClient);
+    }
+
     const struct audio_port_config source = {
         .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE,
         .ext.device.type = AUDIO_DEVICE_IN_TELEPHONY_RX, .ext.device.address = ""
     };
-    const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
-
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
-    status_t status = startAudioSource(&source, &aa, &portId, 0 /*uid*/, true /*internal*/);
+
+    status_t status = startAudioSourceInternal(&source, &aa, &portId, 0 /*uid*/,
+                                       true /*internal*/, true /*isCallRx*/);
     ALOGE_IF(status != OK, "%s: failed to start audio source (%d)", __func__, status);
     mCallRxSourceClient = mAudioSources.valueFor(portId);
+    ALOGV("%s portdID %d between source %s and sink %s", __func__, portId,
+        mCallRxSourceClient->srcDevice()->toString().c_str(),
+        mCallRxSourceClient->sinkDevice()->toString().c_str());
     ALOGE_IF(mCallRxSourceClient == nullptr,
              "%s failed to start Telephony Rx AudioSource", __func__);
 }
@@ -830,15 +859,26 @@
         const sp<DeviceDescriptor> &srcDevice, const sp<DeviceDescriptor> &sinkDevice,
         uint32_t delayMs)
 {
-    disconnectTelephonyAudioSource(mCallTxSourceClient);
     if (srcDevice == nullptr || sinkDevice == nullptr) {
         ALOGW("%s could not create patch, invalid sink and/or source device(s)", __func__);
         return;
     }
+
+    if (fix_call_audio_patch()) {
+        if (mCallTxSourceClient != nullptr) {
+            if (mCallTxSourceClient->isConnected()
+                    && mCallTxSourceClient->srcDevice()->equals(srcDevice)) {
+                return;
+            }
+            disconnectTelephonyAudioSource(mCallTxSourceClient);
+        }
+    } else {
+        disconnectTelephonyAudioSource(mCallTxSourceClient);
+    }
+
     PatchBuilder patchBuilder;
     patchBuilder.addSource(srcDevice).addSink(sinkDevice);
-    ALOGV("%s between source %s and sink %s", __func__,
-            srcDevice->toString().c_str(), sinkDevice->toString().c_str());
+
     auto callTxSourceClientPortId = PolicyAudioPort::getNextUniqueId();
     const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
 
@@ -846,7 +886,8 @@
     srcDevice->toAudioPortConfig(&source);
     mCallTxSourceClient = new SourceClientDescriptor(
                 callTxSourceClientPortId, mUidCached, aa, source, srcDevice, AUDIO_STREAM_PATCH,
-                mCommunnicationStrategy, toVolumeSource(aa), true);
+                mCommunnicationStrategy, toVolumeSource(aa), true,
+                false /*isCallRx*/, true /*isCallTx*/);
     mCallTxSourceClient->setPreferredDeviceId(sinkDevice->getId());
 
     audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
@@ -854,6 +895,8 @@
                 mCallTxSourceClient, sinkDevice, patchBuilder.patch(), patchHandle, mUidCached,
                 delayMs);
     ALOGE_IF(status != NO_ERROR, "%s() error %d creating TX audio patch", __func__, status);
+    ALOGV("%s portdID %d between source %s and sink %s", __func__, callTxSourceClientPortId,
+        srcDevice->toString().c_str(), sinkDevice->toString().c_str());
     if (status == NO_ERROR) {
         mAudioSources.add(callTxSourceClientPortId, mCallTxSourceClient);
     }
@@ -3082,43 +3125,115 @@
         }
     }
 
+    bool isPreemptor = false;
     if (!profile->canOpenNewIo()) {
-        for (size_t i = 0; i < mInputs.size(); ) {
-            sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
-            if (desc->mProfile != profile) {
-                i++;
-                continue;
-            }
-            // if sound trigger, reuse input if used by other sound trigger on same session
-            // else
-            //    reuse input if active client app is not in IDLE state
-            //
-            RecordClientVector clients = desc->clientsList();
-            bool doClose = false;
-            for (const auto& client : clients) {
-                if (isSoundTrigger != client->isSoundTrigger()) {
+        if (com::android::media::audioserver::fix_input_sharing_logic()) {
+            //  First pick best candidate for preemption (there may not be any):
+            //  - Preempt and input if:
+            //     - It has only strictly lower priority use cases than the new client
+            //     - It has equal priority use cases than the new client, was not
+            //     opened thanks to preemption or has been active since opened.
+            //  - Order the preemption candidates by inactive first and priority second
+            sp<AudioInputDescriptor> closeCandidate;
+            int leastCloseRank = INT_MAX;
+            static const int sCloseActive = 0x100;
+
+            for (size_t i = 0; i < mInputs.size(); i++) {
+                sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
+                if (desc->mProfile != profile) {
                     continue;
                 }
-                if (client->isSoundTrigger()) {
-                    if (session == client->session()) {
+                sp<RecordClientDescriptor> topPrioClient = desc->getHighestPriorityClient();
+                if (topPrioClient == nullptr) {
+                    continue;
+                }
+                int topPrio = source_priority(topPrioClient->source());
+                if (topPrio < source_priority(attributes.source)
+                      || (topPrio == source_priority(attributes.source)
+                          && !desc->isPreemptor())) {
+                    int closeRank = (desc->isActive() ? sCloseActive : 0) + topPrio;
+                    if (closeRank < leastCloseRank) {
+                        leastCloseRank = closeRank;
+                        closeCandidate = desc;
+                    }
+                }
+            }
+
+            if (closeCandidate != nullptr) {
+                closeInput(closeCandidate->mIoHandle);
+                // Mark the new input as being issued from a preemption
+                // so that is will not be preempted later
+                isPreemptor = true;
+            } else {
+                // Then pick the best reusable input (There is always one)
+                // The order of preference is:
+                // 1) active inputs with same use case as the new client
+                // 2) inactive inputs with same use case
+                // 3) active inputs with different use cases
+                // 4) inactive inputs with different use cases
+                sp<AudioInputDescriptor> reuseCandidate;
+                int leastReuseRank = INT_MAX;
+                static const int sReuseDifferentUseCase = 0x100;
+
+                for (size_t i = 0; i < mInputs.size(); i++) {
+                    sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
+                    if (desc->mProfile != profile) {
+                        continue;
+                    }
+                    int reuseRank = sReuseDifferentUseCase;
+                    for (const auto& client: desc->getClientIterable()) {
+                        if (client->source() == attributes.source) {
+                            reuseRank = 0;
+                            break;
+                        }
+                    }
+                    reuseRank += desc->isActive() ? 0 : 1;
+                    if (reuseRank < leastReuseRank) {
+                        leastReuseRank = reuseRank;
+                        reuseCandidate = desc;
+                    }
+                }
+                return reuseCandidate->mIoHandle;
+            }
+        } else { // fix_input_sharing_logic()
+            for (size_t i = 0; i < mInputs.size(); ) {
+                 sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
+                 if (desc->mProfile != profile) {
+                     i++;
+                     continue;
+                 }
+                // if sound trigger, reuse input if used by other sound trigger on same session
+                // else
+                //    reuse input if active client app is not in IDLE state
+                //
+                RecordClientVector clients = desc->clientsList();
+                bool doClose = false;
+                for (const auto& client : clients) {
+                    if (isSoundTrigger != client->isSoundTrigger()) {
+                        continue;
+                    }
+                    if (client->isSoundTrigger()) {
+                        if (session == client->session()) {
+                            return desc->mIoHandle;
+                        }
+                        continue;
+                    }
+                    if (client->active() && client->appState() != APP_STATE_IDLE) {
                         return desc->mIoHandle;
                     }
-                    continue;
+                    doClose = true;
                 }
-                if (client->active() && client->appState() != APP_STATE_IDLE) {
-                    return desc->mIoHandle;
+                if (doClose) {
+                    closeInput(desc->mIoHandle);
+                } else {
+                    i++;
                 }
-                doClose = true;
-            }
-            if (doClose) {
-                closeInput(desc->mIoHandle);
-            } else {
-                i++;
             }
         }
     }
 
-    sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile, mpClientInterface);
+    sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(
+            profile, mpClientInterface, isPreemptor);
 
     audio_config_t lConfig = AUDIO_CONFIG_INITIALIZER;
     lConfig.sample_rate = profileSamplingRate;
@@ -3584,7 +3699,9 @@
         if (isVolumeConsistentForCalls(vs, {mCallRxSourceClient->sinkDevice()->type()},
                 isVoiceVolSrc, isBtScoVolSrc, __func__)
                 && (isVoiceVolSrc || isBtScoVolSrc)) {
-            setVoiceVolume(index, curves, isVoiceVolSrc, 0);
+            bool voiceVolumeManagedByHost = isVoiceVolSrc &&
+                    !audio_is_ble_out_device(mCallRxSourceClient->sinkDevice()->type());
+            setVoiceVolume(index, curves, voiceVolumeManagedByHost, 0);
         }
     }
 
@@ -5095,7 +5212,7 @@
             new SourceClientDescriptor(
                 portId, uid, attributes, *source, srcDevice, AUDIO_STREAM_PATCH,
                 mEngine->getProductStrategyForAttributes(attributes), toVolumeSource(attributes),
-                true);
+                true, false /*isCallRx*/, false /*isCallTx*/);
     sourceDesc->setPreferredDeviceId(sinkDevice->getId());
 
     status_t status =
@@ -5427,7 +5544,7 @@
                         outputDesc->toAudioPortConfig(&srcMixPortConfig, nullptr);
                         // for volume control, we may need a valid stream
                         srcMixPortConfig.ext.mix.usecase.stream =
-                            (!sourceDesc->isInternal() || isCallTxAudioSource(sourceDesc)) ?
+                            (!sourceDesc->isInternal() || sourceDesc->isCallTx()) ?
                                     mEngine->getStreamTypeForAttributes(sourceDesc->attributes()) :
                                     AUDIO_STREAM_PATCH;
                         patchBuilder.addSource(srcMixPortConfig);
@@ -5765,7 +5882,15 @@
 status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
                                               const audio_attributes_t *attributes,
                                               audio_port_handle_t *portId,
-                                              uid_t uid, bool internal)
+                                              uid_t uid) {
+    return startAudioSourceInternal(source, attributes, portId, uid,
+                                    false /*internal*/, false /*isCallRx*/);
+}
+
+status_t AudioPolicyManager::startAudioSourceInternal(const struct audio_port_config *source,
+                                              const audio_attributes_t *attributes,
+                                              audio_port_handle_t *portId,
+                                              uid_t uid, bool internal, bool isCallRx)
 {
     ALOGV("%s", __FUNCTION__);
     *portId = AUDIO_PORT_HANDLE_NONE;
@@ -5798,7 +5923,7 @@
         new SourceClientDescriptor(*portId, uid, *attributes, *source, srcDevice,
                                    mEngine->getStreamTypeForAttributes(*attributes),
                                    mEngine->getProductStrategyForAttributes(*attributes),
-                                   toVolumeSource(*attributes), internal);
+                                   toVolumeSource(*attributes), internal, isCallRx, false);
 
     status_t status = connectAudioSource(sourceDesc);
     if (status == NO_ERROR) {
@@ -5891,7 +6016,8 @@
 float AudioPolicyManager::getStreamVolumeDB(
         audio_stream_type_t stream, int index, audio_devices_t device)
 {
-    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, {device});
+    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index,
+                         {device}, /* adjustAttenuation= */false);
 }
 
 status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
@@ -6621,8 +6747,8 @@
                     __func__, inProfile->getTagName().c_str());
                 continue;
             }
-            sp<AudioInputDescriptor> inputDesc =
-                    new AudioInputDescriptor(inProfile, mpClientInterface);
+            sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(
+                    inProfile, mpClientInterface, false /*isPreemptor*/);
 
             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status_t status = inputDesc->open(nullptr,
@@ -6932,7 +7058,7 @@
                 continue;
             }
 
-            desc = new AudioInputDescriptor(profile, mpClientInterface);
+            desc = new AudioInputDescriptor(profile, mpClientInterface, false  /*isPreemptor*/);
             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status = desc->open(nullptr, device, AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_NONE, &input);
 
@@ -7178,7 +7304,7 @@
         sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
         if (sourceDesc != nullptr && followsSameRouting(attr, sourceDesc->attributes())
                 && sourceDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE
-                && !isCallRxAudioSource(sourceDesc) && !sourceDesc->isInternal()) {
+                && !sourceDesc->isCallRx() && !sourceDesc->isInternal()) {
             connectAudioSource(sourceDesc);
         }
     }
@@ -7285,7 +7411,7 @@
                 }
             }
             sp<SourceClientDescriptor> source = getSourceForAttributesOnOutput(srcOut, attr);
-            if (source != nullptr && !isCallRxAudioSource(source) && !source->isInternal()) {
+            if (source != nullptr && !source->isCallRx() && !source->isInternal()) {
                 connectAudioSource(source);
             }
         }
@@ -8069,9 +8195,15 @@
                                         VolumeSource volumeSource,
                                         int index,
                                         const DeviceTypeSet& deviceTypes,
+                                        bool adjustAttenuation,
                                         bool computeInternalInteraction)
 {
-    float volumeDb = adjustDeviceAttenuationForAbsVolume(curves, volumeSource, index, deviceTypes);
+    float volumeDb;
+    if (adjustAttenuation) {
+        volumeDb = adjustDeviceAttenuationForAbsVolume(curves, volumeSource, index, deviceTypes);
+    } else {
+        volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);
+    }
     ALOGV("%s volume source %d, index %d,  devices %s, compute internal %b ", __func__,
           volumeSource, index, dumpDeviceTypes(deviceTypes).c_str(), computeInternalInteraction);
 
@@ -8092,7 +8224,8 @@
             mOutputs.isActive(ringVolumeSrc, 0)) {
         auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
         const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes,
-                /* computeInternalInteraction= */ false);
+                                                 adjustAttenuation,
+                                                 /* computeInternalInteraction= */false);
         return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
     }
 
@@ -8110,7 +8243,7 @@
         int voiceVolumeIndex = voiceCurves.getVolumeIndex(deviceTypes);
         const float maxVoiceVolDb =
                 computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes,
-                              /* computeInternalInteraction= */ false)
+                        adjustAttenuation, /* computeInternalInteraction= */false)
                 + IN_CALL_EARPIECE_HEADROOM_DB;
         // FIXME: Workaround for call screening applications until a proper audio mode is defined
         // to support this scenario : Exempt the RING stream from the audio cap if the audio was
@@ -8163,7 +8296,8 @@
                                              musicVolumeSrc,
                                              musicCurves.getVolumeIndex(musicDevice),
                                              musicDevice,
-                                             /* computeInternalInteraction= */ false);
+                                              adjustAttenuation,
+                                              /* computeInternalInteraction= */ false);
             float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
                         musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
             if (volumeDb > minVolDb) {
@@ -8172,9 +8306,10 @@
             }
             if (Volume::getDeviceForVolume(deviceTypes) != AUDIO_DEVICE_OUT_SPEAKER
                     &&  !Intersection(deviceTypes, {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
-                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}).empty()) {
-                // on A2DP, also ensure notification volume is not too low compared to media when
-                // intended to be played
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+                        AUDIO_DEVICE_OUT_BLE_HEADSET}).empty()) {
+                // on A2DP/BLE, also ensure notification volume is not too low compared to media
+                // when intended to be played.
                 if ((volumeDb > -96.0f) &&
                         (musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
                     ALOGV("%s increasing volume for volume source=%d device=%s from %f to %f",
@@ -8256,9 +8391,10 @@
 
     float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
     if (outputDesc->isFixedVolume(deviceTypes) ||
-            // Force VoIP volume to max for bluetooth SCO device except if muted
+            // Force VoIP volume to max for bluetooth SCO/BLE device except if muted
             (index != 0 && (isVoiceVolSrc || isBtScoVolSrc) &&
-                    isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
+                    (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);
@@ -8266,17 +8402,19 @@
             deviceTypes, delayMs, force, isVoiceVolSrc);
 
     if (outputDesc == mPrimaryOutput && (isVoiceVolSrc || isBtScoVolSrc)) {
-        setVoiceVolume(index, curves, isVoiceVolSrc, delayMs);
+        bool voiceVolumeManagedByHost = isVoiceVolSrc &&
+                !isSingleDeviceType(deviceTypes, audio_is_ble_out_device);
+        setVoiceVolume(index, curves, voiceVolumeManagedByHost, delayMs);
     }
     return NO_ERROR;
 }
 
 void AudioPolicyManager::setVoiceVolume(
-        int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs) {
+        int index, IVolumeCurves &curves, bool voiceVolumeManagedByHost, int delayMs) {
     float voiceVolume;
-    // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed
+    // Force voice volume to max or mute for Bluetooth SCO/BLE as other attenuations are managed
     // by the headset
-    if (isVoiceVolSrc) {
+    if (voiceVolumeManagedByHost) {
         voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
     } else {
         voiceVolume = index == 0 ? 0.0 : 1.0;
@@ -8454,7 +8592,7 @@
         sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
         if (sourceDesc->isConnected() && (sourceDesc->srcDevice()->equals(deviceDesc) ||
                                           sourceDesc->sinkDevice()->equals(deviceDesc))
-                && !isCallRxAudioSource(sourceDesc)) {
+                && !sourceDesc->isCallRx()) {
             disconnectAudioSource(sourceDesc);
         }
     }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 011e867..f899cd5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -345,8 +345,7 @@
         virtual status_t startAudioSource(const struct audio_port_config *source,
                                           const audio_attributes_t *attributes,
                                           audio_port_handle_t *portId,
-                                          uid_t uid,
-                                          bool internal = false);
+                                          uid_t uid);
         virtual status_t stopAudioSource(audio_port_handle_t portId);
 
         virtual status_t setMasterMono(bool mono);
@@ -591,6 +590,8 @@
          * @param index index to match in the volume curves for the calculation
          * @param deviceTypes devices that should be considered in the volume curves for the
          *        calculation
+         * @param adjustAttenuation boolean indicating whether we should adjust the value to
+         *        avoid double attenuation when controlling an avrcp device
          * @param computeInternalInteraction boolean indicating whether recursive volume computation
          *        should continue within the volume computation. Defaults to {@code true} so the
          *        volume interactions can be computed. Calls within the method should always set the
@@ -599,6 +600,7 @@
          */
         virtual float computeVolume(IVolumeCurves &curves, VolumeSource volumeSource,
                                int index, const DeviceTypeSet& deviceTypes,
+                               bool adjustAttenuation = true,
                                bool computeInternalInteraction = true);
 
         // rescale volume index from srcStream within range of dstStream
@@ -705,14 +707,6 @@
         void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0,
                 bool skipDelays = false);
 
-        bool isCallRxAudioSource(const sp<SourceClientDescriptor> &source) {
-            return mCallRxSourceClient != nullptr && source == mCallRxSourceClient;
-        }
-
-        bool isCallTxAudioSource(const sp<SourceClientDescriptor> &source) {
-            return mCallTxSourceClient != nullptr && source == mCallTxSourceClient;
-        }
-
         void connectTelephonyRxAudioSource();
 
         void disconnectTelephonyAudioSource(sp<SourceClientDescriptor> &clientDesc);
@@ -976,6 +970,12 @@
         void checkLeBroadcastRoutes(bool wasUnicastActive,
                 sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs);
 
+        status_t startAudioSourceInternal(const struct audio_port_config *source,
+                                          const audio_attributes_t *attributes,
+                                          audio_port_handle_t *portId,
+                                          uid_t uid,
+                                          bool internal,
+                                          bool isCallRx);
         const uid_t mUidCached;                         // AID_AUDIOSERVER
         sp<const AudioPolicyConfig> mConfig;
         EngineInstance mEngine;                         // Audio Policy Engine instance
diff --git a/services/audiopolicy/permission/NativePermissionController.cpp b/services/audiopolicy/permission/NativePermissionController.cpp
index 9fcf22d..8659f2c 100644
--- a/services/audiopolicy/permission/NativePermissionController.cpp
+++ b/services/audiopolicy/permission/NativePermissionController.cpp
@@ -24,9 +24,9 @@
 #include <cutils/android_filesystem_config.h>
 #include <utils/Errors.h>
 
-using ::android::base::unexpected;
 using ::android::binder::Status;
-using ::android::error::Result;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
 
 namespace com::android::media::permission {
 static std::optional<std::string> getFixedPackageName(uid_t uid) {
@@ -103,23 +103,31 @@
 
 // -- End Binder methods
 
-Result<std::vector<std::string>> NativePermissionController::getPackagesForUid(uid_t uid) const {
+BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
+        uid_t uid) const {
     uid = uid % AID_USER_OFFSET;
     const auto fixed_package_opt = getFixedPackageName(uid);
     if (fixed_package_opt.has_value()) {
-        return Result<std::vector<std::string>>{std::in_place_t{}, {fixed_package_opt.value()}};
+        return BinderResult<std::vector<std::string>>{std::in_place_t{},
+                                                      {fixed_package_opt.value()}};
     }
     std::lock_guard l{m_};
-    if (!is_package_populated_) return unexpected{::android::NO_INIT};
+    if (!is_package_populated_) {
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_STATE,
+                "NPC::getPackagesForUid: controller never populated by system_server");
+    }
     const auto cursor = package_map_.find(uid);
     if (cursor != package_map_.end()) {
         return cursor->second;
     } else {
-        return unexpected{::android::BAD_VALUE};
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_ARGUMENT,
+                ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
     }
 }
 
-Result<bool> NativePermissionController::validateUidPackagePair(
+BinderResult<bool> NativePermissionController::validateUidPackagePair(
         uid_t uid, const std::string& packageName) const {
     uid = uid % AID_USER_OFFSET;
     const auto fixed_package_opt = getFixedPackageName(uid);
@@ -127,20 +135,27 @@
         return packageName == fixed_package_opt.value();
     }
     std::lock_guard l{m_};
-    if (!is_package_populated_) return unexpected{::android::NO_INIT};
+    if (!is_package_populated_) {
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_STATE,
+                "NPC::validatedUidPackagePair: controller never populated by system_server");
+    }
     const auto cursor = package_map_.find(uid);
     return (cursor != package_map_.end()) &&
            (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
             cursor->second.end());
 }
 
-Result<bool> NativePermissionController::checkPermission(PermissionEnum perm, uid_t uid) const {
+BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
+                                                               uid_t uid) const {
     std::lock_guard l{m_};
     const auto& uids = permission_map_[static_cast<size_t>(perm)];
     if (!uids.empty()) {
         return std::binary_search(uids.begin(), uids.end(), uid);
     } else {
-        return unexpected{::android::NO_INIT};
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_STATE,
+                "NPC::checkPermission: controller never populated by system_server");
     }
 }
 
diff --git a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
index 2c32289..f313422 100644
--- a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
+++ b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
@@ -20,31 +20,39 @@
 #include <error/expected_utils.h>
 #include <utils/Log.h>
 
+using ::android::binder::Status;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
+
 namespace com::android::media::permission {
 
-using ::android::base::unexpected;
-
-Result<ValidatedAttributionSourceState> ValidatedAttributionSourceState::createFromBinderContext(
-        AttributionSourceState attr, const IPermissionProvider& provider) {
+BinderResult<ValidatedAttributionSourceState>
+ValidatedAttributionSourceState::createFromBinderContext(AttributionSourceState attr,
+                                                         const IPermissionProvider& provider) {
     attr.pid = ::android::IPCThreadState::self()->getCallingPid();
     attr.uid = ::android::IPCThreadState::self()->getCallingUid();
     return createFromTrustedUidNoPackage(std::move(attr), provider);
 }
 
-Result<ValidatedAttributionSourceState>
+BinderResult<ValidatedAttributionSourceState>
 ValidatedAttributionSourceState::createFromTrustedUidNoPackage(
         AttributionSourceState attr, const IPermissionProvider& provider) {
     if (attr.packageName.has_value() && attr.packageName->size() != 0) {
         if (VALUE_OR_RETURN(provider.validateUidPackagePair(attr.uid, attr.packageName.value()))) {
             return ValidatedAttributionSourceState{std::move(attr)};
         } else {
-            return unexpected{::android::PERMISSION_DENIED};
+            return unexpectedExceptionCode(Status::EX_SECURITY,
+                                           attr.toString()
+                                                   .insert(0, ": invalid attr ")
+                                                   .insert(0, __PRETTY_FUNCTION__)
+                                                   .c_str());
         }
     } else {
         // For APIs which don't appropriately pass attribution sources or packages, we need
         // to populate the package name with our best guess.
         const auto packageNames = VALUE_OR_RETURN(provider.getPackagesForUid(attr.uid));
-        LOG_ALWAYS_FATAL_IF(packageNames.empty());
+        LOG_ALWAYS_FATAL_IF(packageNames.empty(), "%s BUG: empty package list from controller",
+                            __PRETTY_FUNCTION__);
         attr.packageName = std::move(packageNames[0]);
         return ValidatedAttributionSourceState{std::move(attr)};
     }
diff --git a/services/audiopolicy/permission/include/media/IPermissionProvider.h b/services/audiopolicy/permission/include/media/IPermissionProvider.h
index 27a61ea..8d90543 100644
--- a/services/audiopolicy/permission/include/media/IPermissionProvider.h
+++ b/services/audiopolicy/permission/include/media/IPermissionProvider.h
@@ -22,7 +22,7 @@
 #include <vector>
 
 #include <com/android/media/permission/PermissionEnum.h>
-#include <error/Result.h>
+#include <error/BinderResult.h>
 
 namespace com::android::media::permission {
 
@@ -31,19 +31,20 @@
     // Get all package names which run under a certain app-id. Returns non-empty.
     // Not user specific, since packages are across users. Special app-ids (system,
     // shell, etc.) are handled.  Fails if the provider does not know about the
-    // app-id.
-    virtual ::android::error::Result<std::vector<std::string>> getPackagesForUid(
+    // app-id or if the provider has not been initialized.
+    virtual ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
             uid_t uid) const = 0;
     // True iff the provided package name runs under the app-id of uid.
     // Special app-ids (system, shell, etc.) are handled.
-    // Fails if the provider does not know about the app-id.
-    virtual ::android::error::Result<bool> validateUidPackagePair(
+    // Fails if the provider does not know about the app-id or if the provider has not been
+    // initialized.
+    virtual ::android::error::BinderResult<bool> validateUidPackagePair(
             uid_t uid, const std::string& packageName) const = 0;
 
     // True iff the uid holds the permission (user aware).
     // Fails with NO_INIT if cache hasn't been populated.
-    virtual ::android::error::Result<bool> checkPermission(PermissionEnum permission,
-                                                           uid_t uid) const = 0;
+    virtual ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+                                                                 uid_t uid) const = 0;
     virtual ~IPermissionProvider() = default;
 };
 }  // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/include/media/NativePermissionController.h b/services/audiopolicy/permission/include/media/NativePermissionController.h
index d464023..a81c7a2 100644
--- a/services/audiopolicy/permission/include/media/NativePermissionController.h
+++ b/services/audiopolicy/permission/include/media/NativePermissionController.h
@@ -24,6 +24,7 @@
 
 #include <android-base/thread_annotations.h>
 #include <com/android/media/permission/BnNativePermissionController.h>
+#include <error/BinderResult.h>
 
 namespace com::android::media::permission {
 
@@ -36,11 +37,12 @@
     Status populatePermissionState(PermissionEnum permission, const std::vector<int>& uids) final;
     // end binder methods
 
-    ::android::error::Result<std::vector<std::string>> getPackagesForUid(uid_t uid) const final;
-    ::android::error::Result<bool> validateUidPackagePair(
+    ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
+            uid_t uid) const final;
+    ::android::error::BinderResult<bool> validateUidPackagePair(
             uid_t uid, const std::string& packageName) const final;
-    ::android::error::Result<bool> checkPermission(PermissionEnum permission,
-                                                   uid_t uid) const final;
+    ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+                                                         uid_t uid) const final;
 
   private:
     mutable std::mutex m_;
diff --git a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
index 8d9da05..46f7d0a 100644
--- a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
+++ b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
@@ -17,22 +17,22 @@
 #pragma once
 
 #include <android/content/AttributionSourceState.h>
-#include <error/Result.h>
+#include <error/BinderResult.h>
 
 #include "IPermissionProvider.h"
 
 namespace com::android::media::permission {
 
 using ::android::content::AttributionSourceState;
-using ::android::error::Result;
 
 class ValidatedAttributionSourceState {
   public:
     /**
      * Validates an attribution source from within the context of a binder transaction.
-     * Overwrites the uid/pid and validates the packageName
+     * Overwrites the uid/pid and validates the packageName.
+     * Returns EX_SECURITY on package validation fail.
      */
-    static Result<ValidatedAttributionSourceState> createFromBinderContext(
+    static ::android::error::BinderResult<ValidatedAttributionSourceState> createFromBinderContext(
             AttributionSourceState attr, const IPermissionProvider& provider);
 
     /**
@@ -47,9 +47,10 @@
      * Create a ValidatedAttribubtionSourceState in cases where the uid/pid is trusted, but the
      * packages have not been validated. Proper use of the previous two methods should avoid the
      * necessity of this, but it is useful for migration purposes as well as testing this class.
+     * Returns EX_SECURITY on package validation fail.
      */
-    static Result<ValidatedAttributionSourceState> createFromTrustedUidNoPackage(
-            AttributionSourceState attr, const IPermissionProvider& provider);
+    static ::android::error::BinderResult<ValidatedAttributionSourceState>
+    createFromTrustedUidNoPackage(AttributionSourceState attr, const IPermissionProvider& provider);
 
     operator AttributionSourceState() const { return state_; }
 
diff --git a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
index 3f6b787..f2423c1 100644
--- a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
+++ b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
@@ -19,14 +19,22 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include <android-base/expected.h>
+#include <error/BinderStatusMatcher.h>
+#include <error/ExpectedMatchers.h>
 
-using ::android::base::unexpected;
-using ::android::binder::Status;
+using android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using android::binder::Status::EX_ILLEGAL_STATE;
+using android::error::BinderStatusMatcher;
+using android::error::IsErrorAnd;
+using android::error::IsOkAnd;
 using com::android::media::permission::NativePermissionController;
 using com::android::media::permission::PermissionEnum;
 using com::android::media::permission::UidPackageState;
 
+using ::testing::ElementsAre;
+using ::testing::IsFalse;
+using ::testing::IsTrue;
+
 class NativePermissionControllerTest : public ::testing::Test {
   protected:
     android::sp<NativePermissionController> holder_ =
@@ -40,50 +48,37 @@
     return out;
 }
 
-static std::vector<std::string> makeVector(const char* one) {
-    return {one};
-}
-
-static std::vector<std::string> makeVector(const char* one, const char* two) {
-    return {one, two};
-}
-
-#define UNWRAP_EQ(expr, desired_expr)                         \
-    do {                                                      \
-        auto tmp_ = (expr);                                   \
-        EXPECT_TRUE(tmp_.has_value());                        \
-        if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \
-    } while (0)
-
 // ---  Tests for non-populated ----
 TEST_F(NativePermissionControllerTest, getPackagesForUid_NotPopulated) {
     // Verify errors are returned
-    EXPECT_EQ(controller_.getPackagesForUid(10000), unexpected{android::NO_INIT});
-    EXPECT_EQ(controller_.getPackagesForUid(10001), unexpected{android::NO_INIT});
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+    EXPECT_THAT(controller_.getPackagesForUid(10001),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 
     // fixed uids should work
-    UNWRAP_EQ(controller_.getPackagesForUid(1000), makeVector("system"));
+    EXPECT_THAT(controller_.getPackagesForUid(1000), IsOkAnd(ElementsAre(std::string{"system"})));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_NotPopulated) {
     // Verify errors are returned
-    EXPECT_EQ(controller_.validateUidPackagePair(10000, "com.package"),
-              unexpected{android::NO_INIT});
+    EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.package"),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 
     // fixed uids should work
-    UNWRAP_EQ(controller_.validateUidPackagePair(1000, "system"), true);
+    EXPECT_THAT(controller_.validateUidPackagePair(1000, "system"), IsOkAnd(IsTrue()));
 }
+
 // ---  Tests for populatePackagesForUids ----
 TEST_F(NativePermissionControllerTest, populatePackages_EmptyInput) {
     std::vector<UidPackageState> input;
 
     // succeeds
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
     // Verify unknown uid behavior
-    const auto res1 = controller_.getPackagesForUid(10000);
-    ASSERT_FALSE(res1.has_value());
-    EXPECT_EQ(res1.error(), ::android::BAD_VALUE);
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
 }
 
 TEST_F(NativePermissionControllerTest, populatePackages_ValidInput) {
@@ -92,11 +87,11 @@
             createState(10001, {"com.example2.app1"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.getPackagesForUid(10000),
-              makeVector("com.example.app1", "com.example.app2"));
-    UNWRAP_EQ(controller_.getPackagesForUid(10001), makeVector("com.example2.app1"));
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+    EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
 }
 
 // --- Tests for updatePackagesForUid ---
@@ -107,14 +102,14 @@
     };
     UidPackageState newState = createState(12000, {"com.example.other"});
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
-    EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+    EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
 
     // Verify the results: only the updated package should be changed
-    UNWRAP_EQ(controller_.getPackagesForUid(10000),
-              makeVector("com.example.app1", "com.example.app2"));
-    UNWRAP_EQ(controller_.getPackagesForUid(10001), makeVector("com.example2.app1"));
-    UNWRAP_EQ(controller_.getPackagesForUid(12000), makeVector("com.example.other"));
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+    EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
+    EXPECT_THAT(controller_.getPackagesForUid(12000), IsOkAnd(ElementsAre("com.example.other")));
 }
 
 TEST_F(NativePermissionControllerTest, updatePackages_ExistingUid) {
@@ -123,14 +118,14 @@
             createState(10001, {"com.example2.app1"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
     // Update packages for existing uid
     UidPackageState newState = createState(10000, {"com.example.other", "com.example.new"});
-    EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+    EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
 
     // Verify update
-    UNWRAP_EQ(controller_.getPackagesForUid(10000),
-              makeVector("com.example.other", "com.example.new"));
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsOkAnd(ElementsAre("com.example.other", "com.example.new")));
 }
 
 TEST_F(NativePermissionControllerTest, updatePackages_EmptyRemovesEntry) {
@@ -138,15 +133,14 @@
             createState(10000, {"com.example.app1"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
     UidPackageState newState{};  // Empty package list
     newState.uid = 10000;
-    EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+    EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
     // getPackages for unknown UID should error out
-    const auto res = controller_.getPackagesForUid(10000);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::BAD_VALUE);
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_ValidPair) {
@@ -154,9 +148,9 @@
             createState(10000, {"com.example.app1", "com.example.app2"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.validateUidPackagePair(10000, "com.example.app1"), true);
+    EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.app1"), IsOkAnd(IsTrue()));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_InvalidPackage) {
@@ -164,9 +158,9 @@
             createState(10000, {"com.example.app1", "com.example.app2"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.validateUidPackagePair(10000, "com.example.other"), false);
+    EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.other"), IsOkAnd(IsFalse()));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_UnknownUid) {
@@ -174,45 +168,44 @@
             createState(10000, {"com.example.app1", "com.example.app2"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.validateUidPackagePair(12000, "any.package"), false);
+    EXPECT_THAT(controller_.validateUidPackagePair(12000, "any.package"), IsOkAnd(IsFalse()));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_InvalidPermission) {
-    EXPECT_EQ(controller_.populatePermissionState(PermissionEnum::ENUM_SIZE, {}).exceptionCode(),
-              Status::EX_ILLEGAL_ARGUMENT);
-    EXPECT_EQ(controller_
-                      .populatePermissionState(
-                              static_cast<PermissionEnum>(
-                                      static_cast<int>(PermissionEnum::ENUM_SIZE) + 1),
-                              {})
-                      .exceptionCode(),
-              Status::EX_ILLEGAL_ARGUMENT);
+    EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::ENUM_SIZE, {}),
+                BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
+    EXPECT_THAT(
+            controller_.populatePermissionState(
+                    static_cast<PermissionEnum>(static_cast<int>(PermissionEnum::ENUM_SIZE) + 1),
+                    {}),
+            BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_HoldsPermission) {
     // Unsorted
     std::vector<int> uids{3, 1, 2, 4, 5};
 
-    EXPECT_TRUE(
-            controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids).isOk());
+    EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+                BinderStatusMatcher::isOk());
 
-    EXPECT_TRUE(*controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3));
+    EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+                IsOkAnd(IsTrue()));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_DoesNotHoldPermission) {
     // Unsorted
     std::vector<int> uids{3, 1, 2, 4, 5};
 
-    EXPECT_TRUE(
-            controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids).isOk());
+    EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+                BinderStatusMatcher::isOk());
 
-    EXPECT_FALSE(*controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 6));
+    EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 6),
+                IsOkAnd(IsFalse()));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_NotInitialized) {
-    const auto res = controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::NO_INIT);
+    EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 }
diff --git a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
index efc318b..0dd8814 100644
--- a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
+++ b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
@@ -20,24 +20,35 @@
 #include <gtest/gtest.h>
 
 #include <android-base/expected.h>
+#include <error/ExpectedMatchers.h>
 #include <media/IPermissionProvider.h>
+#include "error/BinderStatusMatcher.h"
 
 using ::android::base::unexpected;
 using ::android::binder::Status;
+using ::android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using ::android::binder::Status::EX_ILLEGAL_STATE;
+using ::android::binder::Status::EX_SECURITY;
 using ::android::content::AttributionSourceState;
-using ::android::error::Result;
+using ::android::error::BinderResult;
+using ::android::error::BinderStatusMatcher;
+using ::android::error::IsErrorAnd;
+using ::android::error::IsOkAnd;
 using ::com::android::media::permission::IPermissionProvider;
 using ::com::android::media::permission::PermissionEnum;
 using ::com::android::media::permission::ValidatedAttributionSourceState;
+
+using ::testing::Eq;
 using ::testing::Return;
 
 class MockPermissionProvider : public IPermissionProvider {
   public:
-    MOCK_METHOD(Result<std::vector<std::string>>, getPackagesForUid, (uid_t uid),
+    MOCK_METHOD(BinderResult<std::vector<std::string>>, getPackagesForUid, (uid_t uid),
                 (override, const));
-    MOCK_METHOD(Result<bool>, validateUidPackagePair, (uid_t uid, const std::string&),
+    MOCK_METHOD(BinderResult<bool>, validateUidPackagePair, (uid_t uid, const std::string&),
                 (override, const));
-    MOCK_METHOD(Result<bool>, checkPermission, (PermissionEnum perm, uid_t), (override, const));
+    MOCK_METHOD(BinderResult<bool>, checkPermission, (PermissionEnum perm, uid_t),
+                (override, const));
 };
 
 class ValidatedAttributionSourceStateTest : public ::testing::Test {
@@ -47,21 +58,14 @@
     const std::vector<std::string> mPackageList{"com.package1", "com.package2"};
 };
 
-#define UNWRAP_EQ(expr, desired_expr)                         \
-    do {                                                      \
-        auto tmp_ = (expr);                                   \
-        EXPECT_TRUE(tmp_.has_value());                        \
-        if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \
-    } while (0)
-
 TEST_F(ValidatedAttributionSourceStateTest, providedPackageValid) {
     const std::string package = "com.package1";
     EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(true));
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = package;
-    UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
-              attr);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsOkAnd(Eq(attr)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, providedPackageInvalid) {
@@ -70,10 +74,8 @@
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = package;
-    const auto res =
-            ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::PERMISSION_DENIED);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_SECURITY)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenMissingPackage) {
@@ -83,8 +85,8 @@
     AttributionSourceState expectedAttr;
     expectedAttr.uid = mUid;
     expectedAttr.packageName = "com.package1";
-    UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
-              expectedAttr);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsOkAnd(Eq(expectedAttr)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenEmptyPackage) {
@@ -95,33 +97,29 @@
     AttributionSourceState expectedAttr;
     expectedAttr.uid = mUid;
     expectedAttr.packageName = "com.package1";
-    UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
-              expectedAttr);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsOkAnd(Eq(expectedAttr)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, controllerNotInitialized) {
     EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
-            .WillOnce(Return(unexpected{::android::NO_INIT}));
+            .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_STATE)}));
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = std::string{};
     AttributionSourceState expectedAttr;
     expectedAttr.uid = mUid;
     expectedAttr.packageName = "com.package1";
-    const auto res =
-            ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::NO_INIT);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, uidNotFound) {
     EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
-            .WillOnce(Return(unexpected{::android::BAD_VALUE}));
+            .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_ARGUMENT)}));
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = std::string{};
-    const auto res =
-            ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::BAD_VALUE);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
 }
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 8ba2814..768cd07 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -1576,19 +1576,6 @@
     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,
@@ -1607,27 +1594,14 @@
     std::unique_ptr<audio_port_v7[]> ports(new audio_port_v7[num_ports]);
     unsigned int generation;
 
-    const AttributionSourceState attributionSource = getCallingAttributionSource();
+    audio_utils::lock_guard _l(mMutex);
+    if (mAudioPolicyManager == NULL) {
+        return binderStatusFromStatusT(NO_INIT);
+    }
     AutoCallerClear acc;
-    {
-        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(
+            mAudioPolicyManager->listAudioPorts(role, type, &num_ports, ports.get(), &generation)));
+    numPortsReq = std::min(numPortsReq, num_ports);
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
             convertRange(ports.get(), ports.get() + numPortsReq, std::back_inserter(*portsAidl),
                          legacy2aidl_audio_port_v7_AudioPortFw)));
@@ -1650,24 +1624,12 @@
 Status AudioPolicyService::getAudioPort(int portId,
                                         media::AudioPortFw* _aidl_return) {
     audio_port_v7 port{ .id = portId };
-
-    const AttributionSourceState attributionSource = getCallingAttributionSource();
+    audio_utils::lock_guard _l(mMutex);
+    if (mAudioPolicyManager == NULL) {
+        return binderStatusFromStatusT(NO_INIT);
+    }
     AutoCallerClear acc;
-
-    {
-        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);
-    }
-
+    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
     *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_port_v7_AudioPortFw(port));
     return Status::ok();
 }
@@ -1725,32 +1687,14 @@
     std::unique_ptr<audio_patch[]> patches(new audio_patch[num_patches]);
     unsigned int generation;
 
-    const AttributionSourceState attributionSource = getCallingAttributionSource();
+    audio_utils::lock_guard _l(mMutex);
+    if (mAudioPolicyManager == NULL) {
+        return binderStatusFromStatusT(NO_INIT);
+    }
     AutoCallerClear acc;
-
-    {
-        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(
+            mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
+    numPatchesReq = std::min(numPatchesReq, num_patches);
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
             convertRange(patches.get(), patches.get() + numPatchesReq,
                          std::back_inserter(*patchesAidl), legacy2aidl_audio_patch_AudioPatchFw)));
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index dc61115..4006489 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -12,6 +12,7 @@
     name: "audiopolicy_tests",
 
     defaults: [
+        "aconfig_lib_cc_shared_link.defaults",
         "latest_android_media_audio_common_types_cpp_static",
     ],
 
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index ba0a1eb..d1dd1e9 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -72,6 +72,7 @@
         *input = mNextIoHandle++;
         mOpenedInputs.insert(*input);
         ALOGD("%s: opened input %d", __func__, *input);
+        mOpenInputCallsCount++;
         return NO_ERROR;
     }
 
@@ -86,6 +87,7 @@
             return BAD_VALUE;
         }
         ALOGD("%s: closed input %d", __func__, input);
+        mCloseInputCallsCount++;
         return NO_ERROR;
     }
 
@@ -260,6 +262,18 @@
         auto it = mTracksInternalMute.find(portId);
         return it == mTracksInternalMute.end() ? false : it->second;
     }
+    void resetInputApiCallsCounters() {
+        mOpenInputCallsCount = 0;
+        mCloseInputCallsCount = 0;
+    }
+
+    size_t getCloseInputCallsCount() const {
+        return mCloseInputCallsCount;
+    }
+
+    size_t getOpenInputCallsCount() const {
+        return mOpenInputCallsCount;
+    }
 
 private:
     audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
@@ -275,6 +289,8 @@
     std::set<audio_channel_mask_t> mSupportedChannelMasks;
     std::map<audio_port_handle_t, bool> mTracksInternalMute;
     std::set<audio_io_handle_t> mOpenedInputs;
+    size_t mOpenInputCallsCount = 0;
+    size_t mCloseInputCallsCount = 0;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 4c98687..07aad0c 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -3830,3 +3830,92 @@
         testing::Values(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
                         AUDIO_USAGE_ALARM)
 );
+
+class AudioPolicyManagerInputPreemptionTest : public AudioPolicyManagerTestWithConfigurationFile {
+};
+
+TEST_F_WITH_FLAGS(
+        AudioPolicyManagerInputPreemptionTest,
+        SameSessionReusesInput,
+        REQUIRES_FLAGS_ENABLED(
+                ACONFIG_FLAG(com::android::media::audioserver, fix_input_sharing_logic))
+) {
+    mClient->resetInputApiCallsCounters();
+
+    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+    attr.source = AUDIO_SOURCE_MIC;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    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));
+
+    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));
+
+    EXPECT_EQ(1, mClient->getOpenInputCallsCount());
+    EXPECT_EQ(0, mClient->getCloseInputCallsCount());
+    EXPECT_EQ(input1, input2);
+}
+
+TEST_F_WITH_FLAGS(
+        AudioPolicyManagerInputPreemptionTest,
+        LesserPriorityReusesInput,
+        REQUIRES_FLAGS_ENABLED(
+                ACONFIG_FLAG(com::android::media::audioserver, fix_input_sharing_logic))
+) {
+    mClient->resetInputApiCallsCounters();
+
+    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+    attr.source = AUDIO_SOURCE_MIC;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    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));
+
+    EXPECT_EQ(1, mClient->getOpenInputCallsCount());
+
+    audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
+    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));
+
+    EXPECT_EQ(1, mClient->getOpenInputCallsCount());
+    EXPECT_EQ(0, mClient->getCloseInputCallsCount());
+    EXPECT_EQ(input1, input2);
+}
+
+TEST_F_WITH_FLAGS(
+        AudioPolicyManagerInputPreemptionTest,
+        HigherPriorityPreemptsInput,
+        REQUIRES_FLAGS_ENABLED(
+                ACONFIG_FLAG(com::android::media::audioserver, fix_input_sharing_logic))
+) {
+    mClient->resetInputApiCallsCounters();
+
+    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+    attr.source = AUDIO_SOURCE_MIC;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    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));
+
+    EXPECT_EQ(1, mClient->getOpenInputCallsCount());
+
+    audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
+    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));
+
+    EXPECT_EQ(2, mClient->getOpenInputCallsCount());
+    EXPECT_EQ(1, mClient->getCloseInputCallsCount());
+    EXPECT_NE(input1, input2);
+}
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index bbc19fa..67e99f2 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -30,7 +30,7 @@
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                 </mixPort>
-                <mixPort name="primary input" role="sink">
+                <mixPort name="primary input" role="sink"  maxActiveCount="1" maxOpenCount="1">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                              samplingRates="48000"
                              channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c154bc0..b8f781c 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -927,8 +927,13 @@
                                 SessionConfigurationUtils::targetPerfClassPrimaryCamera(
                                         mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
 
-    return isSessionConfigurationWithParametersSupportedUnsafe(cameraId, sessionConfiguration,
-                                                               overrideForPerfClass, supported);
+    auto ret = isSessionConfigurationWithParametersSupportedUnsafe(cameraId,
+            sessionConfiguration, overrideForPerfClass, supported);
+    if (flags::analytics_24q3()) {
+        mCameraServiceProxyWrapper->logFeatureCombinationQuery(cameraId,
+                getCallingUid(), sessionConfiguration, ret);
+    }
+    return ret;
 }
 
 Status CameraService::isSessionConfigurationWithParametersSupportedUnsafe(
@@ -1072,7 +1077,12 @@
             }
     }
 
-    return filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
+    Status res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
+    if (flags::analytics_24q3()) {
+        mCameraServiceProxyWrapper->logSessionCharacteristicsQuery(cameraId,
+                getCallingUid(), sessionConfiguration, res);
+    }
+    return res;
 }
 
 Status CameraService::filterSensitiveMetadataIfNeeded(
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index c710671..78a1fc8 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -85,7 +85,7 @@
         "camera_service_fuzzer.cpp",
     ],
     defaults: [
-        "camera_service_fuzzer_defaults"
+        "camera_service_fuzzer_defaults",
     ],
 }
 
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index 55e2c9d..8bb5ffa 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -30,7 +30,7 @@
         "ExifUtilsTest.cpp",
         "NV12Compressor.cpp",
         "RotateAndCropMapperTest.cpp",
-	"SessionStatsBuilderTest.cpp",
+        "SessionStatsBuilderTest.cpp",
         "ZoomRatioTest.cpp",
     ],
 
@@ -76,7 +76,7 @@
 
     defaults: [
         "libcameraservice_deps",
-	"cameraservice_test_hostsupported"
+        "cameraservice_test_hostsupported",
     ],
 
     // Only include libs that can't be run host-side here
@@ -118,13 +118,13 @@
     name: "cameraservice_test_host",
 
     defaults: [
-        "cameraservice_test_hostsupported"
+        "cameraservice_test_hostsupported",
     ],
 
     include_dirs: [
         "frameworks/av/camera/include",
         "frameworks/av/camera/include/camera",
-        "frameworks/native/libs/binder/include_activitymanager"
+        "frameworks/native/libs/binder/include_activitymanager",
     ],
 
     // Only include libs that can't be run device-side here
diff --git a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
index cf86a05..feb5540 100644
--- a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
@@ -146,6 +146,11 @@
         return mCameraServiceProxy->notifyCameraState(cameraSessionStats);
     }
 
+    virtual binder::Status notifyFeatureCombinationStats(
+            const hardware::CameraFeatureCombinationStats& featureCombStats) override {
+        return mCameraServiceProxy->notifyFeatureCombinationStats(featureCombStats);
+    }
+
     virtual binder::Status isCameraDisabled(int userId, bool *ret) override {
         if (mOverrideCameraDisabled) {
             *ret = mCameraDisabled;
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index 4afae9b..d5e3790 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -18,19 +18,25 @@
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
+#include <gui/Surface.h>
 #include <inttypes.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
 #include <camera/StringUtils.h>
 #include <binder/IServiceManager.h>
+#include <system/window.h>
+
+#include "aidl/android/hardware/graphics/common/Dataspace.h"
 
 #include "CameraServiceProxyWrapper.h"
 
 namespace android {
 
 using hardware::CameraExtensionSessionStats;
+using hardware::CameraFeatureCombinationStats;
 using hardware::CameraSessionStats;
 using hardware::ICameraServiceProxy;
+using hardware::camera2::params::SessionConfiguration;
 
 namespace {
 // Sentinel value to be returned when extension session with a stale or invalid key is reported.
@@ -215,6 +221,105 @@
     proxyBinder->pingForUserUpdate();
 }
 
+int64_t CameraServiceProxyWrapper::encodeSessionConfiguration(
+        const SessionConfiguration& sessionConfig) {
+    int64_t features = CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
+    const static int32_t WIDTH_4K = 3840;
+    const static int32_t HEIGHT_4K = 2160;
+
+    // Check session parameters
+    if (sessionConfig.hasSessionParameters()) {
+        const auto& parameters = sessionConfig.getSessionParameters();
+
+        camera_metadata_ro_entry fpsEntry = parameters.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+        if (fpsEntry.count == 2 && fpsEntry.data.i32[1] == 60) {
+            features |= CameraFeatureCombinationStats::CAMERA_FEATURE_60_FPS;
+        }
+
+        camera_metadata_ro_entry stabEntry =
+                parameters.find(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE);
+        if (stabEntry.count == 1 && stabEntry.data.u8[0] ==
+                ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
+            features |= CameraFeatureCombinationStats::CAMERA_FEATURE_STABILIZATION;
+        }
+    }
+
+    // Check output configurations
+    const auto& outputConfigs = sessionConfig.getOutputConfigurations();
+    for (const auto& config : outputConfigs) {
+        int format = config.getFormat();
+        int dataSpace = config.getDataspace();
+        int64_t dynamicRangeProfile = config.getDynamicRangeProfile();
+
+        // Check JPEG and JPEG_R features
+        if (format == HAL_PIXEL_FORMAT_BLOB) {
+            if (dataSpace == HAL_DATASPACE_V0_JFIF) {
+                features |= CameraFeatureCombinationStats::CAMERA_FEATURE_JPEG;
+            } else if (dataSpace == static_cast<android_dataspace_t>(
+                    aidl::android::hardware::graphics::common::Dataspace::JPEG_R)) {
+                features |= CameraFeatureCombinationStats::CAMERA_FEATURE_JPEG_R;
+            }
+        } else {
+            if (dynamicRangeProfile == HAL_DATASPACE_BT2020_HLG) {
+                features |= CameraFeatureCombinationStats::CAMERA_FEATURE_HLG10;
+            }
+
+            // Check 4K
+            const auto& gbps = config.getGraphicBufferProducers();
+            int32_t width = 0, height = 0;
+            if (gbps.size() > 0) {
+                sp<Surface> surface = new Surface(gbps[0], /*useAsync*/false);
+                ANativeWindow *anw = surface.get();
+
+                width = ANativeWindow_getWidth(anw);
+                if (width < 0) {
+                    ALOGE("%s: Failed to query Surface width: %s (%d)",
+                            __FUNCTION__, strerror(-width), width);
+                    return CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
+                }
+                height = ANativeWindow_getHeight(anw);
+                if (height < 0) {
+                    ALOGE("%s: Failed to query Surface height: %s (%d)",
+                            __FUNCTION__, strerror(-height), height);
+                    return CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
+                }
+            } else {
+                width = config.getWidth();
+                height = config.getHeight();
+            }
+            if (width == WIDTH_4K && height == HEIGHT_4K) {
+                features |= CameraFeatureCombinationStats::CAMERA_FEATURE_4K;
+            }
+        }
+    }
+    return features;
+}
+
+// Note: The `ret` parameter is the return value of the
+// `isSessionConfigurationWithParametersSupporteed` binder call from the app.
+void CameraServiceProxyWrapper::logFeatureCombinationInternal(
+        const std::string &cameraId, int clientUid,
+        const SessionConfiguration& sessionConfiguration, binder::Status ret,
+        int type) {
+    sp<hardware::ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+    if (proxyBinder == nullptr) return;
+
+    int64_t featureCombination = encodeSessionConfiguration(sessionConfiguration);
+    int queryStatus = ret.isOk() ? OK : ret.serviceSpecificErrorCode();
+    CameraFeatureCombinationStats stats;
+    stats.mCameraId = cameraId;
+    stats.mUid = clientUid;
+    stats.mFeatureCombination = featureCombination;
+    stats.mQueryType = type;
+    stats.mStatus = queryStatus;
+
+    auto status = proxyBinder->notifyFeatureCombinationStats(stats);
+    if (!status.isOk()) {
+        ALOGE("%s: Failed to notify feature combination stats: %s", __FUNCTION__,
+                status.exceptionMessage().c_str());
+    }
+}
+
 int CameraServiceProxyWrapper::getRotateAndCropOverride(const std::string &packageName,
         int lensFacing, int userId) {
     sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index b6a967f..ad8b1cd 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
 #define ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
 
+#include <android/hardware/CameraFeatureCombinationStats.h>
 #include <android/hardware/ICameraServiceProxy.h>
 
 #include <utils/Mutex.h>
@@ -26,7 +27,7 @@
 #include <string>
 
 #include <camera/CameraSessionStats.h>
-
+#include <camera/camera2/SessionConfiguration.h>
 namespace android {
 
 class CameraServiceProxyWrapper {
@@ -86,6 +87,11 @@
     // ID generated for the open event associated with them.
     static int64_t generateLogId(std::random_device& randomDevice);
 
+    static int64_t encodeSessionConfiguration(const SessionConfiguration& sessionConfig);
+
+    void logFeatureCombinationInternal(const std::string &cameraId, int clientUid,
+            const hardware::camera2::params::SessionConfiguration& sessionConfiguration,
+            binder::Status ret, int type);
 public:
     CameraServiceProxyWrapper(sp<hardware::ICameraServiceProxy> serviceProxy = nullptr) :
             mCameraServiceProxy(serviceProxy)
@@ -115,6 +121,20 @@
             bool usedZoomOverride, std::pair<int32_t, int32_t> mostRequestedFpsRange,
             const std::vector<hardware::CameraStreamStats>& streamStats);
 
+    // Feature combination query
+    void logFeatureCombinationQuery(const std::string &id, int clientUid,
+            const hardware::camera2::params::SessionConfiguration& sessionConfiguration,
+            binder::Status ret) {
+        logFeatureCombinationInternal(id, clientUid, sessionConfiguration, ret,
+                (int)hardware::CameraFeatureCombinationStats::QueryType::QUERY_FEATURE_COMBINATION);
+    }
+    void logSessionCharacteristicsQuery(const std::string &id, int clientUid,
+            const hardware::camera2::params::SessionConfiguration& sessionConfiguration,
+            binder::Status ret) {
+        logFeatureCombinationInternal(id, clientUid, sessionConfiguration, ret, (int)
+                hardware::CameraFeatureCombinationStats::QueryType::QUERY_SESSION_CHARACTERISTICS);
+    }
+
     // Ping camera service proxy for user update
     void pingCameraServiceProxy();
 
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 9a5bd1e..cd17517 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -24,6 +24,7 @@
 #include <memory>
 #include <mutex>
 #include <thread>
+#include <utility>
 #include <vector>
 
 #include "Exif.h"
@@ -78,6 +79,15 @@
 
 namespace {
 
+// helper type for the visitor
+template <class... Ts>
+struct overloaded : Ts... {
+  using Ts::operator()...;
+};
+// explicit deduction guide (not needed as of C++20)
+template <class... Ts>
+overloaded(Ts...) -> overloaded<Ts...>;
+
 using namespace std::chrono_literals;
 
 static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
@@ -89,6 +99,8 @@
 
 static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024;  // 32 KiB
 
+static constexpr UpdateTextureTask kUpdateTextureTask;
+
 CameraMetadata createCaptureResultMetadata(
     const std::chrono::nanoseconds timestamp,
     const RequestSettings& requestSettings,
@@ -287,6 +299,21 @@
       static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
 }
 
+class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
+ public:
+  FrameAvailableListenerProxy(std::function<void()> callback)
+      : mOnFrameAvailableCallback(callback) {
+  }
+
+  virtual void onFrameAvailable(const BufferItem&) override {
+    ALOGV("%s: onFrameAvailable", __func__);
+    mOnFrameAvailableCallback();
+  }
+
+ private:
+  std::function<void()> mOnFrameAvailableCallback;
+};
+
 }  // namespace
 
 CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -345,9 +372,25 @@
   return mRequestSettings;
 }
 
+void VirtualCameraRenderThread::requestTextureUpdate() {
+  std::lock_guard<std::mutex> lock(mLock);
+  // If queue is not empty, we don't need to set the mTextureUpdateRequested
+  // flag, since the texture will be updated during ProcessCaptureRequestTask
+  // processing anyway.
+  if (mQueue.empty()) {
+    mTextureUpdateRequested = true;
+    mCondVar.notify_one();
+  }
+}
+
 void VirtualCameraRenderThread::enqueueTask(
     std::unique_ptr<ProcessCaptureRequestTask> task) {
   std::lock_guard<std::mutex> lock(mLock);
+  // When enqueving process capture request task, clear the
+  // mTextureUpdateRequested flag. If this flag is set, the texture was not yet
+  // updated and it will be updated when processing ProcessCaptureRequestTask
+  // anyway.
+  mTextureUpdateRequested = false;
   mQueue.emplace_back(std::move(task));
   mCondVar.notify_one();
 }
@@ -377,8 +420,7 @@
   return mInputSurfaceFuture.get();
 }
 
-std::unique_ptr<ProcessCaptureRequestTask>
-VirtualCameraRenderThread::dequeueTask() {
+RenderThreadTask VirtualCameraRenderThread::dequeueTask() {
   std::unique_lock<std::mutex> lock(mLock);
   // Clang's thread safety analysis doesn't perform alias analysis,
   // so it doesn't support moveable std::unique_lock.
@@ -389,12 +431,20 @@
   ScopedLockAssertion lockAssertion(mLock);
 
   mCondVar.wait(lock, [this]() REQUIRES(mLock) {
-    return mPendingExit || !mQueue.empty();
+    return mPendingExit || mTextureUpdateRequested || !mQueue.empty();
   });
   if (mPendingExit) {
-    return nullptr;
+    // Render thread task with null task signals render thread to terminate.
+    return RenderThreadTask(nullptr);
   }
-  std::unique_ptr<ProcessCaptureRequestTask> task = std::move(mQueue.front());
+  if (mTextureUpdateRequested) {
+    // If mTextureUpdateRequested, it's guaranteed the queue is empty, return
+    // kUpdateTextureTask to signal we want render thread to update the texture
+    // (consume buffer from the queue).
+    mTextureUpdateRequested = false;
+    return RenderThreadTask(kUpdateTextureTask);
+  }
+  RenderThreadTask task(std::move(mQueue.front()));
   mQueue.pop_front();
   return task;
 }
@@ -409,11 +459,23 @@
       EglTextureProgram::TextureFormat::RGBA);
   mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
       mInputSurfaceSize.width, mInputSurfaceSize.height);
+  sp<FrameAvailableListenerProxy> frameAvailableListener =
+      sp<FrameAvailableListenerProxy>::make(
+          [this]() { requestTextureUpdate(); });
+  mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);
 
   mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
 
-  while (std::unique_ptr<ProcessCaptureRequestTask> task = dequeueTask()) {
-    processCaptureRequest(*task);
+  while (RenderThreadTask task = dequeueTask()) {
+    std::visit(
+        overloaded{[this](const std::unique_ptr<ProcessCaptureRequestTask>& t) {
+                     processTask(*t);
+                   },
+                   [this](const UpdateTextureTask&) {
+                     ALOGV("Idle update of the texture");
+                     mEglSurfaceTexture->updateTexture();
+                   }},
+        task);
   }
 
   // Destroy EGL utilities still on the render thread.
@@ -425,7 +487,7 @@
   ALOGV("Render thread exiting");
 }
 
-void VirtualCameraRenderThread::processCaptureRequest(
+void VirtualCameraRenderThread::processTask(
     const ProcessCaptureRequestTask& request) {
   std::chrono::nanoseconds timestamp =
       std::chrono::duration_cast<std::chrono::nanoseconds>(
@@ -688,7 +750,7 @@
     return status;
   }
 
-  PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
+  PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
                              fence);
   if (planesLock.getStatus() != OK) {
     return cameraStatus(Status::INTERNAL_ERROR);
@@ -771,8 +833,8 @@
 
   Rect viewportRect =
       viewport.value_or(Rect(framebuffer.getWidth(), framebuffer.getHeight()));
-  glViewport(viewportRect.leftTop().x, viewportRect.leftTop().y,
-             viewportRect.getWidth(), viewportRect.getHeight());
+  glViewport(viewportRect.left, viewportRect.top, viewportRect.getWidth(),
+             viewportRect.getHeight());
 
   sp<GraphicBuffer> textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
   if (textureBuffer == nullptr) {
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index b23c30c..5a5966b 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -23,6 +23,7 @@
 #include <future>
 #include <memory>
 #include <thread>
+#include <variant>
 #include <vector>
 
 #include "VirtualCameraDevice.h"
@@ -34,7 +35,6 @@
 #include "util/EglFramebuffer.h"
 #include "util/EglProgram.h"
 #include "util/EglSurfaceTexture.h"
-#include "util/MetadataUtil.h"
 #include "util/Util.h"
 
 namespace android {
@@ -94,6 +94,24 @@
   const RequestSettings mRequestSettings;
 };
 
+struct UpdateTextureTask {};
+
+struct RenderThreadTask
+    : public std::variant<std::unique_ptr<ProcessCaptureRequestTask>,
+                          UpdateTextureTask> {
+  // Allow implicit conversion to bool.
+  //
+  // Returns false, if the RenderThreadTask consist of null
+  // ProcessCaptureRequestTask, which signals that the thread should terminate.
+  operator bool() const {
+    const bool isExitSignal =
+        std::holds_alternative<std::unique_ptr<ProcessCaptureRequestTask>>(
+            *this) &&
+        std::get<std::unique_ptr<ProcessCaptureRequestTask>>(*this) == nullptr;
+    return !isExitSignal;
+  }
+};
+
 // Wraps dedicated rendering thread and rendering business with corresponding
 // input surface.
 class VirtualCameraRenderThread {
@@ -120,6 +138,12 @@
   // Stop rendering thread.
   void stop();
 
+  // Send request to render thread to update the texture.
+  // Currently queued buffers in the input surface will be consumed and the most
+  // recent buffer in the input surface will be attached to the texture), all
+  // other buffers will be returned to the buffer queue.
+  void requestTextureUpdate() EXCLUDES(mLock);
+
   // Equeue capture task for processing on render thread.
   void enqueueTask(std::unique_ptr<ProcessCaptureRequestTask> task)
       EXCLUDES(mLock);
@@ -131,13 +155,13 @@
   sp<Surface> getInputSurface();
 
  private:
-  std::unique_ptr<ProcessCaptureRequestTask> dequeueTask() EXCLUDES(mLock);
+  RenderThreadTask dequeueTask() EXCLUDES(mLock);
 
   // Rendering thread entry point.
   void threadLoop();
 
   // Process single capture request task (always called on render thread).
-  void processCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
+  void processTask(const ProcessCaptureRequestTask& captureRequestTask);
 
   // Flush single capture request task returning the error status immediately.
   void flushCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
@@ -192,6 +216,7 @@
   std::mutex mLock;
   std::deque<std::unique_ptr<ProcessCaptureRequestTask>> mQueue GUARDED_BY(mLock);
   std::condition_variable mCondVar;
+  volatile bool mTextureUpdateRequested GUARDED_BY(mLock);
   volatile bool mPendingExit GUARDED_BY(mLock);
 
   // Acquisition timestamp of last frame.
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 705af86..7466089 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -76,6 +76,8 @@
        --camera_id=(ID) - override numerical ID for test camera instance
        --lens_facing=(front|back|external) - specifies lens facing for test camera instance
        --input_fps=(fps) - specify input fps for test camera, valid values are from 1 to 1000
+       --sensor_orientation=(0|90|180|270) - Clockwise angle through which the output image 
+           needs to be rotated to be upright on the device screen in its native orientation
  * disable_test_camera
 )";
 constexpr char kCreateVirtualDevicePermission[] =
@@ -439,6 +441,31 @@
     }
   }
 
+  std::optional<SensorOrientation> sensorOrientation;
+  std::optional<int> sensorOrientationInt;
+  it = options.find("sensor_orientation");
+  if (it != options.end()) {
+    sensorOrientationInt = parseInt(it->second);
+    switch (sensorOrientationInt.value_or(0)) {
+      case 0:
+        sensorOrientation = SensorOrientation::ORIENTATION_0;
+        break;
+      case 90:
+        sensorOrientation = SensorOrientation::ORIENTATION_90;
+        break;
+      case 180:
+        sensorOrientation = SensorOrientation::ORIENTATION_180;
+        break;
+      case 270:
+        sensorOrientation = SensorOrientation::ORIENTATION_270;
+        break;
+      default:
+        dprintf(err, "Invalid sensor rotation: %s\n, must be 0, 90, 180 or 270.",
+                it->second.c_str());
+        return STATUS_BAD_VALUE;
+    }
+  }
+
   sp<BBinder> token = sp<BBinder>::make();
   mTestCameraToken.set(AIBinder_fromPlatformBinder(token));
 
@@ -449,6 +476,8 @@
                                                   Format::RGBA_8888,
                                                   .maxFps = kMaxFps});
   configuration.lensFacing = lensFacing.value_or(LensFacing::EXTERNAL);
+  configuration.sensorOrientation =
+      sensorOrientation.value_or(SensorOrientation::ORIENTATION_0);
   configuration.virtualCameraCallback =
       ndk::SharedRefBase::make<VirtualCameraTestInstance>(
           inputFps.value_or(kTestCameraDefaultInputFps));
diff --git a/services/camera/virtualcamera/VirtualCameraSessionContext.cc b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
index 284ad05..aab2d0d 100644
--- a/services/camera/virtualcamera/VirtualCameraSessionContext.cc
+++ b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
@@ -129,7 +129,8 @@
           streamId);
     return std::optional<Stream>();
   }
-  return {it->second->getStreamConfig()};
+  VirtualCameraStream& stream = *it->second;
+  return {stream.getStreamConfig()};
 }
 
 std::shared_ptr<AHardwareBuffer> VirtualCameraSessionContext::fetchHardwareBuffer(
@@ -141,7 +142,8 @@
           streamId);
     return nullptr;
   }
-  return it->second->getHardwareBuffer(bufferId);
+  VirtualCameraStream& stream = *it->second;
+  return stream.getHardwareBuffer(bufferId);
 }
 
 std::shared_ptr<EglFrameBuffer>
@@ -154,7 +156,8 @@
           streamId);
     return nullptr;
   }
-  return it->second->getEglFrameBuffer(eglDisplay, bufferId);
+  VirtualCameraStream& stream = *it->second;
+  return stream.getEglFrameBuffer(eglDisplay, bufferId);
 }
 
 std::set<int> VirtualCameraSessionContext::getStreamIds() const {
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index 752d390..719f64d 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -19,6 +19,7 @@
 #include <cstdio>
 #include <iterator>
 #include <memory>
+#include <optional>
 #include <regex>
 
 #include "VirtualCameraService.h"
@@ -191,6 +192,16 @@
     return getLensFacing(metadata);
   }
 
+  std::optional<int32_t> getCameraSensorOrienation(const std::string& id) {
+    std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->getCamera(id);
+    if (camera == nullptr) {
+      return std::nullopt;
+    }
+    CameraMetadata metadata;
+    camera->getCameraCharacteristics(&metadata);
+    return getSensorOrientation(metadata);
+  }
+
  protected:
   std::shared_ptr<VirtualCameraService> mCameraService;
   std::shared_ptr<VirtualCameraProvider> mCameraProvider;
@@ -506,6 +517,24 @@
               Eq(STATUS_BAD_VALUE));
 }
 
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientation90) {
+  EXPECT_THAT(
+      execute_shell_command("enable_test_camera --sensor_orientation=90"),
+      Eq(NO_ERROR));
+
+  std::vector<std::string> cameraIds = getCameraIds();
+  ASSERT_THAT(cameraIds, SizeIs(1));
+  EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(90)));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientationNoArgs) {
+  EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR));
+
+  std::vector<std::string> cameraIds = getCameraIds();
+  ASSERT_THAT(cameraIds, SizeIs(1));
+  EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(0)));
+}
+
 }  // namespace
 }  // namespace virtualcamera
 }  // namespace companion
diff --git a/services/camera/virtualcamera/util/EglDisplayContext.cc b/services/camera/virtualcamera/util/EglDisplayContext.cc
index 166ac75..70da25b 100644
--- a/services/camera/virtualcamera/util/EglDisplayContext.cc
+++ b/services/camera/virtualcamera/util/EglDisplayContext.cc
@@ -93,16 +93,16 @@
 }
 
 EglDisplayContext::~EglDisplayContext() {
+  eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   if (mEglSurface != EGL_NO_SURFACE) {
     eglDestroySurface(mEglDisplay, mEglSurface);
   }
-  if (mEglDisplay != EGL_NO_DISPLAY) {
-    eglTerminate(mEglDisplay);
-  }
   if (mEglContext != EGL_NO_CONTEXT) {
     eglDestroyContext(mEglDisplay, mEglContext);
   }
-  eglReleaseThread();
+  if (mEglDisplay != EGL_NO_DISPLAY) {
+    eglTerminate(mEglDisplay);
+  }
 }
 
 EGLDisplay EglDisplayContext::getEglDisplay() const {
diff --git a/services/camera/virtualcamera/util/EglProgram.cc b/services/camera/virtualcamera/util/EglProgram.cc
index 9c97118..28f04cf 100644
--- a/services/camera/virtualcamera/util/EglProgram.cc
+++ b/services/camera/virtualcamera/util/EglProgram.cc
@@ -229,6 +229,15 @@
                         kTextureCoords.size(), kTextureCoords.data());
 }
 
+EglTestPatternProgram::~EglTestPatternProgram() {
+  if (mPositionHandle != -1) {
+    glDisableVertexAttribArray(mPositionHandle);
+  }
+  if (mTextureCoordHandle != -1) {
+    glDisableVertexAttribArray(mTextureCoordHandle);
+  }
+}
+
 bool EglTestPatternProgram::draw(const std::chrono::nanoseconds timestamp) {
   // Load compiled shader.
   glUseProgram(mProgram);
diff --git a/services/camera/virtualcamera/util/EglProgram.h b/services/camera/virtualcamera/util/EglProgram.h
index a88308d..cf93157 100644
--- a/services/camera/virtualcamera/util/EglProgram.h
+++ b/services/camera/virtualcamera/util/EglProgram.h
@@ -46,6 +46,7 @@
 class EglTestPatternProgram : public EglProgram {
  public:
   EglTestPatternProgram();
+  virtual ~EglTestPatternProgram();
 
   bool draw(std::chrono::nanoseconds timestamp);
 
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 7de5020..c81d36d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -64,6 +64,11 @@
   return mGlConsumer->getCurrentBuffer();
 }
 
+void EglSurfaceTexture::setFrameAvailableListener(
+    const wp<ConsumerBase::FrameAvailableListener>& listener) {
+  mGlConsumer->setFrameAvailableListener(listener);
+}
+
 bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
   return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
                                     static_cast<nsecs_t>(timeout.count()));
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index b9c5126..ac3cf7d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -21,6 +21,7 @@
 #include <cstdint>
 
 #include "GLES/gl.h"
+#include "gui/ConsumerBase.h"
 #include "gui/Surface.h"
 #include "utils/RefBase.h"
 
@@ -58,6 +59,9 @@
   // Returns false on timeout, true if new frame was received before timeout.
   bool waitForNextFrame(std::chrono::nanoseconds timeout);
 
+  void setFrameAvailableListener(
+      const wp<ConsumerBase::FrameAvailableListener>& listener);
+
   // Update the texture with the most recent submitted buffer.
   // Most be called on thread with EGL context.
   //
diff --git a/services/camera/virtualcamera/util/MetadataUtil.cc b/services/camera/virtualcamera/util/MetadataUtil.cc
index 31a8776..4889830 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.cc
+++ b/services/camera/virtualcamera/util/MetadataUtil.cc
@@ -961,6 +961,20 @@
   return static_cast<int32_t>(entry.data.i32[0]);
 }
 
+std::optional<int32_t> getSensorOrientation(
+    const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+  auto metadata =
+      reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+  camera_metadata_ro_entry_t entry;
+  if (find_camera_metadata_ro_entry(metadata, ANDROID_SENSOR_ORIENTATION,
+                                    &entry) != OK) {
+    return std::nullopt;
+  }
+
+  return static_cast<int32_t>(entry.data.i32[0]);
+}
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.h b/services/camera/virtualcamera/util/MetadataUtil.h
index ca6f332..22d3657 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.h
+++ b/services/camera/virtualcamera/util/MetadataUtil.h
@@ -488,6 +488,11 @@
 std::optional<int32_t> getDeviceId(
     const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
 
+// Return the value of ANDROID_SENSOR_ORIENTATION or nullopt if the key is not
+// present (which is equivalent to a orientation of 0).
+std::optional<int32_t> getSensorOrientation(
+    const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp b/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp
index d329e54..2b31de7 100644
--- a/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp
+++ b/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp
@@ -22,6 +22,7 @@
 using ::android::MediaExtractorService;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    signal(SIGPIPE, SIG_IGN);
     auto service = sp<MediaExtractorService>::make();
     fuzzService(service, FuzzedDataProvider(data, size));
     return 0;
diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp
index 7dc445b..201d740 100644
--- a/services/mediametrics/AudioPowerUsage.cpp
+++ b/services/mediametrics/AudioPowerUsage.cpp
@@ -93,18 +93,27 @@
 /* static */
 bool AudioPowerUsage::deviceFromString(const std::string& device_string, int32_t& device) {
     static std::map<std::string, int32_t> deviceTable = {
-        { "AUDIO_DEVICE_OUT_EARPIECE",             OUTPUT_EARPIECE },
-        { "AUDIO_DEVICE_OUT_SPEAKER_SAFE",         OUTPUT_SPEAKER_SAFE },
-        { "AUDIO_DEVICE_OUT_SPEAKER",              OUTPUT_SPEAKER },
-        { "AUDIO_DEVICE_OUT_WIRED_HEADSET",        OUTPUT_WIRED_HEADSET },
-        { "AUDIO_DEVICE_OUT_WIRED_HEADPHONE",      OUTPUT_WIRED_HEADSET },
-        { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO",        OUTPUT_BLUETOOTH_SCO },
-        { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP",       OUTPUT_BLUETOOTH_A2DP },
-        { "AUDIO_DEVICE_OUT_USB_HEADSET",          OUTPUT_USB_HEADSET },
-        { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET", OUTPUT_BLUETOOTH_SCO },
+        { "AUDIO_DEVICE_OUT_EARPIECE",                  OUTPUT_EARPIECE },
+        { "AUDIO_DEVICE_OUT_SPEAKER_SAFE",              OUTPUT_SPEAKER_SAFE },
+        { "AUDIO_DEVICE_OUT_SPEAKER",                   OUTPUT_SPEAKER },
+        { "AUDIO_DEVICE_OUT_WIRED_HEADSET",             OUTPUT_WIRED_HEADSET },
+        { "AUDIO_DEVICE_OUT_WIRED_HEADPHONE",           OUTPUT_WIRED_HEADSET },
+        { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO",             OUTPUT_BLUETOOTH_SCO },
+        { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET",     OUTPUT_BLUETOOTH_SCO },
+        { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP",            OUTPUT_BLUETOOTH_A2DP },
+        { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES", OUTPUT_BLUETOOTH_A2DP },
+        { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER",    OUTPUT_BLUETOOTH_A2DP },
+        { "AUDIO_DEVICE_OUT_BLE_HEADSET",               OUTPUT_BLUETOOTH_BLE },
+        { "AUDIO_DEVICE_OUT_BLE_SPEAKER",               OUTPUT_BLUETOOTH_BLE },
+        { "AUDIO_DEVICE_OUT_BLE_BROADCAST",             OUTPUT_BLUETOOTH_BLE },
+        { "AUDIO_DEVICE_OUT_USB_HEADSET",               OUTPUT_USB_HEADSET },
+        { "AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET",         OUTPUT_DOCK },
+        { "AUDIO_DEVICE_OUT_HDMI",                      OUTPUT_HDMI },
 
         { "AUDIO_DEVICE_IN_BUILTIN_MIC",           INPUT_BUILTIN_MIC },
         { "AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET", INPUT_BLUETOOTH_SCO },
+        { "AUDIO_DEVICE_IN_BLUETOOTH_BLE",         INPUT_BLUETOOTH_BLE },
+        { "AUDIO_DEVICE_IN_BLE_HEADSET",           INPUT_BLUETOOTH_BLE },
         { "AUDIO_DEVICE_IN_WIRED_HEADSET",         INPUT_WIRED_HEADSET_MIC },
         { "AUDIO_DEVICE_IN_USB_DEVICE",            INPUT_USB_HEADSET_MIC },
         { "AUDIO_DEVICE_IN_BACK_MIC",              INPUT_BUILTIN_BACK_MIC },
diff --git a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
index c6793a9..c7b4297 100644
--- a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
@@ -17,6 +17,7 @@
  *****************************************************************************
  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
  */
+#include <binder/IPCThreadState.h>
 #include <fuzzer/FuzzedDataProvider.h>
 #include <media/MediaMetricsItem.h>
 #include <mediametricsservice/AudioTypes.h>
@@ -26,210 +27,158 @@
 #include <string.h>
 #include <utils/Log.h>
 #include <algorithm>
+#include <set>
 
 using namespace android;
+static constexpr size_t STATSD_LOG_LINES_MAX = 48;
+static unsigned long long kPackedCallingUid = (unsigned long long)AID_SYSTEM << 32;
+constexpr int8_t kMaxBytes = 100;
+constexpr int8_t kMinBytes = 0;
+constexpr size_t kMaxItemLength = 16;
 
 // low water mark
 constexpr size_t kLogItemsLowWater = 1;
 // high water mark
 constexpr size_t kLogItemsHighWater = 2;
-constexpr size_t kMaxItemLength = 16;
-constexpr size_t kMaxApis = 64;
+
+/*
+ * Concatenating strings to generate keys in such a way that the
+ * lambda function inside AudioAnalytics() added in the 'mAction' object is covered
+ */
+
+std::string keyMediaValues[] = {
+        "metrics.manager",
+        "mediadrm",
+        "audio.device.a2dp",
+        AMEDIAMETRICS_KEY_AUDIO_MIDI,
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*",
+        AMEDIAMETRICS_KEY_AUDIO_FLINGER,
+        AMEDIAMETRICS_KEY_AUDIO_POLICY,
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
+        "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent",
+};
+
+std::string keyMediaAction[] = {
+        "createAudioPatch",
+        "connected",
+        AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP,
+};
 
 class MediaMetricsServiceFuzzer {
-   public:
-    void invokeStartsWith(const uint8_t *data, size_t size);
-    void invokeInstantiate(const uint8_t *data, size_t size);
-    void invokePackageInstallerCheck(const uint8_t *data, size_t size);
-    void invokeItemManipulation(const uint8_t *data, size_t size);
-    void invokeItemExpansion(const uint8_t *data, size_t size);
-    void invokeTimeMachineStorage(const uint8_t *data, size_t size);
-    void invokeTransactionLog(const uint8_t *data, size_t size);
-    void invokeAnalyticsAction(const uint8_t *data, size_t size);
-    void invokeAudioAnalytics(const uint8_t *data, size_t size);
-    void invokeTimedAction(const uint8_t *data, size_t size);
-    void process(const uint8_t *data, size_t size);
+  public:
+    MediaMetricsServiceFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+    void invokeStartsWith();
+    void invokeInstantiate();
+    void invokePackageInstallerCheck();
+    void invokeTimeMachineStorage();
+    void invokeTransactionLog();
+    void invokeAnalyticsAction();
+    void invokeAudioAnalytics();
+    void invokeTimedAction();
+    void setKeyValues(std::shared_ptr<mediametrics::Item>& item, std::string keyValue);
+    std::shared_ptr<mediametrics::Item> CreateItem();
+    sp<MediaMetricsService> mMediaMetricsService;
+    FuzzedDataProvider mFdp;
     std::atomic_int mValue = 0;
 };
 
-void MediaMetricsServiceFuzzer::invokeStartsWith(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-    while (fdp.remaining_bytes()) {
-        android::mediametrics::startsWith(fdp.ConsumeRandomLengthString(),
-                                          fdp.ConsumeRandomLengthString());
-    }
+void MediaMetricsServiceFuzzer::setKeyValues(std::shared_ptr<mediametrics::Item>& item,
+                                             std::string keyValue) {
+    auto invokeActionAPIs = mFdp.PickValueInArray<const std::function<void()>>({
+            [&]() { item->setInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
+            [&]() { item->addInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
+            [&]() { item->setInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
+            [&]() { item->addInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
+            [&]() { item->setDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
+            [&]() { item->addDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
+            [&]() { item->setTimestamp(mFdp.ConsumeIntegral<int64_t>()); },
+            [&]() {
+                std::string value = mFdp.ConsumeBool()
+                                            ? mFdp.ConsumeRandomLengthString(kMaxBytes)
+                                            : mFdp.PickValueInArray<std::string>(keyMediaAction);
+                item->setCString(keyValue.c_str(), value.c_str());
+            },
+            [&]() {
+                item->setRate(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>(),
+                              mFdp.ConsumeIntegral<int64_t>());
+            },
+            [&]() {
+                mediametrics::LogItem<1> itemTemp(mFdp.ConsumeRandomLengthString(kMaxBytes));
+                itemTemp.setPid(mFdp.ConsumeIntegral<int16_t>())
+                        .setUid(mFdp.ConsumeIntegral<int16_t>());
+
+                int32_t i = mFdp.ConsumeIntegral<int32_t>();
+                itemTemp.set(std::to_string(i).c_str(), (int32_t)i);
+                itemTemp.updateHeader();
+                (void)item->readFromByteString(itemTemp.getBuffer(), itemTemp.getLength());
+            },
+
+    });
+    invokeActionAPIs();
 }
 
-void MediaMetricsServiceFuzzer::invokeInstantiate(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-    sp mediaMetricsService = new MediaMetricsService();
-
-    while (fdp.remaining_bytes()) {
-        std::unique_ptr<mediametrics::Item> random_key(
-            mediametrics::Item::create(fdp.ConsumeRandomLengthString()));
-        mediaMetricsService->submit(random_key.get());
-        random_key->setInt32(fdp.ConsumeRandomLengthString().c_str(),
-                             fdp.ConsumeIntegral<int32_t>());
-        mediaMetricsService->submit(random_key.get());
-
-        std::unique_ptr<mediametrics::Item> audiotrack_key(
-            mediametrics::Item::create("audiotrack"));
-        mediaMetricsService->submit(audiotrack_key.get());
-        audiotrack_key->addInt32(fdp.ConsumeRandomLengthString().c_str(),
-                                 fdp.ConsumeIntegral<int32_t>());
-        mediaMetricsService->submit(audiotrack_key.get());
+std::shared_ptr<mediametrics::Item> MediaMetricsServiceFuzzer::CreateItem() {
+    std::string key;
+    if (mFdp.ConsumeBool()) {
+        key = mFdp.ConsumeRandomLengthString(kMaxItemLength);
+    } else {
+        key = mFdp.PickValueInArray<std::string>(keyMediaValues);
     }
-}
 
-void MediaMetricsServiceFuzzer::invokePackageInstallerCheck(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-    while (fdp.remaining_bytes()) {
-        MediaMetricsService::useUidForPackage(fdp.ConsumeRandomLengthString().c_str(),
-                                              fdp.ConsumeRandomLengthString().c_str());
-    }
-}
-
-void MediaMetricsServiceFuzzer::invokeItemManipulation(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
-    mediametrics::Item item(fdp.ConsumeRandomLengthString().c_str());
-    while (fdp.remaining_bytes()) {
-        const uint8_t action = fdp.ConsumeIntegralInRange<uint8_t>(0, 16);
-        const std::string key = fdp.ConsumeRandomLengthString();
-        if (fdp.remaining_bytes() < 1 || key.length() < 1) {
-            break;
+    std::shared_ptr<mediametrics::Item> item = std::make_shared<mediametrics::Item>(key.c_str());
+    size_t numKeys = mFdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes);
+    std::set<std::string> keySet;
+    for (size_t i = 0; i < numKeys; ++i) {
+        std::string keyValue;
+        if (mFdp.ConsumeBool()) {
+            keyValue = mFdp.ConsumeRandomLengthString(kMaxBytes);
+        } else {
+            keyValue = mFdp.PickValueInArray<std::string>(
+                    {AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_STATE, "logSessionIkeyd"});
         }
-        switch (action) {
-            case 0: {
-                item.setInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
-                break;
-            }
-            case 1: {
-                item.addInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
-                break;
-            }
-            case 2: {
-                int32_t i32 = 0;
-                item.getInt32(key.c_str(), &i32);
-                break;
-            }
-            case 3: {
-                item.setInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
-                break;
-            }
-            case 4: {
-                item.addInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
-                break;
-            }
-            case 5: {
-                int64_t i64 = 0;
-                item.getInt64(key.c_str(), &i64);
-                break;
-            }
-            case 6: {
-                item.setDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
-                break;
-            }
-            case 7: {
-                item.addDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
-                break;
-            }
-            case 8: {
-                double d = 0;
-                item.getDouble(key.c_str(), &d);
-                break;
-            }
-            case 9: {
-                item.setCString(key.c_str(), fdp.ConsumeRandomLengthString().c_str());
-                break;
-            }
-            case 10: {
-                char *s = nullptr;
-                item.getCString(key.c_str(), &s);
-                if (s) free(s);
-                break;
-            }
-            case 11: {
-                std::string s;
-                item.getString(key.c_str(), &s);
-                break;
-            }
-            case 12: {
-                item.setRate(key.c_str(), fdp.ConsumeIntegral<int64_t>(),
-                             fdp.ConsumeIntegral<int64_t>());
-                break;
-            }
-            case 13: {
-                int64_t b = 0, h = 0;
-                double d = 0;
-                item.getRate(key.c_str(), &b, &h, &d);
-                break;
-            }
-            case 14: {
-                (void)item.filter(key.c_str());
-                break;
-            }
-            case 15: {
-                const char *arr[1] = {""};
-                arr[0] = const_cast<char *>(key.c_str());
-                (void)item.filterNot(1, arr);
-                break;
-            }
-            case 16: {
-                (void)item.toString().c_str();
-                break;
-            }
+        if (keySet.find(keyValue) == keySet.end()) {
+            setKeyValues(item, keyValue);
+            keySet.insert(keyValue);
         }
     }
-
-    Parcel p;
-    mediametrics::Item item2;
-
-    (void)item.writeToParcel(&p);
-    p.setDataPosition(0);  // rewind for reading
-    (void)item2.readFromParcel(p);
-
-    char *byteData = nullptr;
-    size_t length = 0;
-    (void)item.writeToByteString(&byteData, &length);
-    (void)item2.readFromByteString(byteData, length);
-    if (byteData) {
-        free(byteData);
-    }
-
-    sp mediaMetricsService = new MediaMetricsService();
-    mediaMetricsService->submit(&item2);
+    return item;
 }
 
-void MediaMetricsServiceFuzzer::invokeItemExpansion(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
-    mediametrics::LogItem<1> item("FuzzItem");
-    item.setPid(fdp.ConsumeIntegral<int16_t>()).setUid(fdp.ConsumeIntegral<int16_t>());
-
-    while (fdp.remaining_bytes()) {
-        int32_t i = fdp.ConsumeIntegral<int32_t>();
-        item.set(std::to_string(i).c_str(), (int32_t)i);
-    }
-    item.updateHeader();
-
-    mediametrics::Item item2;
-    (void)item2.readFromByteString(item.getBuffer(), item.getLength());
-
-    sp mediaMetricsService = new MediaMetricsService();
-    mediaMetricsService->submit(&item2);
+void MediaMetricsServiceFuzzer::invokeStartsWith() {
+    android::mediametrics::startsWith(mFdp.ConsumeRandomLengthString(kMaxBytes),
+                                      mFdp.ConsumeRandomLengthString(kMaxBytes));
 }
 
-void MediaMetricsServiceFuzzer::invokeTimeMachineStorage(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeInstantiate() {
+    auto item = CreateItem();
+    mMediaMetricsService->submit(item.get());
+}
 
-    auto item = std::make_shared<mediametrics::Item>("FuzzKey");
-    int32_t i32 = fdp.ConsumeIntegral<int32_t>();
-    int64_t i64 = fdp.ConsumeIntegral<int64_t>();
-    double d = fdp.ConsumeFloatingPoint<double>();
-    std::string str = fdp.ConsumeRandomLengthString();
-    std::pair<int64_t, int64_t> pair(fdp.ConsumeIntegral<int64_t>(),
-                                     fdp.ConsumeIntegral<int64_t>());
+void MediaMetricsServiceFuzzer::invokePackageInstallerCheck() {
+    MediaMetricsService::useUidForPackage(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str(),
+                                          mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
+}
+
+void MediaMetricsServiceFuzzer::invokeTimeMachineStorage() {
+    auto item = CreateItem();
+    int32_t i32 = mFdp.ConsumeIntegral<int32_t>();
+    int64_t i64 = mFdp.ConsumeIntegral<int64_t>();
+    double d = mFdp.ConsumeFloatingPoint<double>();
+    std::string str = mFdp.ConsumeRandomLengthString(kMaxBytes);
+    std::pair<int64_t, int64_t> pair(mFdp.ConsumeIntegral<int64_t>(),
+                                     mFdp.ConsumeIntegral<int64_t>());
     (*item).set("i32", i32).set("i64", i64).set("double", d).set("string", str).set("rate", pair);
 
     android::mediametrics::TimeMachine timeMachine;
@@ -253,124 +202,89 @@
     timeMachine.get("Key.string", &str, -1);
 }
 
-void MediaMetricsServiceFuzzer::invokeTransactionLog(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
-    auto item = std::make_shared<mediametrics::Item>("Key1");
-    (*item)
-        .set("one", fdp.ConsumeIntegral<int32_t>())
-        .set("two", fdp.ConsumeIntegral<int32_t>())
-        .setTimestamp(fdp.ConsumeIntegral<int32_t>());
+void MediaMetricsServiceFuzzer::invokeTransactionLog() {
+    auto item = CreateItem();
 
     android::mediametrics::TransactionLog transactionLog(
         kLogItemsLowWater, kLogItemsHighWater);  // keep at most 2 items
     transactionLog.size();
 
     transactionLog.put(item);
-    transactionLog.size();
-
-    auto item2 = std::make_shared<mediametrics::Item>("Key2");
-    (*item2)
-        .set("three", fdp.ConsumeIntegral<int32_t>())
-        .set("[Key1]three", fdp.ConsumeIntegral<int32_t>())
-        .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-
-    transactionLog.put(item2);
-    transactionLog.size();
-
-    auto item3 = std::make_shared<mediametrics::Item>("Key3");
-    (*item3)
-        .set("six", fdp.ConsumeIntegral<int32_t>())
-        .set("[Key1]four", fdp.ConsumeIntegral<int32_t>())  // affects Key1
-        .set("[Key1]five", fdp.ConsumeIntegral<int32_t>())  // affects key1
-        .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-
-    transactionLog.put(item3);
-    transactionLog.size();
 }
 
-void MediaMetricsServiceFuzzer::invokeAnalyticsAction(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
+void MediaMetricsServiceFuzzer::invokeAnalyticsAction() {
     mediametrics::AnalyticsActions analyticsActions;
     bool action = false;
 
-    while (fdp.remaining_bytes()) {
-        analyticsActions.addAction(
-            (fdp.ConsumeRandomLengthString() + std::string(".event")).c_str(),
-            fdp.ConsumeRandomLengthString(),
+    analyticsActions.addAction(
+            (mFdp.ConsumeRandomLengthString(kMaxBytes) + std::string(".event")).c_str(),
+            mFdp.ConsumeRandomLengthString(kMaxBytes),
             std::make_shared<mediametrics::AnalyticsActions::Function>(
-                [&](const std::shared_ptr<const android::mediametrics::Item> &) {
-                    action = true;
-                }));
-    }
+                    [&](const std::shared_ptr<const android::mediametrics::Item>&) {
+                        action = true;
+                    }));
 
-    FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size);
-    size_t apiCount = 0;
-    while (fdp2.remaining_bytes() && ++apiCount <= kMaxApis) {
-        // make a test item
-        auto item = std::make_shared<mediametrics::Item>(
-                fdp2.ConsumeRandomLengthString(kMaxItemLength).c_str());
-        (*item).set("event", fdp2.ConsumeRandomLengthString().c_str());
+    // make a test item
+    auto item = CreateItem();
+    (*item).set("event", mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
 
-        // get the actions and execute them
-        auto actions = analyticsActions.getActionsForItem(item);
-        for (const auto &action : actions) {
-            action->operator()(item);
+    // get the actions and execute them
+    auto actions = analyticsActions.getActionsForItem(item);
+    for (const auto& action : actions) {
+        action->operator()(item);
         }
-    }
 }
 
-void MediaMetricsServiceFuzzer::invokeAudioAnalytics(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeAudioAnalytics() {
+    int32_t maxLogLine = mFdp.ConsumeIntegralInRange<int32_t>(0, STATSD_LOG_LINES_MAX);
     std::shared_ptr<android::mediametrics::StatsdLog> statsdLog =
-            std::make_shared<android::mediametrics::StatsdLog>(10);
+            std::make_shared<android::mediametrics::StatsdLog>(maxLogLine);
     android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
 
-    while (fdp.remaining_bytes()) {
-        auto item = std::make_shared<mediametrics::Item>(fdp.ConsumeRandomLengthString().c_str());
-        int32_t transactionUid = fdp.ConsumeIntegral<int32_t>();  // arbitrary
-        (*item)
-            .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
-            .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
-            .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
-            .setUid(transactionUid)
-            .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-        audioAnalytics.submit(item, fdp.ConsumeBool());
+    auto item = CreateItem();
+    Parcel parcel;
+    item->writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    if (mFdp.ConsumeBool()) {
+        item->readFromParcel(parcel);
     }
-
-    audioAnalytics.dump(1000);
+    audioAnalytics.submit(item, mFdp.ConsumeBool());
 }
 
-void MediaMetricsServiceFuzzer::invokeTimedAction(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeTimedAction() {
     android::mediametrics::TimedAction timedAction;
+    timedAction.postIn(std::chrono::seconds(mFdp.ConsumeIntegral<uint32_t>()),
+                       [this] { ++mValue; });
+    timedAction.size();
+}
 
-    while (fdp.remaining_bytes()) {
-        timedAction.postIn(std::chrono::seconds(fdp.ConsumeIntegral<int32_t>()),
-                           [this] { ++mValue; });
-        timedAction.size();
+void MediaMetricsServiceFuzzer::process() {
+    mMediaMetricsService = sp<MediaMetricsService>::make();
+
+    if (mFdp.ConsumeBool()) {
+        IPCThreadState::self()->restoreCallingIdentity(kPackedCallingUid);
+    } else {
+        IPCThreadState::self()->restoreCallingIdentity(mFdp.ConsumeIntegral<size_t>());
+    }
+    while (mFdp.remaining_bytes()) {
+        auto invokeAPIs = mFdp.PickValueInArray<const std::function<void()>>({
+                [&]() { invokeStartsWith(); },
+                [&]() { invokeInstantiate(); },
+                [&]() { invokePackageInstallerCheck(); },
+                [&]() { invokeTimeMachineStorage(); },
+                [&]() { invokeTransactionLog(); },
+                [&]() { invokeAudioAnalytics(); },
+                [&]() { invokeTimedAction(); },
+        });
+        invokeAPIs();
     }
 }
 
-void MediaMetricsServiceFuzzer::process(const uint8_t *data, size_t size) {
-    invokeStartsWith(data, size);
-    invokeInstantiate(data, size);
-    invokePackageInstallerCheck(data, size);
-    invokeItemManipulation(data, size);
-    invokeItemExpansion(data, size);
-    invokeTimeMachineStorage(data, size);
-    invokeTransactionLog(data, size);
-    invokeAnalyticsAction(data, size);
-    invokeAudioAnalytics(data, size);
-    invokeTimedAction(data, size);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     if (size < 1) {
         return 0;
     }
-    MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer;
-    mediaMetricsServiceFuzzer.process(data, size);
+    MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer(data, size);
+    mediaMetricsServiceFuzzer.process();
     return 0;
 }
diff --git a/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
index 6e5a5cf..cf09113 100644
--- a/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
+++ b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
@@ -71,6 +71,9 @@
         OUTPUT_BLUETOOTH_SCO    = 0x10,
         OUTPUT_BLUETOOTH_A2DP   = 0x20,
         OUTPUT_SPEAKER_SAFE     = 0x40,
+        OUTPUT_BLUETOOTH_BLE    = 0x80,
+        OUTPUT_DOCK             = 0x100,
+        OUTPUT_HDMI             = 0x200,
 
         INPUT_DEVICE_BIT        = 0x40000000,
         INPUT_BUILTIN_MIC       = INPUT_DEVICE_BIT | 0x1, // non-negative positive int32.
@@ -78,6 +81,7 @@
         INPUT_WIRED_HEADSET_MIC = INPUT_DEVICE_BIT | 0x4,
         INPUT_USB_HEADSET_MIC   = INPUT_DEVICE_BIT | 0x8,
         INPUT_BLUETOOTH_SCO     = INPUT_DEVICE_BIT | 0x10,
+        INPUT_BLUETOOTH_BLE     = INPUT_DEVICE_BIT | 0x20,
     };
 
     static bool typeFromString(const std::string& type_string, int32_t& type);
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 5dfec30..ac41959 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -30,7 +30,7 @@
         "server_configurable_flags",
     ],
     defaults: [
-        "aconfig_lib_cc_static_link.defaults",
+        "aconfig_lib_cc_shared_link.defaults",
     ],
     include_dirs: [
         "frameworks/av/include",
@@ -84,6 +84,9 @@
         "libactivitymanager_aidl",
         "server_configurable_flags",
     ],
+    defaults: [
+        "aconfig_lib_cc_shared_link.defaults",
+    ],
     include_dirs: [
         "frameworks/av/include",
         "frameworks/av/services/mediaresourcemanager",
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 5b4fca9..d663f37 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -205,6 +205,8 @@
           "sample_rate=%u, channel_mask=%#x, device=%d",
           __func__, config->format, config->sample_rate,
           config->channel_mask, deviceId);
+
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
     const status_t status = MmapStreamInterface::openMmapStream(streamDirection,
                                                                 &attributes,
                                                                 config,
@@ -246,7 +248,7 @@
           __func__, config->format, getDeviceId(), getSessionId());
 
     // Create MMAP/NOIRQ buffer.
-    result = createMmapBuffer();
+    result = createMmapBuffer_l();
     if (result != AAUDIO_OK) {
         goto error;
     }
@@ -283,7 +285,7 @@
     return result;
 
 error:
-    close();
+    close_l();
     // restore original requests
     setDeviceId(mRequestedDeviceId);
     setSessionId(requestedSessionId);
@@ -291,13 +293,28 @@
 }
 
 void AAudioServiceEndpointMMAP::close() {
-    if (mMmapStream != nullptr) {
-        // Needs to be explicitly cleared or CTS will fail but it is not clear why.
-        mMmapStream.clear();
+    bool closedIt = false;
+    {
+        const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+        closedIt = close_l();
+    }
+    if (closedIt) {
+        // TODO Why is this needed?
         AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
     }
 }
 
+bool AAudioServiceEndpointMMAP::close_l() { // requires mMmapStreamLock
+    bool closedIt = false;
+    if (mMmapStream != nullptr) {
+        // Needs to be explicitly cleared or CTS will fail but it is not clear why.
+        ALOGD("%s() clear mMmapStream", __func__);
+        mMmapStream.clear();
+        closedIt = true;
+    }
+    return closedIt;
+}
+
 aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream,
                                                    audio_port_handle_t *clientHandle __unused) {
     // Start the client on behalf of the AAudio service.
@@ -318,7 +335,7 @@
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> /*stream*/,
-                                                      audio_port_handle_t /*clientHandle*/) {
+                                                      audio_port_handle_t clientHandle) {
     mFramesTransferred.reset32();
 
     // Round 64-bit counter up to a multiple of the buffer capacity.
@@ -328,36 +345,68 @@
     mFramesTransferred.roundUp64(getBufferCapacity());
 
     // Use the port handle that was provided by openMmapStream().
-    ALOGV("%s() mPortHandle = %d", __func__, mPortHandle);
-    return stopClient(mPortHandle);
+    aaudio_result_t result = stopClient(mPortHandle);
+    ALOGD("%s(%d): called stopClient(%d=mPortHandle), returning %d", __func__,
+          (int)clientHandle, mPortHandle, result);
+    return result;
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
                                                        const audio_attributes_t *attr,
-                                                       audio_port_handle_t *clientHandle) {
-    return mMmapStream == nullptr
-            ? AAUDIO_ERROR_NULL
-            : AAudioConvert_androidToAAudioResult(mMmapStream->start(client, attr, clientHandle));
+                                                       audio_port_handle_t *portHandlePtr) {
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+    if (mMmapStream == nullptr) {
+        ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+        return AAUDIO_ERROR_NULL;
+    } else if (!isConnected()) {
+        ALOGD("%s(): MMAP stream was disconnected", __func__);
+        return AAUDIO_ERROR_DISCONNECTED;
+    } else {
+        aaudio_result_t result = AAudioConvert_androidToAAudioResult(
+                mMmapStream->start(client, attr, portHandlePtr));
+        if (!isConnected() && (portHandlePtr != nullptr)) {
+            ALOGD("%s(): MMAP stream DISCONNECTED after starting port %d, will stop it",
+                  __func__, *portHandlePtr);
+            mMmapStream->stop(*portHandlePtr);
+            *portHandlePtr = AUDIO_PORT_HANDLE_NONE;
+            result = AAUDIO_ERROR_DISCONNECTED;
+        }
+        ALOGD("%s(): returning port %d, result %d", __func__,
+              (portHandlePtr == nullptr) ? -1 : *portHandlePtr, result);
+        return result;
+    }
 }
 
-aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
-    return mMmapStream == nullptr
-            ? AAUDIO_ERROR_NULL
-            : AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
+aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t portHandle) {
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+    if (mMmapStream == nullptr) {
+        ALOGE("%s(%d): called after mMmapStream set to NULL", __func__, (int)portHandle);
+        return AAUDIO_ERROR_NULL;
+    } else {
+        aaudio_result_t result = AAudioConvert_androidToAAudioResult(
+                mMmapStream->stop(portHandle));
+        ALOGD("%s(%d): returning %d", __func__, (int)portHandle, result);
+        return result;
+    }
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::standby() {
-    return mMmapStream == nullptr
-            ? AAUDIO_ERROR_NULL
-            : AAudioConvert_androidToAAudioResult(mMmapStream->standby());
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+    if (mMmapStream == nullptr) {
+        ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+        return AAUDIO_ERROR_NULL;
+    } else {
+        return AAudioConvert_androidToAAudioResult(mMmapStream->standby());
+    }
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::exitStandby(AudioEndpointParcelable* parcelable) {
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
     if (mMmapStream == nullptr) {
         return AAUDIO_ERROR_NULL;
     }
     mAudioDataWrapper->reset();
-    const aaudio_result_t result = createMmapBuffer();
+    const aaudio_result_t result = createMmapBuffer_l();
     if (result == AAUDIO_OK) {
         getDownDataDescription(parcelable);
     }
@@ -367,10 +416,12 @@
 // Get free-running DSP or DMA hardware position from the HAL.
 aaudio_result_t AAudioServiceEndpointMMAP::getFreeRunningPosition(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
-    struct audio_mmap_position position;
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
     if (mMmapStream == nullptr) {
+        ALOGW("%s(): called after mMmapStream set to NULL", __func__);
         return AAUDIO_ERROR_NULL;
     }
+    struct audio_mmap_position position;
     const status_t status = mMmapStream->getMmapPosition(&position);
     ALOGV("%s() status= %d, pos = %d, nanos = %lld\n",
           __func__, status, position.position_frames, (long long) position.time_nanoseconds);
@@ -475,9 +526,14 @@
 aaudio_result_t AAudioServiceEndpointMMAP::getExternalPosition(uint64_t *positionFrames,
                                                                int64_t *timeNanos)
 {
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
     if (mHalExternalPositionStatus != AAUDIO_OK) {
         return mHalExternalPositionStatus;
     }
+    if (mMmapStream == nullptr) {
+        ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+        return AAUDIO_ERROR_NULL;
+    }
     uint64_t tempPositionFrames;
     int64_t tempTimeNanos;
     const status_t status = mMmapStream->getExternalPosition(&tempPositionFrames, &tempTimeNanos);
@@ -552,13 +608,20 @@
     return mHalExternalPositionStatus;
 }
 
-aaudio_result_t AAudioServiceEndpointMMAP::createMmapBuffer()
+// mMmapStreamLock should be held when calling this function.
+aaudio_result_t AAudioServiceEndpointMMAP::createMmapBuffer_l()
 {
     memset(&mMmapBufferinfo, 0, sizeof(struct audio_mmap_buffer_info));
     int32_t minSizeFrames = getBufferCapacity();
     if (minSizeFrames <= 0) { // zero will get rejected
         minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
     }
+
+    if (mMmapStream == nullptr) {
+        ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+        return AAUDIO_ERROR_NULL;
+    }
+
     const status_t status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
     const bool isBufferShareable = mMmapBufferinfo.flags & AUDIO_MMAP_APPLICATION_SHAREABLE;
     if (status != OK) {
@@ -598,6 +661,7 @@
     // Call to HAL to make sure the transport FD was able to be closed by binder.
     // This is a tricky workaround for a problem in Binder.
     // TODO:[b/192048842] When that problem is fixed we may be able to remove or change this code.
+    ALOGD("%s() - call getMmapPosition() as a hack to clear FD stuck in Binder", __func__);
     struct audio_mmap_position position;
     mMmapStream->getMmapPosition(&position);
 
@@ -613,11 +677,14 @@
 }
 
 void AAudioServiceEndpointMMAP::reportData() {
+    const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+
     if (mMmapStream == nullptr) {
         // This must not happen
         ALOGE("%s() invalid state, mmap stream is not initialized", __func__);
         return;
     }
+
     auto fifo = mAudioDataWrapper->getFifoBuffer();
     if (fifo == nullptr) {
         ALOGE("%s() fifo buffer is not initialized, cannot report data", __func__);
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index eaa578c..962d390 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -50,7 +50,7 @@
 
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
 
-    void close() override;
+    void close() override EXCLUDES(mMmapStreamLock);
 
     aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
                                 audio_port_handle_t *clientHandle) override;
@@ -60,15 +60,19 @@
 
     aaudio_result_t startClient(const android::AudioClient& client,
                                 const audio_attributes_t *attr,
-                                audio_port_handle_t *clientHandle)  override;
+                                audio_port_handle_t *clientHandle)  override
+                                EXCLUDES(mMmapStreamLock);
 
-    aaudio_result_t stopClient(audio_port_handle_t clientHandle)  override;
+    aaudio_result_t stopClient(audio_port_handle_t clientHandle)  override
+            EXCLUDES(mMmapStreamLock);
 
-    aaudio_result_t standby() override;
+    aaudio_result_t standby() override EXCLUDES(mMmapStreamLock);
 
-    aaudio_result_t exitStandby(AudioEndpointParcelable* parcelable) override;
+    aaudio_result_t exitStandby(AudioEndpointParcelable* parcelable) override
+            EXCLUDES(mMmapStreamLock);
 
-    aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
+    aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override
+             EXCLUDES(mMmapStreamLock);
 
     aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
 
@@ -88,22 +92,31 @@
         return mHardwareTimeOffsetNanos;
     }
 
-    aaudio_result_t getExternalPosition(uint64_t *positionFrames, int64_t *timeNanos);
+    aaudio_result_t getExternalPosition(uint64_t *positionFrames, int64_t *timeNanos)
+            EXCLUDES(mMmapStreamLock);
 
-    int64_t nextDataReportTime();
+    int64_t nextDataReportTime() EXCLUDES(mMmapStreamLock);
 
-    void reportData();
+    void reportData() EXCLUDES(mMmapStreamLock);
 
 private:
 
-    aaudio_result_t openWithConfig(audio_config_base_t* config);
+    /**
+     *
+     * @return true if mMapStream was cleared
+     */
+    bool close_l() REQUIRES(mMmapStreamLock);
 
-    aaudio_result_t createMmapBuffer();
+    aaudio_result_t openWithConfig(audio_config_base_t* config) EXCLUDES(mMmapStreamLock);
+
+    aaudio_result_t createMmapBuffer_l() REQUIRES(mMmapStreamLock);
 
     MonotonicCounter                          mFramesTransferred;
 
     // Interface to the AudioFlinger MMAP support.
-    android::sp<android::MmapStreamInterface> mMmapStream;
+    mutable std::mutex                        mMmapStreamLock;
+    android::sp<android::MmapStreamInterface> mMmapStream GUARDED_BY(mMmapStreamLock);
+
     struct audio_mmap_buffer_info             mMmapBufferinfo;
 
     // There is only one port associated with an MMAP endpoint.
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 20a5ea8..78cf706 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -227,6 +227,10 @@
         ALOGE("%s() has no endpoint", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }
+    if (!endpoint->isConnected()) {
+        ALOGE("%s() endpoint was already disconnected", __func__);
+        return AAUDIO_ERROR_DISCONNECTED;
+    }
     return endpoint->startStream(this, &mClientHandle);
 }
 
@@ -334,6 +338,7 @@
 aaudio_result_t AAudioServiceStreamBase::stop_l() {
     aaudio_result_t result = AAUDIO_OK;
     if (!isRunning()) {
+        ALOGW("%s() stream not running, returning early", __func__);
         return result;
     }
     const int64_t beginNs = AudioClock::getNanoseconds();
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index fc53949..5203e50 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -150,9 +150,9 @@
 
 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
                                                      const audio_attributes_t *attr,
-                                                     audio_port_handle_t *clientHandle) {
+                                                     audio_port_handle_t *portHandlePtr) {
     if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
-        return sendStartClientCommand(client, attr, clientHandle);
+        return sendStartClientCommand(client, attr, portHandlePtr);
     } else {
         sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
         if (endpoint == nullptr) {
@@ -160,7 +160,9 @@
             return AAUDIO_ERROR_INVALID_STATE;
         }
         // Start the client on behalf of the application. Generate a new porthandle.
-        aaudio_result_t result = endpoint->startClient(client, attr, clientHandle);
+        aaudio_result_t result = endpoint->startClient(client, attr, portHandlePtr);
+        ALOGD("%s() flag off, got port %d", __func__,
+              ((portHandlePtr == nullptr) ? -1 : *portHandlePtr));
         return result;
     }
 }