Merge "Camera: Populate ZOOM_METHOD in CaptureResult" into main
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 2feebb4..3b199b3 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -183,6 +183,13 @@
 
 flag {
     namespace: "camera_platform"
+    name: "depth_jpeg_extensions"
+    description: "Add Depth Jpeg extension output support"
+    bug: "362788689"
+}
+
+flag {
+    namespace: "camera_platform"
     name: "mirror_mode_shared_surfaces"
     is_exported: true
     description: "Support setting and getting mirror mode for shared surfaces"
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 754f066..eaa5bd5 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -288,10 +288,10 @@
 }
 
 DrmStatus DrmHal::getSupportedSchemes(std::vector<uint8_t>& schemes) const {
-    status_t statusResult;
-    statusResult = mDrmHalAidl->getSupportedSchemes(schemes);
-    if (statusResult == OK) return statusResult;
-    return mDrmHalHidl->getSupportedSchemes(schemes);
+    const DrmStatus statusResultAidl = mDrmHalAidl->getSupportedSchemes(schemes);
+    const DrmStatus statusResultHidl = mDrmHalHidl->getSupportedSchemes(schemes);
+    if (statusResultHidl == OK || statusResultAidl == OK) return OK;
+    return statusResultAidl;
 }
 
 }  // namespace android
diff --git a/media/OWNERS b/media/OWNERS
index b926075..5e32047 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,6 +1,7 @@
 # Bug component: 1344
 elaurent@google.com
 essick@google.com
+atneya@google.com
 hunga@google.com
 jiabin@google.com
 jmtrivi@google.com
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 95a8a69..f739f3c 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -76,8 +76,6 @@
 using media::audio::common::AudioOffloadInfo;
 using media::audio::common::AudioOutputFlags;
 using media::audio::common::AudioPlaybackRate;
-using media::audio::common::AudioPolicyForcedConfig;
-using media::audio::common::AudioPolicyForceUse;
 using media::audio::common::AudioPort;
 using media::audio::common::AudioPortConfig;
 using media::audio::common::AudioPortDeviceExt;
@@ -3359,138 +3357,6 @@
     return OK;
 }
 
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(AudioPolicyForceUse aidl) {
-    switch (aidl) {
-        case AudioPolicyForceUse::COMMUNICATION:
-            return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
-        case AudioPolicyForceUse::MEDIA:
-            return AUDIO_POLICY_FORCE_FOR_MEDIA;
-        case AudioPolicyForceUse::RECORD:
-            return AUDIO_POLICY_FORCE_FOR_RECORD;
-        case AudioPolicyForceUse::DOCK:
-            return AUDIO_POLICY_FORCE_FOR_DOCK;
-        case AudioPolicyForceUse::SYSTEM:
-            return AUDIO_POLICY_FORCE_FOR_SYSTEM;
-        case AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
-            return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
-        case AudioPolicyForceUse::ENCODED_SURROUND:
-            return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
-        case AudioPolicyForceUse::VIBRATE_RINGING:
-            return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
-    switch (legacy) {
-        case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
-            return AudioPolicyForceUse::COMMUNICATION;
-        case AUDIO_POLICY_FORCE_FOR_MEDIA:
-            return AudioPolicyForceUse::MEDIA;
-        case AUDIO_POLICY_FORCE_FOR_RECORD:
-            return AudioPolicyForceUse::RECORD;
-        case AUDIO_POLICY_FORCE_FOR_DOCK:
-            return AudioPolicyForceUse::DOCK;
-        case AUDIO_POLICY_FORCE_FOR_SYSTEM:
-            return AudioPolicyForceUse::SYSTEM;
-        case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
-            return AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
-        case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
-            return AudioPolicyForceUse::ENCODED_SURROUND;
-        case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
-            return AudioPolicyForceUse::VIBRATE_RINGING;
-        case AUDIO_POLICY_FORCE_USE_CNT:
-            break;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(AudioPolicyForcedConfig aidl) {
-    switch (aidl) {
-        case AudioPolicyForcedConfig::NONE:
-            return AUDIO_POLICY_FORCE_NONE;
-        case AudioPolicyForcedConfig::SPEAKER:
-            return AUDIO_POLICY_FORCE_SPEAKER;
-        case AudioPolicyForcedConfig::HEADPHONES:
-            return AUDIO_POLICY_FORCE_HEADPHONES;
-        case AudioPolicyForcedConfig::BT_SCO:
-            return AUDIO_POLICY_FORCE_BT_SCO;
-        case AudioPolicyForcedConfig::BT_A2DP:
-            return AUDIO_POLICY_FORCE_BT_A2DP;
-        case AudioPolicyForcedConfig::WIRED_ACCESSORY:
-            return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
-        case AudioPolicyForcedConfig::BT_CAR_DOCK:
-            return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
-        case AudioPolicyForcedConfig::BT_DESK_DOCK:
-            return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
-        case AudioPolicyForcedConfig::ANALOG_DOCK:
-            return AUDIO_POLICY_FORCE_ANALOG_DOCK;
-        case AudioPolicyForcedConfig::DIGITAL_DOCK:
-            return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
-        case AudioPolicyForcedConfig::NO_BT_A2DP:
-            return AUDIO_POLICY_FORCE_NO_BT_A2DP;
-        case AudioPolicyForcedConfig::SYSTEM_ENFORCED:
-            return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
-        case AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
-            return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
-        case AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
-            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
-        case AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
-            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
-        case AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
-            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
-        case AudioPolicyForcedConfig::BT_BLE:
-            return AUDIO_POLICY_FORCE_BT_BLE;
-    }
-    return unexpected(BAD_VALUE);
-}
-
-ConversionResult<AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
-    switch (legacy) {
-        case AUDIO_POLICY_FORCE_NONE:
-            return AudioPolicyForcedConfig::NONE;
-        case AUDIO_POLICY_FORCE_SPEAKER:
-            return AudioPolicyForcedConfig::SPEAKER;
-        case AUDIO_POLICY_FORCE_HEADPHONES:
-            return AudioPolicyForcedConfig::HEADPHONES;
-        case AUDIO_POLICY_FORCE_BT_SCO:
-            return AudioPolicyForcedConfig::BT_SCO;
-        case AUDIO_POLICY_FORCE_BT_A2DP:
-            return AudioPolicyForcedConfig::BT_A2DP;
-        case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
-            return AudioPolicyForcedConfig::WIRED_ACCESSORY;
-        case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
-            return AudioPolicyForcedConfig::BT_CAR_DOCK;
-        case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
-            return AudioPolicyForcedConfig::BT_DESK_DOCK;
-        case AUDIO_POLICY_FORCE_ANALOG_DOCK:
-            return AudioPolicyForcedConfig::ANALOG_DOCK;
-        case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
-            return AudioPolicyForcedConfig::DIGITAL_DOCK;
-        case AUDIO_POLICY_FORCE_NO_BT_A2DP:
-            return AudioPolicyForcedConfig::NO_BT_A2DP;
-        case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
-            return AudioPolicyForcedConfig::SYSTEM_ENFORCED;
-        case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
-            return AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
-        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
-            return AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
-        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
-            return AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
-        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
-            return AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
-        case AUDIO_POLICY_FORCE_BT_BLE:
-            return AudioPolicyForcedConfig::BT_BLE;
-        case AUDIO_POLICY_FORCE_CFG_CNT:
-            break;
-    }
-    return unexpected(BAD_VALUE);
-}
-
 }  // namespace android
 
 #undef GET_DEVICE_DESC_CONNECTION
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
index 9dfb7e7..7268464 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
@@ -58,8 +58,6 @@
 #include PREFIX(android/media/audio/common/AudioMode.h)
 #include PREFIX(android/media/audio/common/AudioOffloadInfo.h)
 #include PREFIX(android/media/audio/common/AudioOutputFlags.h)
-#include PREFIX(android/media/audio/common/AudioPolicyForceUse.h)
-#include PREFIX(android/media/audio/common/AudioPolicyForcedConfig.h)
 #include PREFIX(android/media/audio/common/AudioPort.h)
 #include PREFIX(android/media/audio/common/AudioPortConfig.h)
 #include PREFIX(android/media/audio/common/AudioPortExt.h)
@@ -78,7 +76,6 @@
 
 #include <system/audio.h>
 #include <system/audio_effect.h>
-#include <system/audio_policy.h>
 
 #if defined(BACKEND_NDK_IMPL)
 namespace aidl {
@@ -457,18 +454,6 @@
         media::audio::common::MicrophoneInfo* aidlInfo,
         media::audio::common::MicrophoneDynamicInfo* aidlDynamic);
 
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(
-        media::audio::common::AudioPolicyForcedConfig aidl);
-ConversionResult<media::audio::common::AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
-
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
-        media::audio::common::AudioPolicyForceUse aidl);
-ConversionResult<media::audio::common::AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
-
 }  // namespace android
 
 #if defined(BACKEND_NDK_IMPL)
diff --git a/media/codec2/components/apv/C2SoftApvEnc.cpp b/media/codec2/components/apv/C2SoftApvEnc.cpp
index d6a9597..9c5e0b2 100644
--- a/media/codec2/components/apv/C2SoftApvEnc.cpp
+++ b/media/codec2/components/apv/C2SoftApvEnc.cpp
@@ -958,108 +958,98 @@
         finish(workIndex, fillWork);
     }
 }
-void C2SoftApvEnc::createCsdData(const std::unique_ptr<C2Work>& work, oapv_bitb_t* bitb,
-                                 uint32_t encodedSize) {
-    uint32_t csdStart = 0, csdEnd = 0;
-    uint32_t bitOffset = 0;
-    uint8_t* buf = (uint8_t*)bitb->addr + csdStart;
 
-    if (encodedSize == 0) {
-        ALOGE("the first frame size is zero, so no csd data will be created.");
+void C2SoftApvEnc::createCsdData(const std::unique_ptr<C2Work>& work,
+                                 oapv_bitb_t* bitb,
+                                 uint32_t encodedSize) {
+    if (encodedSize < 31) {
+        ALOGE("the first frame size is too small, so no csd data will be created.");
         return;
     }
-    ABitReader reader(buf, encodedSize);
+    ABitReader reader((uint8_t*)bitb->addr, encodedSize);
+
+    uint8_t number_of_configuration_entry = 0;
+    uint8_t pbu_type = 0;
+    uint8_t number_of_frame_info = 0;
+    bool color_description_present_flag = false;
+    bool capture_time_distance_ignored = false;
+    uint8_t profile_idc = 0;
+    uint8_t level_idc = 0;
+    uint8_t band_idc = 0;
+    uint32_t frame_width_minus1 = 0;
+    uint32_t frame_height_minus1 = 0;
+    uint8_t chroma_format_idc = 0;
+    uint8_t bit_depth_minus8 = 0;
+    uint8_t capture_time_distance = 0;
+    uint8_t color_primaries = 0;
+    uint8_t transfer_characteristics = 0;
+    uint8_t matrix_coefficients = 0;
 
     /* pbu_header() */
-    reader.skipBits(32);
-    bitOffset += 32;  // pbu_size
-    reader.skipBits(32);
-    bitOffset += 32;  // currReadSize
-    csdStart = bitOffset / 8;
-
-    int32_t pbu_type = reader.getBits(8);
-    bitOffset += 8;  // pbu_type
-    reader.skipBits(16);
-    bitOffset += 16;  // group_id
-    reader.skipBits(8);
-    bitOffset += 8;  // reserved_zero_8bits
+    reader.skipBits(32);           // pbu_size
+    reader.skipBits(32);           // currReadSize
+    pbu_type = reader.getBits(8);  // pbu_type
+    reader.skipBits(16);           // group_id
+    reader.skipBits(8);            // reserved_zero_8bits
 
     /* frame info() */
-    int32_t profile_idc = reader.getBits(8);
-    bitOffset += 8;  // profile_idc
-    int32_t level_idc = reader.getBits(8);
-    bitOffset += 8;  // level_idc
-    int32_t band_idc = reader.getBits(3);
-    bitOffset += 3;  // band_idc
-    reader.skipBits(5);
-    bitOffset += 5;  // reserved_zero_5bits
-    int32_t width = reader.getBits(32);
-    bitOffset += 32;  // width
-    int32_t height = reader.getBits(32);
-    bitOffset += 32;  // height
-    int32_t chroma_idc = reader.getBits(4);
-    bitOffset += 4;  // chroma_format_idc
-    reader.skipBits(4);
-    bitOffset += 4;  // bit_depth
-    reader.skipBits(8);
-    bitOffset += 8;  // capture_time_distance
-    reader.skipBits(8);
-    bitOffset += 8;  // reserved_zero_8bits
+    profile_idc = reader.getBits(8);            // profile_idc
+    level_idc = reader.getBits(8);              // level_idc
+    band_idc = reader.getBits(3);               // band_idc
+    reader.skipBits(5);                         // reserved_zero_5bits
+    frame_width_minus1 = reader.getBits(32);    // width
+    frame_height_minus1 = reader.getBits(32);   // height
+    chroma_format_idc = reader.getBits(4);      // chroma_format_idc
+    bit_depth_minus8 = reader.getBits(4);       // bit_depth
+    capture_time_distance = reader.getBits(8);  // capture_time_distance
+    reader.skipBits(8);                         // reserved_zero_8bits
 
     /* frame header() */
-    reader.skipBits(8);
-    bitOffset += 8;  // reserved_zero_8bit
-    bool color_description_present_flag = reader.getBits(1);
-    bitOffset += 1;  // color_description_present_flag
+    reader.skipBits(8);  // reserved_zero_8bit
+    color_description_present_flag = reader.getBits(1);  // color_description_present_flag
     if (color_description_present_flag) {
-        reader.skipBits(8);
-        bitOffset += 8;  // color_primaries
-        reader.skipBits(8);
-        bitOffset += 8;  // transfer_characteristics
-        reader.skipBits(8);
-        bitOffset += 8;  // matrix_coefficients
-    }
-    bool use_q_matrix = reader.getBits(1);
-    bitOffset += 1;  // use_q_matrix
-    if (use_q_matrix) {
-        /* quantization_matrix() */
-        int32_t numComp = chroma_idc == 0   ? 1
-                          : chroma_idc == 2 ? 3
-                          : chroma_idc == 3 ? 3
-                          : chroma_idc == 4 ? 4
-                                            : -1;
-        int32_t needBitsForQ = 64 * 8 * numComp;
-        reader.skipBits(needBitsForQ);
-        bitOffset += needBitsForQ;
+        color_primaries = reader.getBits(8);           // color_primaries
+        transfer_characteristics = reader.getBits(8);  // transfer_characteristics
+        matrix_coefficients = reader.getBits(8);       // matrix_coefficients
     }
 
-    /* tile_info() */
-    int32_t tile_width_in_mbs_minus1 = reader.getBits(28);
-    bitOffset += 28;
-    int32_t tile_height_in_mbs_minus1 = reader.getBits(28);
-    bitOffset += 28;
-    bool tile_size_present_in_fh_flag = reader.getBits(1);
-    bitOffset += 1;
-    if (tile_size_present_in_fh_flag) {
-        int32_t numTiles = ceil((double)width / (double)tile_width_in_mbs_minus1) *
-                           ceil((double)height / (double)tile_height_in_mbs_minus1);
-        reader.skipBits(32 * numTiles);
-        bitOffset += (32 * numTiles);
-    }
+    number_of_configuration_entry = 1;  // The real-time encoding on the device is assumed to be 1.
+    number_of_frame_info = 1;  // The real-time encoding on the device is assumed to be 1.
 
-    reader.skipBits(8);
-    bitOffset += 8;  // reserved_zero_8bits
+    std::vector<uint8_t> csdData;
+    csdData.push_back((uint8_t)0x1);
+    csdData.push_back(number_of_configuration_entry);
 
-    /* byte_alignmenet() */
-    while (bitOffset % 8) {
-        reader.skipBits(1);
-        bitOffset += 1;
+    for (uint8_t i = 0; i < number_of_configuration_entry; i++) {
+        csdData.push_back(pbu_type);
+        csdData.push_back(number_of_frame_info);
+        for (uint8_t j = 0; j < number_of_frame_info; j++) {
+            csdData.push_back((uint8_t)((color_description_present_flag << 1) |
+                                      capture_time_distance_ignored));
+            csdData.push_back(profile_idc);
+            csdData.push_back(level_idc);
+            csdData.push_back(band_idc);
+            csdData.push_back((uint8_t)((frame_width_minus1 >> 24) & 0xff));
+            csdData.push_back((uint8_t)((frame_width_minus1 >> 16) & 0xff));
+            csdData.push_back((uint8_t)((frame_width_minus1 >> 8) & 0xff));
+            csdData.push_back((uint8_t)(frame_width_minus1 & 0xff));
+            csdData.push_back((uint8_t)((frame_height_minus1 >> 24) & 0xff));
+            csdData.push_back((uint8_t)((frame_height_minus1 >> 16) & 0xff));
+            csdData.push_back((uint8_t)((frame_height_minus1 >> 8) & 0xff));
+            csdData.push_back((uint8_t)(frame_height_minus1 & 0xff));
+            csdData.push_back((uint8_t)(((chroma_format_idc << 4) & 0xf0) |
+                                      (bit_depth_minus8 & 0xf)));
+            csdData.push_back((uint8_t)(capture_time_distance));
+            if (color_description_present_flag) {
+                csdData.push_back(color_primaries);
+                csdData.push_back(transfer_characteristics);
+                csdData.push_back(matrix_coefficients);
+            }
+        }
     }
-    csdEnd = bitOffset / 8;
-    int32_t csdSize = csdEnd - csdStart + 1;
 
     std::unique_ptr<C2StreamInitDataInfo::output> csd =
-            C2StreamInitDataInfo::output::AllocUnique(csdSize, 0u);
+        C2StreamInitDataInfo::output::AllocUnique(csdData.size(), 0u);
     if (!csd) {
         ALOGE("CSD allocation failed");
         mSignalledError = true;
@@ -1068,10 +1058,10 @@
         return;
     }
 
-    buf = buf + csdStart;
-    memcpy(csd->m.value, buf, csdSize);
+    memcpy(csd->m.value, csdData.data(), csdData.size());
     work->worklets.front()->output.configUpdate.push_back(std::move(csd));
 }
+
 c2_status_t C2SoftApvEnc::drainInternal(uint32_t drainMode,
                                         const std::shared_ptr<C2BlockPool>& pool,
                                         const std::unique_ptr<C2Work>& work) {
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 069d6ad..fa5ce77 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -70,6 +70,7 @@
     enum platform_level_t : uint32_t;       ///< platform level
     enum prepend_header_mode_t : uint32_t;  ///< prepend header operational modes
     enum profile_t : uint32_t;              ///< coding profile
+    enum resource_kind_t : uint32_t;        ///< resource kinds
     enum scaling_method_t : uint32_t;       ///< scaling methods
     enum scan_order_t : uint32_t;           ///< scan orders
     enum secure_mode_t : uint32_t;          ///< secure/protected modes
@@ -101,6 +102,7 @@
     kParamIndexMasteringDisplayColorVolume,
     kParamIndexChromaOffset,
     kParamIndexGopLayer,
+    kParamIndexSystemResource,
 
     /* =================================== parameter indices =================================== */
 
@@ -167,6 +169,10 @@
     /* Region of Interest Encoding parameters */
     kParamIndexQpOffsetMapBuffer, // info-buffer, used to signal qp-offset map for a frame
 
+    /* resource capacity and resources excluded */
+    kParamIndexResourcesCapacity,
+    kParamIndexResourcesExcluded,
+
     // deprecated
     kParamIndexDelayRequest = kParamIndexDelay | C2Param::CoreIndex::IS_REQUEST_FLAG,
 
@@ -1257,21 +1263,114 @@
 /* ----------------------------------------- resources ----------------------------------------- */
 
 /**
- * Resources needed and resources reserved for current configuration.
- *
- * Resources are tracked as a vector of positive numbers. Available resources are defined by
- * the vendor.
- *
- * By default, no resources are reserved for a component. If resource reservation is successful,
- * the component shall be able to use those resources exclusively. If however, the component is
- * not using all of the reserved resources, those may be shared with other components.
- *
- * TODO: define some of the resources.
+ * Resource kind.
  */
-typedef C2GlobalParam<C2Tuning, C2Uint64Array, kParamIndexResourcesNeeded> C2ResourcesNeededTuning;
-typedef C2GlobalParam<C2Tuning, C2Uint64Array, kParamIndexResourcesReserved>
-        C2ResourcesReservedTuning;
+C2ENUM(C2Config::resource_kind_t, uint32_t,
+    CONST,
+    PER_FRAME,
+    PER_INPUT_BLOCK,
+    PER_OUTPUT_BLOCK
+)
+
+/**
+ * Definition of a system resource use.
+ *
+ * [PROPOSED]
+ *
+ * System resources are defined by the default component store.
+ * They represent any physical or abstract entities of limited availability
+ * that is required for a component instance to execute and process work.
+ *
+ * Each defined resource has an id.
+ * The use of a resource is specified by the amount and the kind (e.g. whether the amount
+ * of resources is required for each frame processed, or whether they are required
+ * regardless of the processing rate (const amount)).
+ *
+ * Note: implementations can shadow this structure with their own custom resource
+ * structure where a uint32_t based enum is used for id.
+ * This can be used to provide a name for each resource, via parameter descriptors.
+ */
+
+struct C2SystemResourceStruct {
+    C2SystemResourceStruct(uint32_t id_,
+                           C2Config::resource_kind_t kind_,
+                           uint64_t amount_)
+        : id(id_), kind(kind_), amount(amount_) { }
+    uint32_t id;
+    C2Config::resource_kind_t kind;
+    uint64_t amount;
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(SystemResource)
+    C2FIELD(id, "id")
+    C2FIELD(kind, "kind")
+    C2FIELD(amount, "amount")
+};
+
+/**
+ * Total system resource capacity.
+ *
+ * [PROPOSED]
+ *
+ * This setting is implemented by the default component store.
+ * The total resource capacity is specified as the maximum amount for each resource ID
+ * that is supported by the device hardware or firmware.
+ * As such, the kind must be CONST for each element.
+ */
+typedef C2GlobalParam<C2Tuning,
+                      C2SimpleArrayStruct<C2SystemResourceStruct>,
+                      kParamIndexResourcesCapacity> C2ResourcesCapacityTuning;
+constexpr char C2_PARAMKEY_RESOURCES_CAPACITY[] = "resources.capacity";
+
+/**
+ * Excluded system resources.
+ *
+ * [PROPOSED]
+ *
+ * This setting is implemented by the default component store.
+ * Some system resources may be used by components and not tracked by the Codec 2.0 API.
+ * This is communicated by this tuning.
+ * Excluded resources are the total resources that are used by non-Codec 2.0 components.
+ * It is specified as the excluded amount for each resource ID that is used by
+ * a non-Codec 2.0 component. As such, the kind must be CONST for each element.
+ *
+ * The platform can calculate the available resources as total capacity minus
+ * excluded resource minus sum of needed resources for each component.
+ */
+typedef C2GlobalParam<C2Tuning,
+                      C2SimpleArrayStruct<C2SystemResourceStruct>,
+                      kParamIndexResourcesExcluded> C2ResourcesExcludedTuning;
+constexpr char C2_PARAMKEY_RESOURCES_EXCLUDED[] = "resources.excluded";
+
+/**
+ * System resources needed for the current configuration.
+ *
+ * [PROPOSED]
+ *
+ * Resources are tracked as a list of individual resource use specifications.
+ * The resource kind can be CONST, PER_FRAME, PER_INPUT_BLODCK or PER_OUTPUT_BLOCK.
+ */
+typedef C2GlobalParam<C2Tuning,
+                      C2SimpleArrayStruct<C2SystemResourceStruct>,
+                      kParamIndexResourcesNeeded> C2ResourcesNeededTuning;
 constexpr char C2_PARAMKEY_RESOURCES_NEEDED[] = "resources.needed";
+
+/**
+ * System resources reserved for this component
+ *
+ * [FUTURE]
+ *
+ * This allows the platform to set aside system resources for the component.
+ * Since this is a static resource reservation, kind must be CONST for each element.
+ * This resource reservation only considers CONST and PER_FRAME use.
+ *
+ * By default, no resources are reserved for a component.
+ * If resource reservation is successful, the component shall be able to use those
+ * resources exclusively. If however, the component is not using all of the
+ * reserved resources, those may be shared with other components.
+ */
+typedef C2GlobalParam<C2Tuning,
+                      C2SimpleArrayStruct<C2SystemResourceStruct>,
+                      kParamIndexResourcesReserved> C2ResourcesReservedTuning;
 constexpr char C2_PARAMKEY_RESOURCES_RESERVED[] = "resources.reserved";
 
 /**
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index fd242a1..0f5cdd6 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -16,6 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2InfoBuilder"
+
+#include <cstdlib>
+
 #include <log/log.h>
 
 #include <strings.h>
@@ -508,6 +511,10 @@
                 && !hasPrefix(v.first, "domain-")
                 && !hasPrefix(v.first, "variant-")) {
             writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
+            if (v.first == "max-concurrent-instances") {
+                MediaCodecInfoWriter::SetMaxSupportedInstances(
+                        (int32_t)strtol(v.second.c_str(), NULL, 10));
+            }
         }
     }
 
@@ -797,6 +804,7 @@
                     }
                 }
             }
+            codecInfo->createCodecCaps();
         }
     }
     return OK;
diff --git a/media/janitors/better_together_OWNERS b/media/janitors/better_together_OWNERS
new file mode 100644
index 0000000..70723cb
--- /dev/null
+++ b/media/janitors/better_together_OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 137631
+
+aquilescanta@google.com
+asapperstein@google.com
+halliwell@google.com
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 136edcc..6c41198 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -119,8 +119,42 @@
      *
      * Available since API level 34.
      */
-    AAUDIO_FORMAT_IEC61937
+    AAUDIO_FORMAT_IEC61937,
 
+    /**
+     * This format is used for audio compressed in MP3 format.
+     */
+    AAUDIO_FORMAT_MP3,
+
+    /**
+     * This format is used for audio compressed in AAC LC format.
+     */
+    AAUDIO_FORMAT_AAC_LC,
+
+    /**
+     * This format is used for audio compressed in AAC HE V1 format.
+     */
+    AAUDIO_FORMAT_AAC_HE_V1,
+
+    /**
+     * This format is used for audio compressed in AAC HE V2 format.
+     */
+    AAUDIO_FORMAT_AAC_HE_V2,
+
+    /**
+     * This format is used for audio compressed in AAC ELD format.
+     */
+    AAUDIO_FORMAT_AAC_ELD,
+
+    /**
+     * This format is used for audio compressed in AAC XHE format.
+     */
+    AAUDIO_FORMAT_AAC_XHE,
+
+    /**
+     * This format is used for audio compressed in OPUS.
+     */
+    AAUDIO_FORMAT_OPUS
 };
 typedef int32_t aaudio_format_t;
 
@@ -335,7 +369,23 @@
     /**
      * Reducing latency is more important than battery life.
      */
-    AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+    AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+
+    /**
+     * Extending battery life is more important than low latency.
+     *
+     * This mode is not supported in input streams.
+     * This mode will play through the offloaded audio path to save battery life.
+     *
+     * Comparing to mode {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING}, the stream at
+     * this mode will be able to write a large amount(several seconds) of data within a
+     * short time. The written data will be queued in a hardware buffer. After that, the
+     * app can suspend its thread/process that playing audio, the audio framework's data
+     * pipe will be suspended automatically and the CPU will be allowed to sleep for
+     * power saving. When all queued data are played, the apps will be able to get callback
+     * to feed more data.
+     */
+    AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED
 };
 typedef int32_t aaudio_performance_mode_t;
 
@@ -1090,7 +1140,8 @@
  * Set the requested performance mode.
  *
  * Supported modes are {@link #AAUDIO_PERFORMANCE_MODE_NONE},
- * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING} * and {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}.
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING}, {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY} and
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED}.
  *
  * The default, if you do not call this function, is {@link #AAUDIO_PERFORMANCE_MODE_NONE}.
  *
@@ -1475,6 +1526,44 @@
         __INTRODUCED_IN(26);
 
 /**
+ * Prototype for the callback function that is passed to
+ * AAudioStreamBuilder_setPresentationEndCallback().
+ *
+ * This will be called when all the buffers of an offloaded stream that were queued in the audio
+ * system (e.g. the combination of the Android audio framework and the device's audio hardware)
+ * have been played after AudioStream_requestStop() has been called.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream(), which must be an
+ *               output stream as the offloaded mode is only supported for output stream
+ * @param userData the same address that was passed to
+ *                 AAudioStreamBuilder_setPresentationEndCallback().
+ */
+typedef void (*AAudioStream_presentationEndCallback)(AAudioStream* _Nonnull stream,
+                                                     void* _Null_unspecified userData);
+
+/**
+ * Request that AAudio call this function when all the buffers of an offloaded stream that were
+ * queued in the audio system (e.g. the combination of the Android audio framework and the device's
+ * audio hardware) have been played.
+ *
+ * The presentation end callback must be used together with the data callback.
+ * The presentation edn callback won't be called if the stream is closed before all the data
+ * is played.
+ *
+ * Available since API level 36.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param callback pointer to a function that will be called when all the buffers of an offloaded
+ *                 stream that were queued have been played.
+ * @param userData pointer to an application data structure that will be passed
+ *                 to the callback functions.
+ */
+AAUDIO_API void AAudioStreamBuilder_setPresentationEndCallback(
+        AAudioStreamBuilder* _Nonnull builder,
+        AAudioStream_presentationEndCallback _Nonnull callback,
+        void* _Nullable userData) __INTRODUCED_IN(36);
+
+/**
  * Open a stream based on the options in the StreamBuilder.
  *
  * AAudioStream_close() must be called when finished with the stream to recover
@@ -2188,6 +2277,72 @@
 AAUDIO_API aaudio_channel_mask_t AAudioStream_getChannelMask(AAudioStream* _Nonnull stream)
         __INTRODUCED_IN(32);
 
+/**
+ * Configures the delay and padding values for the current stream playing in offload mode.
+ * This should only be used on a stream whose performance mode is
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED} and the format is compressed format.
+ * The unit is frames, where a frame includes samples for all audio channels, e.g. 100 frames
+ * for a stereo stream corresponds to 200 interleaved PCM samples.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param delayInFrames number of frames to be ignored at the beginning of the stream. A value
+ *                      of 0 indicates no delay is to be applied.
+ * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
+ *                        of 0 indicates no padding is to be applied.
+ * @return {@link #AAUDIO_OK} if the delay and padding values are set successfully,
+ *         or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if delayInFrames or paddingInFrames
+ *         is less than 0,
+ *         or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ *         performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ *         or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadDelayPadding(
+        AAudioStream* _Nonnull stream, int32_t delayInFrames, int32_t paddingInFrames)
+        __INTRODUCED_IN(36);
+
+/**
+ * Return the decoder delay of an offloaded stream in frames.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the offload delay in frames that previously set with
+ *         {@link #AAudioStream_setOffloadDelayPadding},
+ *         or 0 if it was never modified,
+ *         or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ *         performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ *         or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API int32_t AAudioStream_getOffloadDelay(AAudioStream* _Nonnull stream) __INTRODUCED_IN(36);
+
+/**
+ * Return the decoder padding of an offloaded stream in frames.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the offload padding in frames that previously set with
+ *         {@link #AAudioStream_setOffloadDelayPadding},
+ *         or 0 if it was never modified,
+ *         or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ *         performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ *         or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API int32_t AAudioStream_getOffloadPadding(AAudioStream* _Nonnull stream)
+        __INTRODUCED_IN(36);
+
+/**
+ * Declares that the last data writing operation on this stream provided the last buffer of this
+ * stream.
+ * After the end of stream, previously set padding and delay values are ignored. That indicates
+ * all written data will be played.
+ * Use this method in the same thread as any data writing operation.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return {@link #AAUDIO_OK} on success,
+ *         or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ *         performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ *         or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadEndOfStream(AAudioStream* _Nonnull stream)
+        __INTRODUCED_IN(36);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 64152f0..de82471 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -255,6 +255,16 @@
     streamBuilder->setErrorCallbackUserData(userData);
 }
 
+AAUDIO_API void AAudioStreamBuilder_setPresentationEndCallback(AAudioStreamBuilder* builder,
+        AAudioStream_presentationEndCallback callback, void* userData) {
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    if (streamBuilder == nullptr) {
+        return;
+    }
+    streamBuilder->setPresentationEndCallbackProc(callback)
+                 ->setPresentationEndCallbackUserData(userData);
+}
+
 AAUDIO_API void AAudioStreamBuilder_setFramesPerDataCallback(AAudioStreamBuilder* builder,
                                                 int32_t frames)
 {
@@ -693,3 +703,27 @@
     // Do not return channel index masks as they are not public.
     return AAudio_isChannelIndexMask(channelMask) ? AAUDIO_UNSPECIFIED : channelMask;
 }
+
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadDelayPadding(
+        AAudioStream* stream, int32_t delayInFrames, int32_t paddingInFrames) {
+    if (delayInFrames < 0 || paddingInFrames < 0) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    }
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->setOffloadDelayPadding(delayInFrames, paddingInFrames);
+}
+
+AAUDIO_API int32_t AAudioStream_getOffloadDelay(AAudioStream* stream) {
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getOffloadDelay();
+}
+
+AAUDIO_API int32_t AAudioStream_getOffloadPadding(AAudioStream* stream) {
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getOffloadPadding();
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadEndOfStream(AAudioStream* stream) {
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->setOffloadEndOfStream();
+}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index f504fa9..ed20d12 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -58,6 +58,13 @@
         case AUDIO_FORMAT_PCM_24_BIT_PACKED:
         case AUDIO_FORMAT_PCM_8_24_BIT:
         case AUDIO_FORMAT_IEC61937:
+        case AUDIO_FORMAT_MP3:
+        case AUDIO_FORMAT_AAC_LC:
+        case AUDIO_FORMAT_AAC_HE_V1:
+        case AUDIO_FORMAT_AAC_HE_V2:
+        case AUDIO_FORMAT_AAC_ELD:
+        case AUDIO_FORMAT_AAC_XHE:
+        case AUDIO_FORMAT_OPUS:
             break; // valid
         default:
             ALOGD("audioFormat not valid, audio_format_t = 0x%08x", format);
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8e3bcf7..468bcfa 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -116,6 +116,8 @@
     mErrorCallbackProc = builder.getErrorCallbackProc();
     mDataCallbackUserData = builder.getDataCallbackUserData();
     mErrorCallbackUserData = builder.getErrorCallbackUserData();
+    setPresentationEndCallbackUserData(builder.getPresentationEndCallbackUserData());
+    setPresentationEndCallbackProc(builder.getPresentationEndCallbackProc());
 
     return AAUDIO_OK;
 }
@@ -285,6 +287,10 @@
 
 aaudio_result_t AudioStream::systemStopInternal() {
     std::lock_guard<std::mutex> lock(mStreamLock);
+    return systemStopInternal_l();
+}
+
+aaudio_result_t AudioStream::systemStopInternal_l() {
     aaudio_result_t result = safeStop_l();
     if (result == AAUDIO_OK) {
         // We only call this for logging in "dumpsys audio". So ignore return code.
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 3354adf..0ddc8ed 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -332,7 +332,7 @@
      * have been called.
      */
     int32_t getBytesPerFrame() const {
-        return mSamplesPerFrame * getBytesPerSample();
+        return audio_bytes_per_frame(mSamplesPerFrame, mFormat);
     }
 
     /**
@@ -346,7 +346,7 @@
      * This is only valid after setDeviceSamplesPerFrame() and setDeviceFormat() have been called.
      */
     int32_t getBytesPerDeviceFrame() const {
-        return getDeviceSamplesPerFrame() * audio_bytes_per_sample(getDeviceFormat());
+        return audio_bytes_per_frame(getDeviceSamplesPerFrame(), getDeviceFormat());
     }
 
     virtual int64_t getFramesWritten() = 0;
@@ -390,6 +390,24 @@
         mDeviceSamplesPerFrame = deviceSamplesPerFrame;
     }
 
+    virtual aaudio_result_t setOffloadDelayPadding(int32_t delayInFrames, int32_t paddingInFrames) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual int32_t getOffloadDelay() {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual int32_t getOffloadPadding() {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual aaudio_result_t setOffloadEndOfStream() EXCLUDES(mStreamLock) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual void setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) { }
+    virtual void setPresentationEndCallbackUserData(void* userData) { }
 
     /**
      * @return true if data callback has been specified
@@ -408,7 +426,7 @@
     /**
      * @return true if called from the same thread as the callback
      */
-    bool collidesWithCallback() const;
+    virtual bool collidesWithCallback() const;
 
     // Implement AudioDeviceCallback
     void onAudioDeviceUpdate(audio_io_handle_t audioIo,
@@ -649,6 +667,8 @@
 
     aaudio_result_t joinThread_l(void **returnArg) REQUIRES(mStreamLock);
 
+    virtual aaudio_result_t systemStopInternal_l() REQUIRES(mStreamLock);
+
     std::atomic<bool>    mCallbackEnabled{false};
 
     float                mDuckAndMuteVolume = 1.0f;
@@ -742,6 +762,8 @@
         mAudioBalance = audioBalance;
     }
 
+    aaudio_result_t safeStop_l() REQUIRES(mStreamLock);
+
     std::string mMetricsId; // set once during open()
 
     std::mutex                 mStreamLock;
@@ -750,8 +772,6 @@
 
 private:
 
-    aaudio_result_t safeStop_l() REQUIRES(mStreamLock);
-
     /**
      * Release then close the stream.
      */
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 73bd69f..61881cb 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -174,6 +174,11 @@
               __func__);
         allowMMap = false;
     }
+    if (!audio_is_linear_pcm(getFormat())) {
+        ALOGD("%s() MMAP not used because the requested format(%#x) is not pcm",
+              __func__, getFormat());
+        allowMMap = false;
+    }
 
     // SessionID and Effects are only supported in Legacy mode.
     if (getSessionId() != AAUDIO_SESSION_ID_NONE) {
@@ -261,6 +266,14 @@
         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
             break;
+        case AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED:
+            if (getDirection() != AAUDIO_DIRECTION_OUTPUT ||
+                getFormat() == AUDIO_FORMAT_DEFAULT ||
+                getSampleRate() == 0 ||
+                getChannelMask() == AAUDIO_UNSPECIFIED) {
+                return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            }
+            break;
         default:
             ALOGE("illegal performanceMode = %d", mPerformanceMode);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index f91c25a..d0678ae 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -89,6 +89,24 @@
         return mErrorCallbackUserData;
     }
 
+    AudioStreamBuilder* setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) {
+        mPresentationEndCallbackProc = proc;
+        return this;
+    }
+
+    AAudioStream_presentationEndCallback getPresentationEndCallbackProc() const {
+        return mPresentationEndCallbackProc;
+    }
+
+    AudioStreamBuilder* setPresentationEndCallbackUserData(void *userData) {
+        mPresentationEndCallbackUserData = userData;
+        return this;
+    }
+
+    void *getPresentationEndCallbackUserData() const {
+        return mPresentationEndCallbackUserData;
+    }
+
     int32_t getFramesPerDataCallback() const {
         return mFramesPerDataCallback;
     }
@@ -128,6 +146,9 @@
     AAudioStream_errorCallback mErrorCallbackProc = nullptr;
     void                      *mErrorCallbackUserData = nullptr;
 
+    AAudioStream_presentationEndCallback mPresentationEndCallbackProc = nullptr;
+    void                                *mPresentationEndCallbackUserData = nullptr;
+
     enum {
         PRIVACY_SENSITIVE_DEFAULT = -1,
         PRIVACY_SENSITIVE_DISABLED = 0,
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 2e57f0d..da15563 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -22,6 +22,7 @@
 #include <media/AudioTrack.h>
 
 #include <aaudio/AAudio.h>
+#include <com_android_media_aaudio.h>
 #include <system/audio.h>
 
 #include "core/AudioGlobal.h"
@@ -56,6 +57,10 @@
 
 aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
 {
+    if (!com::android::media::aaudio::offload_support() &&
+        builder.getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
     aaudio_result_t result = AAUDIO_OK;
 
     result = AudioStream::open(builder);
@@ -152,6 +157,34 @@
     if (tags.has_value() && !tags.value().empty()) {
         strcpy(attributes.tags, tags.value().c_str());
     }
+
+    audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+    if (getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+        config.format = format;
+        config.channel_mask = channelMask;
+        config.sample_rate = getSampleRate();
+        audio_direct_mode_t directMode = AUDIO_DIRECT_NOT_SUPPORTED;
+        if (status_t status = AudioSystem::getDirectPlaybackSupport(
+                &attributes, &config, &directMode);
+            status != NO_ERROR) {
+            ALOGE("%s, failed to query direct support, error=%d", __func__, status);
+            return status;
+        }
+        static const audio_direct_mode_t offloadMode = static_cast<audio_direct_mode_t>(
+                AUDIO_DIRECT_OFFLOAD_SUPPORTED | AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED);
+        if ((directMode & offloadMode) == AUDIO_DIRECT_NOT_SUPPORTED) {
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+        }
+        flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+        frameCount = 0;
+        offloadInfo.format = format;
+        offloadInfo.sample_rate = getSampleRate();
+        offloadInfo.channel_mask = channelMask;
+        offloadInfo.has_video = false;
+        offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+    }
+
     mAudioTrack = new AudioTrack();
     // TODO b/182392769: use attribution source util
     mAudioTrack->set(
@@ -167,7 +200,8 @@
             false,   // DEFAULT threadCanCallJava
             sessionId,
             streamTransferType,
-            nullptr,    // DEFAULT audio_offload_info_t
+            getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED
+                    ? &offloadInfo : nullptr,
             AttributionSourceState(), // DEFAULT uid and pid
             &attributes,
             // WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
@@ -247,7 +281,9 @@
     audio_output_flags_t actualFlags = mAudioTrack->getFlags();
     aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
     // We may not get the RAW flag. But as long as we get the FAST flag we can call it LOW_LATENCY.
-    if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
+    if ((actualFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != AUDIO_OUTPUT_FLAG_NONE) {
+        actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED;
+    } else if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
         actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
     } else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
         actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
@@ -347,6 +383,7 @@
         setState(originalState);
         return AAudioConvert_androidToAAudioResult(err);
     }
+    mOffloadEosPending = false;
     return AAUDIO_OK;
 }
 
@@ -430,6 +467,12 @@
         break;
     case AAUDIO_STREAM_STATE_STOPPING:
         if (mAudioTrack->stopped()) {
+            if (getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+                std::lock_guard<std::mutex> lock(mStreamLock);
+                if (!mOffloadEosPending) {
+                    break;
+                }
+            }
             setState(AAUDIO_STREAM_STATE_STOPPED);
         }
         break;
@@ -579,6 +622,104 @@
     mAudioTrack->setPlayerIId(mPlayerBase->getPlayerIId());
 }
 
+aaudio_result_t AudioStreamTrack::systemStopInternal_l() {
+    if (aaudio_result_t result = AudioStream::systemStopInternal_l(); result != AAUDIO_OK) {
+        return result;
+    }
+    mOffloadEosPending = false;
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::setOffloadDelayPadding(
+        int32_t delayInFrames, int32_t paddingInFrames) {
+    if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+        audio_is_linear_pcm(getFormat())) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+    if (mAudioTrack == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES),  delayInFrames);
+    param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES),  paddingInFrames);
+    mAudioTrack->setParameters(param.toString());
+    mOffloadDelayFrames.store(delayInFrames);
+    mOffloadPaddingFrames.store(paddingInFrames);
+    return AAUDIO_OK;
+}
+
+int32_t AudioStreamTrack::getOffloadDelay() {
+    if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+        audio_is_linear_pcm(getFormat())) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+    if (mAudioTrack == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    return mOffloadDelayFrames.load();
+}
+
+int32_t AudioStreamTrack::getOffloadPadding() {
+    if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+        audio_is_linear_pcm(getFormat())) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+    if (mAudioTrack == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    return mOffloadPaddingFrames.load();
+}
+
+aaudio_result_t AudioStreamTrack::setOffloadEndOfStream() {
+    if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+    if (mAudioTrack == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    std::lock_guard<std::mutex> lock(mStreamLock);
+    if (aaudio_result_t result = safeStop_l(); result != AAUDIO_OK) {
+        return result;
+    }
+    mOffloadEosPending = true;
+    return AAUDIO_OK;
+}
+
+bool AudioStreamTrack::collidesWithCallback() const {
+    if (AudioStream::collidesWithCallback()) {
+        return true;
+    }
+    pid_t thisThread = gettid();
+    return mPresentationEndCallbackThread.load() == thisThread;
+}
+
+void AudioStreamTrack::onStreamEnd() {
+    if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+        return;
+    }
+    if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
+        std::lock_guard<std::mutex> lock(mStreamLock);
+        if (mOffloadEosPending) {
+            requestStart_l();
+        }
+        mOffloadEosPending = false;
+    }
+    maybeCallPresentationEndCallback();
+}
+
+void AudioStreamTrack::maybeCallPresentationEndCallback() {
+    if (mPresentationEndCallbackProc != nullptr) {
+        pid_t expected = CALLBACK_THREAD_NONE;
+        if (mPresentationEndCallbackThread.compare_exchange_strong(expected, gettid())) {
+            (*mPresentationEndCallbackProc)(
+                    (AAudioStream *) this, mPresentationEndCallbackUserData);
+            mPresentationEndCallbackThread.store(CALLBACK_THREAD_NONE);
+        } else {
+            ALOGW("%s() error callback already running!", __func__);
+        }
+    }
+}
+
 #if AAUDIO_USE_VOLUME_SHAPER
 
 using namespace android::media::VolumeShaper;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 05609c4..82ba772 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -49,6 +49,11 @@
     aaudio_result_t requestPause_l() REQUIRES(mStreamLock) override;
     aaudio_result_t requestFlush_l() REQUIRES(mStreamLock) override;
     aaudio_result_t requestStop_l() REQUIRES(mStreamLock) override;
+    aaudio_result_t systemStopInternal_l() REQUIRES(mStreamLock) final;
+
+    bool collidesWithCallback() const final;
+
+    void onStreamEnd() final;
 
 public:
     bool isFlushSupported() const override {
@@ -89,6 +94,26 @@
 
     void registerPlayerBase() override;
 
+    // Offload begin --------------------------------------
+    aaudio_result_t setOffloadDelayPadding(int32_t delayInFrames, int32_t paddingInFrames) final;
+
+    int32_t getOffloadDelay() final;
+
+    int32_t getOffloadPadding() final;
+
+    aaudio_result_t setOffloadEndOfStream() EXCLUDES(mStreamLock) final;
+
+    void setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) final {
+        mPresentationEndCallbackProc = proc;
+    }
+
+    virtual void setPresentationEndCallbackUserData(void *userData) final {
+        mPresentationEndCallbackUserData = userData;
+    }
+
+    void maybeCallPresentationEndCallback();
+    // Offload end ----------------------------------------
+
 #if AAUDIO_USE_VOLUME_SHAPER
     virtual android::binder::Status applyVolumeShaper(
             const android::media::VolumeShaper::Configuration& configuration,
@@ -110,6 +135,15 @@
 
     // TODO add 64-bit position reporting to AudioTrack and use it.
     aaudio_wrapping_frames_t         mPositionWhenPausing = 0;
+
+    // Offload --------------------------------------------
+    std::atomic<int32_t>        mOffloadDelayFrames = 0;
+    std::atomic<int32_t>        mOffloadPaddingFrames = 0;
+    bool                        mOffloadEosPending GUARDED_BY(mStreamLock) = false;
+
+    AAudioStream_presentationEndCallback mPresentationEndCallbackProc = nullptr;
+    void                                *mPresentationEndCallbackUserData = nullptr;
+    std::atomic<pid_t>                   mPresentationEndCallbackThread{CALLBACK_THREAD_NONE};
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
index 36d76aa..44bb4c6 100644
--- a/media/libaaudio/src/libaaudio.map.txt
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -28,6 +28,7 @@
     AAudioStreamBuilder_setChannelMask;    # introduced=32
     AAudioStreamBuilder_setSpatializationBehavior; # introduced=32
     AAudioStreamBuilder_setIsContentSpatialized;   # introduced=32
+    AAudioStreamBuilder_setPresentationEndCallback; #introduced=36
     AAudioStreamBuilder_openStream;
     AAudioStreamBuilder_delete;
     AAudioStream_close;
@@ -73,6 +74,10 @@
     AAudio_getPlatformMMapPolicy; # introduced=36
     AAudio_getPlatformMMapExclusivePolicy; #introduced=36
     AAudioStream_getDeviceIds; # introduced=36
+    AAudioStream_setOffloadDelayPadding; #introduced=36
+    AAudioStream_getOffloadDelay; #introduced=36
+    AAudioStream_getOffloadPadding; #introduced=36
+    AAudioStream_setOffloadEndOfStream; #introduced=36
 
     AAudioStreamBuilder_setTags; # systemapi
     AAudioStream_getTags; # systemapi
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index c741946..873fcba 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -147,6 +147,27 @@
     case AAUDIO_FORMAT_IEC61937:
         androidFormat = AUDIO_FORMAT_IEC61937;
         break;
+    case AAUDIO_FORMAT_MP3:
+        androidFormat = AUDIO_FORMAT_MP3;
+        break;
+    case AAUDIO_FORMAT_AAC_LC:
+        androidFormat = AUDIO_FORMAT_AAC_LC;
+        break;
+    case AAUDIO_FORMAT_AAC_HE_V1:
+        androidFormat = AUDIO_FORMAT_AAC_HE_V1;
+        break;
+    case AAUDIO_FORMAT_AAC_HE_V2:
+        androidFormat = AUDIO_FORMAT_AAC_HE_V2;
+        break;
+    case AAUDIO_FORMAT_AAC_ELD:
+        androidFormat = AUDIO_FORMAT_AAC_ELD;
+        break;
+    case AAUDIO_FORMAT_AAC_XHE:
+        androidFormat = AUDIO_FORMAT_AAC_XHE;
+        break;
+    case AAUDIO_FORMAT_OPUS:
+        androidFormat = AUDIO_FORMAT_OPUS;
+        break;
     default:
         androidFormat = AUDIO_FORMAT_INVALID;
         ALOGE("%s() 0x%08X unrecognized", __func__, aaudioFormat);
@@ -176,6 +197,27 @@
     case AUDIO_FORMAT_IEC61937:
         aaudioFormat = AAUDIO_FORMAT_IEC61937;
         break;
+    case AUDIO_FORMAT_MP3:
+        aaudioFormat = AAUDIO_FORMAT_MP3;
+        break;
+    case AUDIO_FORMAT_AAC_LC:
+        aaudioFormat = AAUDIO_FORMAT_AAC_LC;
+        break;
+    case AUDIO_FORMAT_AAC_HE_V1:
+        aaudioFormat = AAUDIO_FORMAT_AAC_HE_V1;
+        break;
+    case AUDIO_FORMAT_AAC_HE_V2:
+        aaudioFormat = AAUDIO_FORMAT_AAC_HE_V2;
+        break;
+    case AUDIO_FORMAT_AAC_ELD:
+        aaudioFormat = AAUDIO_FORMAT_AAC_ELD;
+        break;
+    case AUDIO_FORMAT_AAC_XHE:
+        aaudioFormat = AAUDIO_FORMAT_AAC_XHE;
+        break;
+    case AUDIO_FORMAT_OPUS:
+        aaudioFormat = AAUDIO_FORMAT_OPUS;
+        break;
     default:
         aaudioFormat = AAUDIO_FORMAT_INVALID;
         ALOGE("%s() 0x%08X unrecognized", __func__, androidFormat);
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index d5069f5..940e4b5 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -373,4 +373,6 @@
 aaudio_policy_t AAudioConvert_androidToAAudioMMapPolicy(
         android::media::audio::common::AudioMMapPolicy policy);
 
+bool AAudio_isCompressedFormat(audio_format_t format);
+
 #endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 61204ae..6dfb327 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -359,6 +359,8 @@
         "aidl/android/media/AudioMixerBehavior.aidl",
         "aidl/android/media/AudioOffloadMode.aidl",
         "aidl/android/media/AudioPolicyDeviceState.aidl",
+        "aidl/android/media/AudioPolicyForceUse.aidl",
+        "aidl/android/media/AudioPolicyForcedConfig.aidl",
         "aidl/android/media/AudioProductStrategy.aidl",
         "aidl/android/media/AudioVolumeGroup.aidl",
         "aidl/android/media/DeviceRole.aidl",
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cfa3011..dcfef45 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -62,8 +62,6 @@
 using media::audio::common::AudioMMapPolicyInfo;
 using media::audio::common::AudioMMapPolicyType;
 using media::audio::common::AudioOffloadInfo;
-using media::audio::common::AudioPolicyForceUse;
-using media::audio::common::AudioPolicyForcedConfig;
 using media::audio::common::AudioSource;
 using media::audio::common::AudioStreamType;
 using media::audio::common::AudioUsage;
@@ -1193,9 +1191,9 @@
     if (aps == nullptr) return AUDIO_POLICY_FORCE_NONE;
 
     auto result = [&]() -> ConversionResult<audio_policy_forced_cfg_t> {
-        AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
+        media::AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
                 legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(usage));
-        AudioPolicyForcedConfig configAidl;
+        media::AudioPolicyForcedConfig configAidl;
         RETURN_IF_ERROR(statusTFromBinderStatus(
                 aps->getForceUse(usageAidl, &configAidl)));
         return aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(configAidl);
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index a414cb7..163a359 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -296,6 +296,138 @@
     return unexpected(BAD_VALUE);
 }
 
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl) {
+    switch (aidl) {
+        case media::AudioPolicyForceUse::COMMUNICATION:
+            return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
+        case media::AudioPolicyForceUse::MEDIA:
+            return AUDIO_POLICY_FORCE_FOR_MEDIA;
+        case media::AudioPolicyForceUse::RECORD:
+            return AUDIO_POLICY_FORCE_FOR_RECORD;
+        case media::AudioPolicyForceUse::DOCK:
+            return AUDIO_POLICY_FORCE_FOR_DOCK;
+        case media::AudioPolicyForceUse::SYSTEM:
+            return AUDIO_POLICY_FORCE_FOR_SYSTEM;
+        case media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
+            return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
+        case media::AudioPolicyForceUse::ENCODED_SURROUND:
+            return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
+        case media::AudioPolicyForceUse::VIBRATE_RINGING:
+            return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
+    switch (legacy) {
+        case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
+            return media::AudioPolicyForceUse::COMMUNICATION;
+        case AUDIO_POLICY_FORCE_FOR_MEDIA:
+            return media::AudioPolicyForceUse::MEDIA;
+        case AUDIO_POLICY_FORCE_FOR_RECORD:
+            return media::AudioPolicyForceUse::RECORD;
+        case AUDIO_POLICY_FORCE_FOR_DOCK:
+            return media::AudioPolicyForceUse::DOCK;
+        case AUDIO_POLICY_FORCE_FOR_SYSTEM:
+            return media::AudioPolicyForceUse::SYSTEM;
+        case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
+            return media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
+        case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
+            return media::AudioPolicyForceUse::ENCODED_SURROUND;
+        case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
+            return media::AudioPolicyForceUse::VIBRATE_RINGING;
+        case AUDIO_POLICY_FORCE_USE_CNT:
+            break;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl) {
+    switch (aidl) {
+        case media::AudioPolicyForcedConfig::NONE:
+            return AUDIO_POLICY_FORCE_NONE;
+        case media::AudioPolicyForcedConfig::SPEAKER:
+            return AUDIO_POLICY_FORCE_SPEAKER;
+        case media::AudioPolicyForcedConfig::HEADPHONES:
+            return AUDIO_POLICY_FORCE_HEADPHONES;
+        case media::AudioPolicyForcedConfig::BT_SCO:
+            return AUDIO_POLICY_FORCE_BT_SCO;
+        case media::AudioPolicyForcedConfig::BT_A2DP:
+            return AUDIO_POLICY_FORCE_BT_A2DP;
+        case media::AudioPolicyForcedConfig::WIRED_ACCESSORY:
+            return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+        case media::AudioPolicyForcedConfig::BT_CAR_DOCK:
+            return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
+        case media::AudioPolicyForcedConfig::BT_DESK_DOCK:
+            return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
+        case media::AudioPolicyForcedConfig::ANALOG_DOCK:
+            return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+        case media::AudioPolicyForcedConfig::DIGITAL_DOCK:
+            return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+        case media::AudioPolicyForcedConfig::NO_BT_A2DP:
+            return AUDIO_POLICY_FORCE_NO_BT_A2DP;
+        case media::AudioPolicyForcedConfig::SYSTEM_ENFORCED:
+            return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
+        case media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
+            return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
+        case media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
+        case media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
+        case media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
+        case media::AudioPolicyForcedConfig::BT_BLE:
+            return AUDIO_POLICY_FORCE_BT_BLE;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
+    switch (legacy) {
+        case AUDIO_POLICY_FORCE_NONE:
+            return media::AudioPolicyForcedConfig::NONE;
+        case AUDIO_POLICY_FORCE_SPEAKER:
+            return media::AudioPolicyForcedConfig::SPEAKER;
+        case AUDIO_POLICY_FORCE_HEADPHONES:
+            return media::AudioPolicyForcedConfig::HEADPHONES;
+        case AUDIO_POLICY_FORCE_BT_SCO:
+            return media::AudioPolicyForcedConfig::BT_SCO;
+        case AUDIO_POLICY_FORCE_BT_A2DP:
+            return media::AudioPolicyForcedConfig::BT_A2DP;
+        case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
+            return media::AudioPolicyForcedConfig::WIRED_ACCESSORY;
+        case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
+            return media::AudioPolicyForcedConfig::BT_CAR_DOCK;
+        case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
+            return media::AudioPolicyForcedConfig::BT_DESK_DOCK;
+        case AUDIO_POLICY_FORCE_ANALOG_DOCK:
+            return media::AudioPolicyForcedConfig::ANALOG_DOCK;
+        case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
+            return media::AudioPolicyForcedConfig::DIGITAL_DOCK;
+        case AUDIO_POLICY_FORCE_NO_BT_A2DP:
+            return media::AudioPolicyForcedConfig::NO_BT_A2DP;
+        case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
+            return media::AudioPolicyForcedConfig::SYSTEM_ENFORCED;
+        case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
+            return media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
+        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
+            return media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
+        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
+            return media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
+        case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
+            return media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
+        case AUDIO_POLICY_FORCE_BT_BLE:
+            return media::AudioPolicyForcedConfig::BT_BLE;
+        case AUDIO_POLICY_FORCE_CFG_CNT:
+            break;
+    }
+    return unexpected(BAD_VALUE);
+}
+
 ConversionResult<device_role_t>
 aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl) {
     switch (aidl) {
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
new file mode 100644
index 0000000..9bb0605
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+/**
+ * {@hide}
+ */
+@Backing(type="int")
+enum AudioPolicyForceUse {
+    COMMUNICATION = 0,
+    MEDIA = 1,
+    RECORD = 2,
+    DOCK = 3,
+    SYSTEM = 4,
+    HDMI_SYSTEM_AUDIO = 5,
+    ENCODED_SURROUND = 6,
+    VIBRATE_RINGING = 7,
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
new file mode 100644
index 0000000..111bb2f
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+/**
+ * {@hide}
+ */
+@Backing(type="int")
+enum AudioPolicyForcedConfig {
+    NONE = 0,
+    SPEAKER = 1,
+    HEADPHONES = 2,
+    BT_SCO = 3,
+    BT_A2DP = 4,
+    WIRED_ACCESSORY = 5,
+    BT_CAR_DOCK = 6,
+    BT_DESK_DOCK = 7,
+    ANALOG_DOCK = 8,
+    DIGITAL_DOCK = 9,
+    NO_BT_A2DP = 10, /* A2DP sink is not preferred to speaker or wired HS */
+    SYSTEM_ENFORCED = 11,
+    HDMI_SYSTEM_AUDIO_ENFORCED = 12,
+    ENCODED_SURROUND_NEVER = 13,
+    ENCODED_SURROUND_ALWAYS = 14,
+    ENCODED_SURROUND_MANUAL = 15,
+    BT_BLE = 16,
+}
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 7f4a7dd..fab2d95 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -25,6 +25,8 @@
 import android.media.AudioOffloadMode;
 import android.media.AudioPatchFw;
 import android.media.AudioPolicyDeviceState;
+import android.media.AudioPolicyForcedConfig;
+import android.media.AudioPolicyForceUse;
 import android.media.AudioPortFw;
 import android.media.AudioPortConfigFw;
 import android.media.AudioPortRole;
@@ -49,8 +51,6 @@
 import android.media.audio.common.AudioMMapPolicyInfo;
 import android.media.audio.common.AudioMMapPolicyType;
 import android.media.audio.common.AudioMode;
-import android.media.audio.common.AudioPolicyForcedConfig;
-import android.media.audio.common.AudioPolicyForceUse;
 import android.media.audio.common.AudioProfile;
 import android.media.audio.common.AudioOffloadInfo;
 import android.media.audio.common.AudioPort;
diff --git a/media/libaudioclient/aidl/fuzzer/Android.bp b/media/libaudioclient/aidl/fuzzer/Android.bp
index 14e528f..05db9e5 100644
--- a/media/libaudioclient/aidl/fuzzer/Android.bp
+++ b/media/libaudioclient/aidl/fuzzer/Android.bp
@@ -22,7 +22,7 @@
     name: "libaudioclient_aidl_fuzzer_defaults",
     static_libs: [
         "android.hardware.audio.common@7.0-enums",
-        "audiopermissioncontroller",
+        "libaudiopermission",
         "libaudiomockhal",
         "libfakeservicemanager",
         "libjsoncpp",
diff --git a/media/libaudioclient/include/media/PolicyAidlConversion.h b/media/libaudioclient/include/media/PolicyAidlConversion.h
index 1b90d6b..ed9ddd6 100644
--- a/media/libaudioclient/include/media/PolicyAidlConversion.h
+++ b/media/libaudioclient/include/media/PolicyAidlConversion.h
@@ -28,6 +28,8 @@
 #include <android/media/AudioMixRouteFlag.h>
 #include <android/media/AudioMixType.h>
 #include <android/media/AudioOffloadMode.h>
+#include <android/media/AudioPolicyForceUse.h>
+#include <android/media/AudioPolicyForcedConfig.h>
 #include <android/media/DeviceRole.h>
 
 #include <media/AidlConversionUtil.h>
@@ -82,6 +84,16 @@
 ConversionResult<media::AudioPolicyDeviceState>
 legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(audio_policy_dev_state_t legacy);
 
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl);
+ConversionResult<media::AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
+
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl);
+ConversionResult<media::AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
+
 ConversionResult<device_role_t>
 aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl);
 ConversionResult<media::DeviceRole>
diff --git a/services/audiopolicy/permission/Android.bp b/media/libaudiopermission/Android.bp
similarity index 92%
rename from services/audiopolicy/permission/Android.bp
rename to media/libaudiopermission/Android.bp
index cfbeaae..7275fd7 100644
--- a/services/audiopolicy/permission/Android.bp
+++ b/media/libaudiopermission/Android.bp
@@ -4,13 +4,13 @@
 }
 
 cc_library_headers {
-    name: "audiopermissioncontroller_headers",
+    name: "libaudiopermission_headers",
     host_supported: true,
     export_include_dirs: ["include"],
 }
 
 cc_library {
-    name: "audiopermissioncontroller",
+    name: "libaudiopermission",
 
     srcs: [
         "NativePermissionController.cpp",
@@ -83,14 +83,14 @@
 }
 
 cc_test {
-    name: "audiopermissioncontroller_test",
+    name: "libaudiopermission_test",
     host_supported: true,
     defaults: [
         "libmediautils_tests_config",
     ],
     static_libs: [
         "audio-permission-aidl-cpp",
-        "audiopermissioncontroller",
+        "libaudiopermission",
         "framework-permission-aidl-cpp",
         "libgmock",
     ],
diff --git a/services/audiopolicy/permission/NativePermissionController.cpp b/media/libaudiopermission/NativePermissionController.cpp
similarity index 100%
rename from services/audiopolicy/permission/NativePermissionController.cpp
rename to media/libaudiopermission/NativePermissionController.cpp
diff --git a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp b/media/libaudiopermission/ValidatedAttributionSourceState.cpp
similarity index 100%
rename from services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
rename to media/libaudiopermission/ValidatedAttributionSourceState.cpp
diff --git a/services/audiopolicy/permission/include/media/IPermissionProvider.h b/media/libaudiopermission/include/media/IPermissionProvider.h
similarity index 100%
rename from services/audiopolicy/permission/include/media/IPermissionProvider.h
rename to media/libaudiopermission/include/media/IPermissionProvider.h
diff --git a/services/audiopolicy/permission/include/media/NativePermissionController.h b/media/libaudiopermission/include/media/NativePermissionController.h
similarity index 100%
rename from services/audiopolicy/permission/include/media/NativePermissionController.h
rename to media/libaudiopermission/include/media/NativePermissionController.h
diff --git a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h b/media/libaudiopermission/include/media/ValidatedAttributionSourceState.h
similarity index 100%
rename from services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
rename to media/libaudiopermission/include/media/ValidatedAttributionSourceState.h
diff --git a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp b/media/libaudiopermission/tests/NativePermissionControllerTest.cpp
similarity index 100%
rename from services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
rename to media/libaudiopermission/tests/NativePermissionControllerTest.cpp
diff --git a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp b/media/libaudiopermission/tests/ValidatedAttributionSourceStateTest.cpp
similarity index 100%
rename from services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
rename to media/libaudiopermission/tests/ValidatedAttributionSourceStateTest.cpp
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index d5d1a09..3834278 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -26,6 +26,9 @@
 
 namespace android {
 
+// initialize max supported instances with default value.
+int32_t MediaCodecInfo::sMaxSupportedInstances = 0;
+
 /** This redundant redeclaration is needed for C++ pre 14 */
 constexpr char MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK[];
 constexpr char MediaCodecInfo::Capabilities::FEATURE_DYNAMIC_TIMESTAMP[];
@@ -169,6 +172,15 @@
     return NULL;
 }
 
+const std::shared_ptr<CodecCapabilities> MediaCodecInfo::getCodecCapsFor(
+        const char *mediaType) const {
+    ssize_t ix = getCodecCapIndex(mediaType);
+    if (ix >= 0) {
+        return mCodecCaps.valueAt(ix);
+    }
+    return nullptr;
+}
+
 const char *MediaCodecInfo::getCodecName() const {
     return mName.c_str();
 }
@@ -179,6 +191,7 @@
 
 // static
 sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
+    sMaxSupportedInstances = parcel.readInt32();
     AString name = AString::FromParcel(parcel);
     AString owner = AString::FromParcel(parcel);
     Attributes attributes = static_cast<Attributes>(parcel.readInt32());
@@ -201,12 +214,17 @@
             return NULL;
         if (info != NULL) {
             info->mCaps.add(mediaType, caps);
+            std::shared_ptr<CodecCapabilities> codecCaps
+                    = MediaCodecInfoWriter::BuildCodecCapabilities(
+                            mediaType.c_str(), caps, info->isEncoder());
+            info->mCodecCaps.add(mediaType, codecCaps);
         }
     }
     return info;
 }
 
 status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
+    parcel->writeInt32(sMaxSupportedInstances);
     mName.writeToParcel(parcel);
     mOwner.writeToParcel(parcel);
     parcel->writeInt32(mAttributes);
@@ -234,6 +252,25 @@
     return -1;
 }
 
+ssize_t MediaCodecInfo::getCodecCapIndex(const char *mediaType) const {
+    if (mediaType == nullptr) {
+        return -1;
+    }
+
+    if (mCodecCaps.size() != mCaps.size()) {
+        ALOGE("Size of mCodecCaps and mCaps do not match, which are %zu and %zu",
+                mCodecCaps.size(), mCaps.size());
+    }
+
+    for (size_t ix = 0; ix < mCodecCaps.size(); ix++) {
+        if (mCodecCaps.keyAt(ix).equalsIgnoreCase(mediaType)) {
+            return ix;
+        }
+    }
+
+    return -1;
+}
+
 MediaCodecInfo::MediaCodecInfo()
     : mAttributes((MediaCodecInfo::Attributes)0),
       mRank(0x100) {
@@ -283,6 +320,52 @@
     return false;
 }
 
+void MediaCodecInfoWriter::createCodecCaps() {
+    mInfo->mCodecCaps.clear();
+    for (size_t ix = 0; ix < mInfo->mCaps.size(); ix++) {
+        AString mediaType = mInfo->mCaps.keyAt(ix);
+        sp<MediaCodecInfo::Capabilities> caps = mInfo->mCaps.valueAt(ix);
+        mInfo->mCodecCaps.add(mediaType,
+                BuildCodecCapabilities(mediaType.c_str(), caps, mInfo->isEncoder(),
+                MediaCodecInfo::sMaxSupportedInstances));
+    }
+}
+
+// static
+std::shared_ptr<CodecCapabilities> MediaCodecInfoWriter::BuildCodecCapabilities(
+        const char *mediaType, sp<MediaCodecInfo::Capabilities> caps, bool isEncoder,
+        int32_t maxSupportedInstances) {
+    Vector<ProfileLevel> profileLevels_;
+    Vector<uint32_t> colorFormats_;
+    caps->getSupportedProfileLevels(&profileLevels_);
+    caps->getSupportedColorFormats(&colorFormats_);
+
+    std::vector<ProfileLevel> profileLevels;
+    std::vector<uint32_t> colorFormats;
+    for (ProfileLevel pl : profileLevels_) {
+        profileLevels.push_back(pl);
+    }
+    for (uint32_t cf : colorFormats_) {
+        colorFormats.push_back(cf);
+    }
+
+    sp<AMessage> defaultFormat = new AMessage();
+    defaultFormat->setString("mime", mediaType);
+
+    sp<AMessage> capabilitiesInfo = caps->getDetails();
+
+    std::shared_ptr<CodecCapabilities> codecCaps = std::make_shared<CodecCapabilities>();
+    codecCaps->init(profileLevels, colorFormats, isEncoder, defaultFormat,
+            capabilitiesInfo, maxSupportedInstances);
+
+    return codecCaps;
+}
+
+// static
+void MediaCodecInfoWriter::SetMaxSupportedInstances(int32_t maxSupportedInstances) {
+    MediaCodecInfo::sMaxSupportedInstances = maxSupportedInstances;
+}
+
 MediaCodecInfoWriter::MediaCodecInfoWriter(MediaCodecInfo* info) :
     mInfo(info) {
 }
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index 72aca98..60e383a 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -192,6 +192,7 @@
     Attributes getAttributes() const;
     void getSupportedMediaTypes(Vector<AString> *mediaTypes) const;
     const sp<Capabilities> getCapabilitiesFor(const char *mediaType) const;
+    const std::shared_ptr<CodecCapabilities> getCodecCapsFor(const char *mediaType) const;
     const char *getCodecName() const;
 
     /**
@@ -229,14 +230,21 @@
     status_t writeToParcel(Parcel *parcel) const;
 
 private:
+    /**
+     * Max supported instances setting from MediaCodecList global setting.
+     */
+    static int32_t sMaxSupportedInstances;
+
     AString mName;
     AString mOwner;
     Attributes mAttributes;
     KeyedVector<AString, sp<Capabilities> > mCaps;
+    KeyedVector<AString, std::shared_ptr<CodecCapabilities>> mCodecCaps;
     Vector<AString> mAliases;
     uint32_t mRank;
 
     ssize_t getCapabilityIndex(const char *mediaType) const;
+    ssize_t getCodecCapIndex(const char *mediaType) const;
 
     /**
      * Construct an `MediaCodecInfo` object. After the construction, its
@@ -264,6 +272,15 @@
  */
 struct MediaCodecInfoWriter {
     /**
+     * Get CodecCapabilities from Capabilities.
+     */
+    static std::shared_ptr<CodecCapabilities> BuildCodecCapabilities(const char *mediaType,
+            sp<MediaCodecInfo::Capabilities> caps, bool isEncoder, int maxSupportedInstances = 0);
+    /**
+     * Set the max supported instances global setting from MediaCodecList.
+     */
+    static void SetMaxSupportedInstances(int32_t maxSupportedInstances);
+    /**
      * Set the name of the codec.
      *
      * @param name The new name.
@@ -319,6 +336,10 @@
      * @param rank The rank of the component.
      */
     void setRank(uint32_t rank);
+    /**
+     * Create CodecCapabilities map from Capabilities.
+     */
+    void createCodecCaps();
 private:
     /**
      * The associated `MediaCodecInfo`.
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 79ffdeb..1cb8f14 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -21,6 +21,8 @@
 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
 #endif
 
+#include <cstdlib>
+
 #include <android-base/properties.h>
 #include <utils/Log.h>
 
@@ -131,6 +133,10 @@
     for (const auto& p : serviceAttributes) {
         writer->addGlobalSetting(
                 p.key.c_str(), p.value.c_str());
+        if (p.key == "max-concurrent-instances") {
+            MediaCodecInfoWriter::SetMaxSupportedInstances(
+                    (int32_t)strtol(p.value.c_str(), NULL, 10));
+        }
     }
 
     // Convert roles to lists of codecs
@@ -217,6 +223,8 @@
                 ALOGW("Fail to add media type %s to codec %s",
                         typeName.c_str(), nodeName.c_str());
                 info->removeMediaType(typeName.c_str());
+            } else {
+                info->createCodecCaps();
             }
         }
     }
diff --git a/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index d21908f..7905e4f 100644
--- a/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -458,6 +458,12 @@
 
     if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
         LOG(DEBUG) << "EOS from decoder.";
+        // NOTE - b/360057459
+        // There is a synchronization problem between feeding the frame to the encoder input surface
+        // and signaling end of stream.
+        // Waiting before signaling end of stream so that input surface has time to feed remaining
+        // frames to the encoder.
+        std::this_thread::sleep_for(std::chrono::milliseconds(10));
         media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
         if (status != AMEDIA_OK) {
             LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 01bde42..add8a43 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -149,7 +149,7 @@
         "audio-permission-aidl-cpp",
         "audioclient-types-aidl-cpp",
         "audioflinger-aidl-cpp",
-        "audiopermissioncontroller",
+        "libaudiopermission",
         "av-types-aidl-cpp",
         "com.android.media.audio-aconfig-cc",
         "com.android.media.audioserver-aconfig-cc",
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 33194b7..e5bd121 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -24,6 +24,7 @@
 #include <android/media/audio/common/AudioMMapPolicyType.h>
 #include <android/media/GetInputForAttrResponse.h>
 #include <android/content/AttributionSourceState.h>
+#include <error/BinderResult.h>
 #include <media/AudioCommonTypes.h>
 #include <media/AudioContainers.h>
 #include <media/AudioDeviceTypeAddr.h>
@@ -182,8 +183,7 @@
                                      audio_input_flags_t flags,
                                      audio_unique_id_t riid,
                                      audio_session_t session,
-                                     const AttributionSourceState& attributionSource,
-                                     input_type_t *inputType /* out param */) = 0;
+                                     const AttributionSourceState& attributionSource) = 0;
     // indicates to the audio policy manager that the input starts being used.
     virtual status_t startInput(audio_port_handle_t portId) = 0;
     // indicates to the audio policy manager that the input stops being used.
@@ -636,6 +636,32 @@
     virtual status_t getMmapPolicyInfos(
             media::audio::common::AudioMMapPolicyType policyType,
             std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) = 0;
+
+    enum class MixType {
+        // e.g. audio recording from a microphone
+        NONE = 0,
+        // used for "remote submix" legacy mode (no DAP), capture of the media to play it remotely
+        CAPTURE,
+        // used for platform audio rerouting, where mixes are handled by external and dynamically
+        // installed policies which reroute audio mixes
+        EXT_POLICY_REROUTE,
+        // used for playback capture with a MediaProjection
+        PUBLIC_CAPTURE_PLAYBACK,
+        // used for capture from telephony RX path
+        TELEPHONY_RX_CAPTURE,
+    };
+
+    struct PermissionReqs {
+        media::audio::common::AudioSource source;
+        MixType mixType;
+        uint32_t virtualDeviceId;
+        // Flag based validation
+        bool isHotword;
+        bool isCallRedir;
+    };
+
+    virtual error::BinderResult<bool> checkPermissionForInput(const AttributionSourceState& attr,
+                                                              const PermissionReqs& req) = 0;
 };
 
     // These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
index dc2517b..424c983 100644
--- a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
+++ b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
@@ -19,76 +19,77 @@
     <criterion_type name="OutputDevicesAddressesType" type="inclusive">
         <values>
             <!-- legacy remote submix -->
-            <value literal="0" numerical="1"/>
+            <value literal="0"/>
         </values>
     </criterion_type>
     <criterion_type name="InputDevicesAddressesType" type="inclusive">
         <values>
             <!-- legacy remote submix -->
-            <value literal="0" numerical="1"/>
+            <value literal="0"/>
         </values>
     </criterion_type>
     <criterion_type name="AndroidModeType" type="exclusive"/>
     <criterion_type name="ForceUseForCommunicationType" type="exclusive">
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="SPEAKER" numerical="1"/>
-            <value literal="BT_SCO" numerical="3"/>
+            <value literal="NONE"/>
+            <value literal="SPEAKER"/>
+            <value literal="BT_SCO"/>
         </values>
     </criterion_type>
     <criterion_type name="ForceUseForMediaType" type="exclusive">
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="SPEAKER" numerical="1"/>
-            <value literal="HEADPHONES" numerical="2"/>
-            <value literal="BT_A2DP" numerical="4"/>
-            <value literal="WIRED_ACCESSORY" numerical="5"/>
-            <value literal="ANALOG_DOCK" numerical="8"/>
-            <value literal="DIGITAL_DOCK" numerical="9"/>
-            <value literal="NO_BT_A2DP" numerical="10"/>
+            <value literal="NONE"/>
+            <value literal="SPEAKER"/>
+            <value literal="HEADPHONES"/>
+            <value literal="BT_A2DP"/>
+            <value literal="ANALOG_DOCK"/>
+            <value literal="DIGITAL_DOCK"/>
+            <value literal="WIRED_ACCESSORY"/>
+            <value literal="NO_BT_A2DP"/>
         </values>
     </criterion_type>
     <criterion_type name="ForceUseForRecordType" type="exclusive">
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="BT_SCO" numerical="3"/>
-            <value literal="WIRED_ACCESSORY" numerical="5"/>
+            <value literal="NONE"/>
+            <value literal="BT_SCO"/>
+            <value literal="WIRED_ACCESSORY"/>
         </values>
     </criterion_type>
     <criterion_type name="ForceUseForDockType" type="exclusive">
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="WIRED_ACCESSORY" numerical="5"/>
-            <value literal="BT_CAR_DOCK" numerical="6"/>
-            <value literal="BT_DESK_DOCK" numerical="7"/>
-            <value literal="ANALOG_DOCK" numerical="8"/>
-            <value literal="DIGITAL_DOCK" numerical="9"/>
+            <value literal="NONE"/>
+            <value literal="BT_CAR_DOCK"/>
+            <value literal="BT_DESK_DOCK"/>
+            <value literal="ANALOG_DOCK"/>
+            <value literal="DIGITAL_DOCK"/>
+            <value literal="WIRED_ACCESSORY"/>
         </values>
     </criterion_type>
     <criterion_type name="ForceUseForSystemType" type="exclusive" >
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="SYSTEM_ENFORCED" numerical="11"/>
+            <value literal="NONE"/>
+            <value literal="SYSTEM_ENFORCED"/>
         </values>
     </criterion_type>
     <criterion_type name="ForceUseForHdmiSystemAudioType" type="exclusive">
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="HDMI_SYSTEM_AUDIO_ENFORCED" numerical="12"/>
+            <value literal="NONE"/>
+            <value literal="HDMI_SYSTEM_AUDIO_ENFORCED"/>
         </values>
     </criterion_type>
     <criterion_type name="ForceUseForEncodedSurroundType" type="exclusive">
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="ENCODED_SURROUND_NEVER" numerical="13"/>
-            <value literal="ENCODED_SURROUND_ALWAYS" numerical="14"/>
-            <value literal="ENCODED_SURROUND_MANUAL" numerical="15"/>
+            <value literal="UNSPECIFIED"/>
+            <value literal="NEVER"/>
+            <value literal="ALWAYS"/>
+            <value literal="MANUAL"/>
         </values>
     </criterion_type>
     <criterion_type name="ForceUseForVibrateRingingType" type="exclusive">
         <values>
-            <value literal="NONE" numerical="0"/>
-            <value literal="BT_SCO" numerical="3"/>
+            <value literal="NONE"/>
+            <value literal="BT_SCO"/>
+            <value literal="BT_BLE"/>
         </values>
     </criterion_type>
 </criterion_types>
diff --git a/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
index b72e517..b89fba0 100644
--- a/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
+++ b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
@@ -41,21 +41,23 @@
 
 namespace android {
 
-using utilities::convertTo;
+using base::unexpected;
 using media::audio::common::AudioDeviceAddress;
 using media::audio::common::AudioDeviceDescription;
 using media::audio::common::AudioHalCapCriterion;
+using media::audio::common::AudioHalCapCriterionV2;
 using media::audio::common::AudioHalCapParameter;
 using media::audio::common::AudioHalCapRule;
+using media::audio::common::AudioPolicyForceUse;
 using media::audio::common::AudioSource;
 using media::audio::common::AudioStreamType;
-using media::audio::common::AudioHalCapCriterionV2;
-using ::android::base::unexpected;
+using utilities::convertTo;
 
 namespace capEngineConfig {
 
 static constexpr const char *gLegacyOutputDevicePrefix = "AUDIO_DEVICE_OUT_";
 static constexpr const char *gLegacyInputDevicePrefix = "AUDIO_DEVICE_IN_";
+static constexpr const char *gLegacyForcePrefix = "AUDIO_POLICY_FORCE_";
 static constexpr const char *gLegacyStreamPrefix = "AUDIO_STREAM_";
 static constexpr const char *gLegacySourcePrefix = "AUDIO_SOURCE_";
 static constexpr const char *gPolicyParamPrefix = "/Policy/policy/";
@@ -83,6 +85,134 @@
     return capName;
 }
 
+ConversionResult<audio_policy_forced_cfg_t>
+        aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+        const AudioPolicyForceUse::CommunicationDeviceCategory aidl) {
+    switch (aidl) {
+        case AudioPolicyForceUse::CommunicationDeviceCategory::NONE:
+            return AUDIO_POLICY_FORCE_NONE;
+        case AudioPolicyForceUse::CommunicationDeviceCategory::SPEAKER:
+            return AUDIO_POLICY_FORCE_SPEAKER;
+        case AudioPolicyForceUse::CommunicationDeviceCategory::BT_SCO:
+            return AUDIO_POLICY_FORCE_BT_SCO;
+        case AudioPolicyForceUse::CommunicationDeviceCategory::BT_BLE:
+            return AUDIO_POLICY_FORCE_BT_BLE;
+        case AudioPolicyForceUse::CommunicationDeviceCategory::WIRED_ACCESSORY:
+            return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+        aidl2legacy_AudioPolicyForceUseMediaDeviceCategory_audio_policy_forced_cfg_t(
+        const AudioPolicyForceUse::MediaDeviceCategory aidl) {
+    switch (aidl) {
+        case AudioPolicyForceUse::MediaDeviceCategory::NONE:
+            return AUDIO_POLICY_FORCE_NONE;
+        case AudioPolicyForceUse::MediaDeviceCategory::SPEAKER:
+            return AUDIO_POLICY_FORCE_SPEAKER;
+        case AudioPolicyForceUse::MediaDeviceCategory::HEADPHONES:
+            return AUDIO_POLICY_FORCE_HEADPHONES;
+        case AudioPolicyForceUse::MediaDeviceCategory::BT_A2DP:
+            return AUDIO_POLICY_FORCE_BT_A2DP;
+        case AudioPolicyForceUse::MediaDeviceCategory::ANALOG_DOCK:
+            return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+        case AudioPolicyForceUse::MediaDeviceCategory::DIGITAL_DOCK:
+            return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+        case AudioPolicyForceUse::MediaDeviceCategory::WIRED_ACCESSORY:
+            return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+        case AudioPolicyForceUse::MediaDeviceCategory::NO_BT_A2DP:
+            return AUDIO_POLICY_FORCE_NO_BT_A2DP;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+        aidl2legacy_AudioPolicyForceUseDockType_audio_policy_forced_cfg_t(
+        const AudioPolicyForceUse::DockType aidl) {
+    switch (aidl) {
+        case AudioPolicyForceUse::DockType::NONE:
+            return AUDIO_POLICY_FORCE_NONE;
+        case AudioPolicyForceUse::DockType::BT_CAR_DOCK:
+            return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
+        case AudioPolicyForceUse::DockType::BT_DESK_DOCK:
+            return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
+        case AudioPolicyForceUse::DockType::ANALOG_DOCK:
+            return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+        case AudioPolicyForceUse::DockType::DIGITAL_DOCK:
+            return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+        case AudioPolicyForceUse::DockType::WIRED_ACCESSORY:
+            return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+        aidl2legacy_AudioPolicyForceUseEncodedSurroundConfig_audio_policy_forced_cfg_t(
+        const AudioPolicyForceUse::EncodedSurroundConfig aidl) {
+    switch (aidl) {
+        case AudioPolicyForceUse::EncodedSurroundConfig::UNSPECIFIED:
+            return AUDIO_POLICY_FORCE_NONE;
+        case AudioPolicyForceUse::EncodedSurroundConfig::NEVER:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
+        case AudioPolicyForceUse::EncodedSurroundConfig::ALWAYS:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
+        case AudioPolicyForceUse::EncodedSurroundConfig::MANUAL:
+            return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<std::pair<audio_policy_force_use_t, audio_policy_forced_cfg_t>>
+        aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+        const AudioPolicyForceUse& aidl) {
+    switch (aidl.getTag()) {
+        case AudioPolicyForceUse::forCommunication:
+            return std::make_pair(
+                    AUDIO_POLICY_FORCE_FOR_COMMUNICATION,
+                    VALUE_OR_RETURN(
+                            aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+                                    aidl.get<AudioPolicyForceUse::forCommunication>())));
+        case AudioPolicyForceUse::forMedia:
+            return std::make_pair(
+                    AUDIO_POLICY_FORCE_FOR_MEDIA,
+                    VALUE_OR_RETURN(
+                            aidl2legacy_AudioPolicyForceUseMediaDeviceCategory_audio_policy_forced_cfg_t(
+                                    aidl.get<AudioPolicyForceUse::forMedia>())));
+        case AudioPolicyForceUse::forRecord:
+            return std::make_pair(
+                    AUDIO_POLICY_FORCE_FOR_RECORD,
+                    VALUE_OR_RETURN(
+                            aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+                                    aidl.get<AudioPolicyForceUse::forRecord>())));
+        case AudioPolicyForceUse::dock:
+            return std::make_pair(AUDIO_POLICY_FORCE_FOR_DOCK,
+                    VALUE_OR_RETURN(
+                            aidl2legacy_AudioPolicyForceUseDockType_audio_policy_forced_cfg_t(
+                                    aidl.get<AudioPolicyForceUse::dock>())));
+        case AudioPolicyForceUse::systemSounds:
+            return std::make_pair(AUDIO_POLICY_FORCE_FOR_SYSTEM,
+                    aidl.get<AudioPolicyForceUse::systemSounds>() ?
+                    AUDIO_POLICY_FORCE_SYSTEM_ENFORCED : AUDIO_POLICY_FORCE_NONE);
+        case AudioPolicyForceUse::hdmiSystemAudio:
+            return std::make_pair(
+                    AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO,
+                    aidl.get<AudioPolicyForceUse::hdmiSystemAudio>() ?
+                    AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AUDIO_POLICY_FORCE_NONE);
+        case AudioPolicyForceUse::encodedSurround:
+            return std::make_pair(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, VALUE_OR_RETURN(
+                aidl2legacy_AudioPolicyForceUseEncodedSurroundConfig_audio_policy_forced_cfg_t(
+                        aidl.get<AudioPolicyForceUse::encodedSurround>())));
+        case AudioPolicyForceUse::forVibrateRinging:
+            return std::make_pair(
+                    AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING,
+                    VALUE_OR_RETURN(
+                            aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+                                    aidl.get<AudioPolicyForceUse::forVibrateRinging>())));
+    }
+    return unexpected(BAD_VALUE);
+}
+
 ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2_CapName(
         const AudioHalCapCriterionV2& aidl) {
     switch (aidl.getTag()) {
@@ -97,14 +227,14 @@
         case AudioHalCapCriterionV2::telephonyMode:
             return gPhoneStateCriterionName;
         case AudioHalCapCriterionV2::forceConfigForUse: {
-            auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>();
-            return gForceUseCriterionTag[VALUE_OR_RETURN(
-                    aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
-                            aidlCriterion.forceUse))];
+            auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>().values[0];
+            const auto [forceUse, _] = VALUE_OR_RETURN(
+                aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+                        aidlCriterion));
+            return gForceUseCriterionTag[forceUse];
         }
-        default:
-            return unexpected(BAD_VALUE);
     }
+    return unexpected(BAD_VALUE);
 }
 
 ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2TypeDevice_CapCriterionValue(
@@ -121,6 +251,32 @@
             isOut ? gLegacyOutputDevicePrefix : gLegacyInputDevicePrefix);
 }
 
+ConversionResult<audio_policy_forced_cfg_t>
+        aidl2legacy_AudioHalCapCriterionV2ForceUse_audio_policy_forced_cfg_t(
+        const AudioPolicyForceUse& aidl) {
+    const auto [_, legacyForcedCfg] = VALUE_OR_RETURN(
+            aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+                    aidl));
+    return legacyForcedCfg;
+}
+
+ConversionResult<std::string> audio_policy_forced_cfg_t_CapCriterionValue(
+        audio_policy_forced_cfg_t legacyForcedCfg) {
+    std::string legacyForcedCfgLiteral = audio_policy_forced_cfg_to_string(legacyForcedCfg);
+    if (legacyForcedCfgLiteral.empty()) {
+        ALOGE("%s Invalid forced config value %d", __func__, legacyForcedCfg);
+        return unexpected(BAD_VALUE);
+    }
+    return truncatePrefix(legacyForcedCfgLiteral, gLegacyForcePrefix);
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2ForceUse_CapCriterionValue(
+        const AudioPolicyForceUse& aidl) {
+    const audio_policy_forced_cfg_t legacyForcedCfg = VALUE_OR_RETURN(
+            aidl2legacy_AudioHalCapCriterionV2ForceUse_audio_policy_forced_cfg_t(aidl));
+    return audio_policy_forced_cfg_t_CapCriterionValue(legacyForcedCfg);
+}
+
 ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2Type_CapCriterionValue(
         const AudioHalCapCriterionV2& aidl) {
     switch (aidl.getTag()) {
@@ -139,10 +295,10 @@
         case AudioHalCapCriterionV2::telephonyMode:
             return toString(aidl.get<AudioHalCapCriterionV2::telephonyMode>().values[0]);
         case AudioHalCapCriterionV2::forceConfigForUse:
-            return toString(aidl.get<AudioHalCapCriterionV2::forceConfigForUse>().values[0]);
-        default:
-            return unexpected(BAD_VALUE);
+            return aidl2legacy_AudioHalCapCriterionV2ForceUse_CapCriterionValue(
+                    aidl.get<AudioHalCapCriterionV2::forceConfigForUse>().values[0]);
     }
+    return unexpected(BAD_VALUE);
 }
 
 ConversionResult<std::string> aidl2legacy_AudioHalCapRule_CapRule(
@@ -331,24 +487,28 @@
     engineConfig::Criterion& criterion = capCriterion.criterion;
     engineConfig::CriterionType& criterionType = capCriterion.criterionType;
 
-    auto loadForceUseCriterion = [](const auto &aidlCriterion, auto &criterion,
-            auto &criterionType) -> status_t {
-        uint32_t legacyForceUse = VALUE_OR_RETURN_STATUS(
-                aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
-                        aidlCriterion.forceUse));
+    auto loadForceUseCriterion = [](const auto& aidlCriterion, auto& criterion,
+                                    auto& criterionType) -> status_t {
+        if (aidlCriterion.values.empty()) {
+            return BAD_VALUE;
+        }
+        const auto [legacyForceUse, _] = VALUE_OR_RETURN_STATUS(
+                aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+                        aidlCriterion.values[0]));
         criterion.typeName = criterionType.name;
         criterionType.name = criterion.typeName + gCriterionTypeSuffix;
         criterionType.isInclusive =
                 (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
         criterion.name = gForceUseCriterionTag[legacyForceUse];
-        criterion.defaultLiteralValue = toString(aidlCriterion.defaultValue);
-        if (aidlCriterion.values.empty()) {
-            return BAD_VALUE;
-        }
+        criterion.defaultLiteralValue = toString(
+                aidlCriterion.defaultValue.template get<AudioPolicyForceUse::forMedia>());
         for (auto &value : aidlCriterion.values) {
-            uint32_t legacyForcedConfig = VALUE_OR_RETURN_STATUS(
-                    aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(value));
-            criterionType.valuePairs.push_back({legacyForcedConfig, 0, toString(value)});
+            const audio_policy_forced_cfg_t legacyForcedCfg = VALUE_OR_RETURN_STATUS(
+                    aidl2legacy_AudioHalCapCriterionV2ForceUse_audio_policy_forced_cfg_t(value));
+            const std::string legacyForcedCfgLiteral = VALUE_OR_RETURN_STATUS(
+                    audio_policy_forced_cfg_t_CapCriterionValue(legacyForcedCfg));
+            criterionType.valuePairs.push_back(
+                    {legacyForcedCfg, 0, legacyForcedCfgLiteral});
         }
         return NO_ERROR;
     };
diff --git a/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
index b873830..1adc602 100755
--- a/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
@@ -102,7 +102,6 @@
                 ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
                 for key, value in ordered_values.items():
                     value_node = ET.SubElement(values_node, "value")
-                    value_node.set('numerical', str(value))
                     value_node.set('literal', key)
 
                     if criterion_type.get('name') == "OutputDevicesMaskType":
@@ -114,20 +113,14 @@
         for criterion_name, values_list in addressCriteria.items():
             for criterion_type in criterion_types_root.findall('criterion_type'):
                 if criterion_type.get('name') == criterion_name:
-                    index = 0
                     existing_values_node = criterion_type.find("values")
                     if existing_values_node is not None:
-                        for existing_value in existing_values_node.findall('value'):
-                            if existing_value.get('numerical') == str(1 << index):
-                                index += 1
                         values_node = existing_values_node
                     else:
                         values_node = ET.SubElement(criterion_type, "values")
 
                     for value in values_list:
                         value_node = ET.SubElement(values_node, "value", literal=value)
-                        value_node.set('numerical', str(1 << index))
-                        index += 1
 
     xmlstr = ET.tostring(criterion_types_root, encoding='utf8', method='xml')
     reparsed = MINIDOM.parseString(xmlstr)
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 84ad604..b17a248 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -295,14 +295,12 @@
     audio_port_handle_t localPortId;
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
-    AudioPolicyInterface::input_type_t inputType;
 
     AttributionSourceState attributionSource;
     attributionSource.uid = 0;
     attributionSource.token = sp<BBinder>::make();
-    const auto inputRes =
-            mManager->getInputForAttr(attr, input, *selectedDeviceId, config, flags, riid,
-                                      AUDIO_SESSION_NONE, attributionSource, &inputType);
+    const auto inputRes = mManager->getInputForAttr(attr, input, *selectedDeviceId, config, flags,
+                                                    riid, AUDIO_SESSION_NONE, attributionSource);
     if (!inputRes.has_value()) return false;
 
     if (inputRes->portId == AUDIO_PORT_HANDLE_NONE || inputRes->input == AUDIO_IO_HANDLE_NONE) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 465b0bf..18b5ea9 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2935,8 +2935,7 @@
                                      audio_input_flags_t flags,
                                      audio_unique_id_t riid,
                                      audio_session_t session,
-                                     const AttributionSourceState& attributionSource,
-                                     input_type_t *inputType)
+                                     const AttributionSourceState& attributionSource)
 {
     ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
           "flags %#x attributes=%s requested device ID %d",
@@ -2957,6 +2956,17 @@
         attributes.source = AUDIO_SOURCE_MIC;
     }
 
+    using PermissionReqs = AudioPolicyClientInterface::PermissionReqs;
+    using MixType = AudioPolicyClientInterface::MixType;
+    PermissionReqs permReq {
+        .source =  legacy2aidl_audio_source_t_AudioSource(attributes.source).value(),
+        .mixType = MixType::NONE, // can be modified
+        .virtualDeviceId = 0, // can be modified
+        .isHotword = (flags & (AUDIO_INPUT_FLAG_HW_HOTWORD | AUDIO_INPUT_FLAG_HOTWORD_TAP |
+                               AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0,
+        .isCallRedir = (attributes.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0,
+    };
+
     // Explicit routing?
     sp<DeviceDescriptor> explicitRoutingDevice =
             mAvailableInputDevices.getDeviceFromId(requestedDeviceId);
@@ -3000,13 +3010,9 @@
                 }
             }
         }
-        *inputType = API_INPUT_LEGACY;
         device = inputDesc->getDevice();
         ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, requestedInput, session);
-        // TODO perm check
     } else {
-        *inputType = API_INPUT_INVALID;
-
         if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
                 extractAddressFromAudioAttributes(attributes).has_value()) {
             status_t status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
@@ -3027,12 +3033,12 @@
             }
 
             if (is_mix_loopback_render(policyMix->mRouteFlags)) {
-                *inputType = API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK;
+                permReq.mixType = MixType::PUBLIC_CAPTURE_PLAYBACK;
             } else {
-                *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
+                permReq.mixType = MixType::EXT_POLICY_REROUTE;
             }
             // TODO is this correct?
-            vdi = policyMix->mVirtualDeviceId;
+            permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
         } else {
             if (explicitRoutingDevice != nullptr) {
                 device = explicitRoutingDevice;
@@ -3050,24 +3056,35 @@
                                         attributes.source))};
             }
             if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
-                *inputType = API_INPUT_MIX_CAPTURE;
+                permReq.mixType = MixType::CAPTURE;
             } else if (policyMix) {
                 ALOG_ASSERT(policyMix->mMixType == MIX_TYPE_RECORDERS, "Invalid Mix Type");
                 // there is an external policy, but this input is attached to a mix of recorders,
                 // meaning it receives audio injected into the framework, so the recorder doesn't
                 // know about it and is therefore considered "legacy"
-                *inputType = API_INPUT_LEGACY;
-                vdi = policyMix->mVirtualDeviceId;
+                permReq.mixType = MixType::NONE;
+                permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
             } else if (audio_is_remote_submix_device(device->type())) {
-                *inputType = API_INPUT_MIX_CAPTURE;
+                permReq.mixType = MixType::CAPTURE;
             } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
-                *inputType = API_INPUT_TELEPHONY_RX;
+                permReq.mixType = MixType::TELEPHONY_RX_CAPTURE;
             } else {
-                *inputType = API_INPUT_LEGACY;
+                permReq.mixType = MixType::NONE;
             }
         }
 
-        // TODO perm check
+        auto permRes = mpClientInterface->checkPermissionForInput(attributionSource, permReq);
+        if (!permRes.has_value()) return base::unexpected {permRes.error()};
+        if (!permRes.value()) {
+            return base::unexpected{Status::fromExceptionCode(
+                    EX_SECURITY, String8::format("%s: %s missing perms for source %d mix %d vdi %d"
+                        "hotword? %d callredir? %d", __func__, attributionSource.toString().c_str(),
+                                                 static_cast<int>(permReq.source),
+                                                 static_cast<int>(permReq.mixType),
+                                                 permReq.virtualDeviceId,
+                                                 permReq.isHotword,
+                                                 permReq.isCallRedir))};
+        }
 
         input = getInputForDevice(device, session, attributes, config, flags, policyMix);
         if (input == AUDIO_IO_HANDLE_NONE) {
@@ -3108,14 +3125,14 @@
     mEffects.moveEffectsForIo(session, input, &mInputs, mpClientInterface);
     inputDesc->addClient(clientDesc);
 
-    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
-            input, *inputType, selectedDeviceId, allocatedPortId);
+    ALOGV("getInputForAttr() returns input %d selectedDeviceId %d vdi %d for port ID %d",
+            input, selectedDeviceId, permReq.virtualDeviceId, allocatedPortId);
 
     auto ret = media::GetInputForAttrResponse {};
     ret.input = input;
     ret.selectedDeviceId = selectedDeviceId;
     ret.portId = allocatedPortId;
-    ret.virtualDeviceId = vdi;
+    ret.virtualDeviceId = permReq.virtualDeviceId;
     ret.config = legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/).value();
     return ret;
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 28bf5cb..44863ee 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -144,8 +144,7 @@
                                          audio_input_flags_t flags,
                                          audio_unique_id_t riid,
                                          audio_session_t session,
-                                         const AttributionSourceState& attributionSource,
-                                         input_type_t *inputType /* out param */) override;
+                                         const AttributionSourceState& attributionSource) override;
 
         // indicates to the audio policy manager that the input starts being used.
         virtual status_t startInput(audio_port_handle_t portId);
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index 79e328e..f415a41 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -25,7 +25,6 @@
         "audio-permission-aidl-cpp",
         "audioclient-types-aidl-cpp",
         "audioflinger-aidl-cpp",
-        "audiopermissioncontroller",
         "audiopolicy-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
@@ -37,6 +36,7 @@
         "libaudioclient_aidl_conversion",
         "libaudiofoundation",
         "libaudiohal",
+        "libaudiopermission",
         "libaudiopolicy",
         "libaudiopolicycomponents",
         "libaudiopolicymanagerdefault",
@@ -118,6 +118,6 @@
     name: "audiopolicyservicelocal_headers",
     host_supported: true,
     export_include_dirs: ["include"],
-    header_libs: ["audiopermissioncontroller_headers"],
-    export_header_lib_headers: ["audiopermissioncontroller_headers"],
+    header_libs: ["libaudiopermission_headers"],
+    export_header_lib_headers: ["libaudiopermission_headers"],
 }
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 9d9836f..12320b7 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -87,8 +87,6 @@
 using media::audio::common::AudioFormatDescription;
 using media::audio::common::AudioMode;
 using media::audio::common::AudioOffloadInfo;
-using media::audio::common::AudioPolicyForceUse;
-using media::audio::common::AudioPolicyForcedConfig;
 using media::audio::common::AudioSource;
 using media::audio::common::AudioStreamType;
 using media::audio::common::AudioUsage;
@@ -298,8 +296,8 @@
     return Status::ok();
 }
 
-Status AudioPolicyService::setForceUse(AudioPolicyForceUse usageAidl,
-                                       AudioPolicyForcedConfig configAidl)
+Status AudioPolicyService::setForceUse(media::AudioPolicyForceUse usageAidl,
+                                       media::AudioPolicyForcedConfig configAidl)
 {
     audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
@@ -330,8 +328,8 @@
     return Status::ok();
 }
 
-Status AudioPolicyService::getForceUse(AudioPolicyForceUse usageAidl,
-                                       AudioPolicyForcedConfig* _aidl_return) {
+Status AudioPolicyService::getForceUse(media::AudioPolicyForceUse usageAidl,
+                                       media::AudioPolicyForcedConfig* _aidl_return) {
     audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
 
@@ -680,13 +678,14 @@
     }
 }
 
-error::BinderResult<bool> AudioPolicyService::evaluatePermsForSource(
-        const AttributionSourceState& attrSource, AudioSource source, bool isHotword) {
+error::BinderResult<bool> AudioPolicyService::AudioPolicyClient::checkPermissionForInput(
+        const AttributionSourceState& attrSource, const PermissionReqs& req) {
+
     error::BinderResult<bool> permRes = true;
     const auto check_perm = [&](PermissionEnum perm, uid_t uid) {
-        return getPermissionProvider().checkPermission(perm, uid);
+        return mAudioPolicyService->getPermissionProvider().checkPermission(perm, uid);
     };
-    switch (source) {
+    switch (req.source) {
         case AudioSource::VOICE_UPLINK:
         case AudioSource::VOICE_DOWNLINK:
         case AudioSource::VOICE_CALL:
@@ -721,14 +720,13 @@
         case AudioSource::VOICE_PERFORMANCE:
             // No additional check intended
         case AudioSource::REMOTE_SUBMIX:
-            // special-case checked based on device (evaluatePermsForDevice)
+            // special-case checked based on mix type below
             break;
     }
 
-    bool isAllowed = VALUE_OR_RETURN(permRes);
-
-    if (!isAllowed) {
-        if (isLegacyOutputSource(source)) {
+    if (!permRes.has_value()) return permRes;
+    if (!permRes.value()) {
+        if (isLegacyOutputSource(req.source)) {
             permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
                                                 : captureAudioOutputAllowed(attrSource);
             PROPAGATE_FALSEY(permRes);
@@ -737,70 +735,61 @@
         }
     }
 
-    if (isHotword) {
+    if (req.isHotword) {
         permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_HOTWORD, attrSource.uid)
                                             : captureHotwordAllowed(attrSource);
         PROPAGATE_FALSEY(permRes);
     }
 
-    // All sources which aren't output capture require RECORD as well,
-    // as well as vdi policy mix
-    const auto legacySource = aidl2legacy_AudioSource_audio_source_t(source).value();
-    if (isRecordOpRequired(legacySource)) {
-        permRes = audioserver_permissions() ? check_perm(RECORD_AUDIO, attrSource.uid)
-                                            : recordingAllowed(attrSource, legacySource);
-        PROPAGATE_FALSEY(permRes);
-    }
-    return true;
-}
-
-error::BinderResult<bool> AudioPolicyService::evaluatePermsForDevice(
-        const AttributionSourceState& attrSource, AudioSource source,
-        AudioPolicyInterface::input_type_t inputType, uint32_t vdi, bool isCallRedir) {
-    // enforce permission (if any) required for each type of input
-    error::BinderResult<bool> permRes = true;
-    const auto check_perm = [&](PermissionEnum perm, uid_t uid) {
-        return getPermissionProvider().checkPermission(perm, uid);
-    };
+    // TODO evaluate whether we should be checking call redirection like this
     bool isAllowedDueToCallPerm = false;
-    if (isCallRedir) {
+    if (req.isCallRedir) {
         const auto checkCall = audioserver_permissions()
-                                       ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
-                                       : callAudioInterceptionAllowed(attrSource);
+                                         ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
+                                         : callAudioInterceptionAllowed(attrSource);
         isAllowedDueToCallPerm = VALUE_OR_RETURN(checkCall);
     }
-    switch (inputType) {
-        case AudioPolicyInterface::API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK:
+
+    switch (req.mixType) {
+        case MixType::NONE:
+            break;
+        case MixType::PUBLIC_CAPTURE_PLAYBACK:
             // this use case has been validated in audio service with a MediaProjection token,
             // and doesn't rely on regular permissions
-        case AudioPolicyInterface::API_INPUT_LEGACY:
+            // TODO (b/378778313)
             break;
-        case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
+        case MixType::TELEPHONY_RX_CAPTURE:
             if (isAllowedDueToCallPerm) break;
             // FIXME: use the same permission as for remote submix for now.
             FALLTHROUGH_INTENDED;
-        case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
+        case MixType::CAPTURE:
             permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
                                                 : captureAudioOutputAllowed(attrSource);
             break;
-        case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: {
+        case MixType::EXT_POLICY_REROUTE:
             // TODO intended?
             if (isAllowedDueToCallPerm) break;
             permRes = audioserver_permissions() ? check_perm(MODIFY_AUDIO_ROUTING, attrSource.uid)
                                                 : modifyAudioRoutingAllowed(attrSource);
             break;
-        }
-        case AudioPolicyInterface::API_INPUT_INVALID:
-        default:
-            LOG_ALWAYS_FATAL("%s encountered an invalid input type %d", __func__, (int)inputType);
     }
 
     PROPAGATE_FALSEY(permRes);
 
-    if (audiopolicy_flags::record_audio_device_aware_permission()) {
-        // enforce device-aware RECORD_AUDIO permission
-        const auto legacySource = aidl2legacy_AudioSource_audio_source_t(source).value();
-        return vdi == kDefaultVirtualDeviceId || recordingAllowed(attrSource, vdi, legacySource);
+    // All sources which aren't output capture
+    // AND capture from vdi policy mix (the injected audio is mic data from another device)
+    // REQUIRE RECORD perms
+    const auto legacySource = aidl2legacy_AudioSource_audio_source_t(req.source).value();
+    if (req.virtualDeviceId != kDefaultVirtualDeviceId) {
+        // TODO assert that this is always a recordOpSource
+        // TODO upcall solution
+        return recordingAllowed(attrSource, req.virtualDeviceId, legacySource);
+    }
+
+    if (isRecordOpRequired(legacySource)) {
+        permRes = audioserver_permissions() ? check_perm(RECORD_AUDIO, attrSource.uid)
+                                            : recordingAllowed(attrSource, legacySource);
+        PROPAGATE_FALSEY(permRes);
     }
     return true;
 }
@@ -847,19 +836,14 @@
         inputSource = AudioSource::MIC;
     }
 
-    const bool isHotword = (flags & (AUDIO_INPUT_FLAG_HW_HOTWORD | AUDIO_INPUT_FLAG_HOTWORD_TAP |
-                        AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0;
-
     const bool isCallRedir = (attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0;
 
-    const bool canCaptureOutput = audioserver_permissions()
-                                ? CHECK_PERM(CAPTURE_AUDIO_OUTPUT, attributionSource.uid)
-                                : captureAudioOutputAllowed(attributionSource);
-
     //TODO(b/374751406): remove forcing canBypassConcurrentPolicy to canCaptureOutput
     // once all system apps using CAPTURE_AUDIO_OUTPUT to capture during calls
     // are updated to use the new CONCURRENT_AUDIO_RECORD_BYPASS permission.
-    bool canBypassConcurrentPolicy = canCaptureOutput;
+    bool canBypassConcurrentPolicy = audioserver_permissions()
+                                ? CHECK_PERM(CAPTURE_AUDIO_OUTPUT, attributionSource.uid)
+                                : captureAudioOutputAllowed(attributionSource);
     if (concurrent_audio_record_bypass_permission()) {
         canBypassConcurrentPolicy = audioserver_permissions() ?
                             CHECK_PERM(BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION,
@@ -867,55 +851,16 @@
                             : bypassConcurrentPolicyAllowed(attributionSource);
     }
 
-    const bool hasPerm = VALUE_OR_RETURN_STATUS(evaluatePermsForSource(
-                attributionSource,
-                inputSource,
-                isHotword));
-
-    if (!hasPerm) {
-        return Status::fromExceptionCode(
-                EX_SECURITY, String8::format("%s: %s missing perms for source %s", __func__,
-                                             attributionSource.toString().c_str(),
-                                             toString(inputSource).c_str()));
-    }
-
     sp<AudioPolicyEffects> audioPolicyEffects;
     base::expected<media::GetInputForAttrResponse, std::variant<binder::Status, AudioConfigBase>>
             res;
     {
-        AudioPolicyInterface::input_type_t inputType;
-
         audio_utils::lock_guard _l(mMutex);
-        {
-            AutoCallerClear acc;
-            // the audio_in_acoustics_t parameter is ignored by get_input()
-            res = mAudioPolicyManager->getInputForAttr(attr, requestedInput, requestedDeviceId,
-                    config, flags, riid, session, attributionSource, &inputType);
-
-        }
-        audioPolicyEffects = mAudioPolicyEffects;
-
-        if (res.has_value()) {
-            const auto permResult = evaluatePermsForDevice(attributionSource,
-                    inputSource, inputType, res->virtualDeviceId,
-                    isCallRedir);
-
-            if (!permResult.has_value()) {
-                AutoCallerClear acc;
-                mAudioPolicyManager->releaseInput(res->portId);
-                return permResult.error();
-            } else if (!permResult.value()) {
-                AutoCallerClear acc;
-                mAudioPolicyManager->releaseInput(res->portId);
-                return Status::fromExceptionCode(
-                        EX_SECURITY,
-                        String8::format(
-                                "%s: %s missing perms for input type %d, inputSource %d, vdi %d",
-                                __func__, attributionSource.toString().c_str(), inputType,
-                                inputSource, res->virtualDeviceId));
-            }
-        }
-
+        AutoCallerClear acc;
+        // the audio_in_acoustics_t parameter is ignored by get_input()
+        res = mAudioPolicyManager->getInputForAttr(attr, requestedInput, requestedDeviceId,
+                                                   config, flags, riid, session,
+                                                   attributionSource);
         if (!res.has_value()) {
             if (res.error().index() == 1) {
                 _aidl_return->config = std::get<1>(res.error());
@@ -925,16 +870,15 @@
             }
         }
 
-        DeviceIdVector selectedDeviceIds = { res->selectedDeviceId };
-        sp<AudioRecordClient> client = new AudioRecordClient(attr, res->input, session, res->portId,
-                                                             selectedDeviceIds, attributionSource,
-                                                             res->virtualDeviceId,
-                                                             canBypassConcurrentPolicy,
-                                                             mOutputCommandThread);
+        audioPolicyEffects = mAudioPolicyEffects;
+
+        sp<AudioRecordClient> client = new AudioRecordClient(
+                attr, res->input, session, res->portId, {res->selectedDeviceId}, attributionSource,
+                res->virtualDeviceId, canBypassConcurrentPolicy, mOutputCommandThread);
         mAudioRecordClients.add(res->portId, client);
     }
 
-    if (audioPolicyEffects != 0) {
+    if (audioPolicyEffects != nullptr) {
         // create audio pre processors according to input source
         status_t status = audioPolicyEffects->addInputEffects(res->input,
                 aidl2legacy_AudioSource_audio_source_t(inputSource).value(), session);
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 5fe200c..acd9fe9 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -108,10 +108,10 @@
             const std::string& deviceName,
             const AudioFormatDescription& encodedFormat) override;
     binder::Status setPhoneState(AudioMode state, int32_t uid) override;
-    binder::Status setForceUse(android::media::audio::common::AudioPolicyForceUse usage,
-            android::media::audio::common::AudioPolicyForcedConfig config) override;
-    binder::Status getForceUse(android::media::audio::common::AudioPolicyForceUse usage,
-            android::media::audio::common::AudioPolicyForcedConfig* _aidl_return) override;
+    binder::Status setForceUse(media::AudioPolicyForceUse usage,
+                               media::AudioPolicyForcedConfig config) override;
+    binder::Status getForceUse(media::AudioPolicyForceUse usage,
+                               media::AudioPolicyForcedConfig* _aidl_return) override;
     binder::Status getOutput(AudioStreamType stream, int32_t* _aidl_return) override;
     binder::Status getOutputForAttr(const media::audio::common::AudioAttributes& attr,
                                     int32_t session,
@@ -504,14 +504,6 @@
                             const audio_output_flags_t flags);
     status_t unregisterOutput(audio_io_handle_t output);
 
-    error::BinderResult<bool> evaluatePermsForSource(const AttributionSourceState& attrSource,
-                                                     AudioSource source, bool isHotword);
-
-    error::BinderResult<bool> evaluatePermsForDevice(const AttributionSourceState& attrSource,
-                                                     AudioSource source,
-                                                     AudioPolicyInterface::input_type_t inputType,
-                                                     uint32_t vdi, bool isCallRedir);
-
     // If recording we need to make sure the UID is allowed to do that. If the UID is idle
     // then it cannot record and gets buffers with zeros - silence. As soon as the UID
     // transitions to an active state we will start reporting buffers with data. This approach
@@ -968,6 +960,9 @@
                 media::audio::common::AudioMMapPolicyType policyType,
                 std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) override;
 
+        error::BinderResult<bool> checkPermissionForInput(const AttributionSourceState& attr,
+                const PermissionReqs& req) override;
+
      private:
         AudioPolicyService *mAudioPolicyService;
     };
diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp
index fd344d9..01e557c 100644
--- a/services/audiopolicy/service/AudioRecordClient.cpp
+++ b/services/audiopolicy/service/AudioRecordClient.cpp
@@ -64,12 +64,12 @@
     using iterator_category = std::forward_iterator_tag;
     using difference_type = std::ptrdiff_t;
     using value_type = AttributionSourceState;
-    using pointer = const value_type*;
-    using reference = const value_type&;
+    using pointer = value_type*;
+    using reference = value_type&;
 
     AttrSourceItr() : mAttr(nullptr) {}
 
-    AttrSourceItr(const AttributionSourceState& attr) : mAttr(&attr) {}
+    AttrSourceItr(AttributionSourceState& attr) : mAttr(&attr) {}
 
     reference operator*() const { return *mAttr; }
     pointer operator->() const { return mAttr; }
@@ -89,7 +89,7 @@
 
     static AttrSourceItr end() { return AttrSourceItr{}; }
 private:
-    const AttributionSourceState * mAttr;
+    AttributionSourceState * mAttr;
 };
 } // anonymous
 
@@ -134,6 +134,16 @@
         mVirtualDeviceId(virtualDeviceId), mAttr(attr), mAppOp(appOp),
         mShouldMonitorRecord(shouldMonitorRecord),
         mCommandThread(commandThread) {
+    // The vdi is carried in the attribution source for appops perm checks.
+    // Overwrite the entire chain with the vdi associated with the mix this client is attached to
+    // This ensures the checkOps triggered by the listener are correct.
+    // Note: we still only register for events by package name, so we assume that we get events
+    // independent of vdi.
+    if (mVirtualDeviceId != 0 /* default vdi */) {
+        // TODO (atneya@) lift for const
+        std::for_each(AttrSourceItr{mAttributionSource}, AttrSourceItr::end(),
+                      [&](auto& attr) { attr.deviceId = mVirtualDeviceId; });
+    }
 }
 
 OpRecordAudioMonitor::~OpRecordAudioMonitor()
diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h
index f45b4de..3553f1d 100644
--- a/services/audiopolicy/service/AudioRecordClient.h
+++ b/services/audiopolicy/service/AudioRecordClient.h
@@ -71,7 +71,7 @@
     void checkOp(bool updateUidStates = false);
 
     std::atomic_bool mHasOp;
-    const AttributionSourceState mAttributionSource;
+    AttributionSourceState mAttributionSource;
     const uint32_t mVirtualDeviceId;
     const audio_attributes_t mAttr;
     const int32_t mAppOp;
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 33dc5fe..8e5fb96 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -128,6 +128,10 @@
             std::vector<media::audio::common::AudioMMapPolicyInfo>* /*policyInfos*/) override {
         return INVALID_OPERATION;
     }
+    error::BinderResult<bool> checkPermissionForInput(const AttributionSourceState& /* attr */,
+                                                              const PermissionReqs& /* req */) {
+        return true;
+    }
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 3cdf6a1..a8f79c3 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -334,10 +334,9 @@
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
     if (!virtualDeviceId) virtualDeviceId = 0;
-    AudioPolicyInterface::input_type_t inputType;
     AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
     auto inputRes = mManager->getInputForAttr(attr, *input, *selectedDeviceId,
-        config, flags, riid, session, attributionSource, &inputType);
+        config, flags, riid, session, attributionSource);
     ASSERT_TRUE(inputRes.has_value());
     ASSERT_NE(inputRes->portId, AUDIO_PORT_HANDLE_NONE);
     *input = inputRes->input;
@@ -1242,7 +1241,7 @@
     };
     auto inputRes = mManager->getInputForAttr(attr, requestedInput, requestedDeviceId,
                                               requestedConfig, AUDIO_INPUT_FLAG_NONE, 1 /*riid*/,
-                                              AUDIO_SESSION_NONE, attributionSource, &inputType);
+                                              AUDIO_SESSION_NONE, attributionSource);
     ASSERT_TRUE(inputRes.has_value());
     ASSERT_NE(inputRes->portId, AUDIO_PORT_HANDLE_NONE);
     ASSERT_EQ(VALUE_OR_FATAL(legacy2aidl_audio_config_base_t_AudioConfigBase(
@@ -1255,7 +1254,7 @@
 
     inputRes = mManager->getInputForAttr(attr, requestedInput, requestedDeviceId, requestedConfig,
                                          AUDIO_INPUT_FLAG_NONE, 1 /*riid*/, AUDIO_SESSION_NONE,
-                                         attributionSource, &inputType);
+                                         attributionSource);
     ASSERT_TRUE(inputRes.has_value());
     ASSERT_NE(inputRes->portId, AUDIO_PORT_HANDLE_NONE);
     ASSERT_EQ(VALUE_OR_FATAL(legacy2aidl_audio_config_base_t_AudioConfigBase(requestedConfig,
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index df94478..31a45c3 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -3811,14 +3811,31 @@
         const std::string& cameraId) {
     // Remove from active clients list
     std::vector<sp<CameraService::BasicClient>> clients;
-    std::vector<CameraService::DescriptorPtr> clientDescriptors;
-    clientDescriptors =  mActiveClientManager.removeAll(cameraId);
-    for (const auto& clientDescriptorPtr : clientDescriptors) {
+    if (flags::camera_multi_client()) {
+        std::vector<CameraService::DescriptorPtr> clientDescriptors;
+        clientDescriptors =  mActiveClientManager.removeAll(cameraId);
+        for (const auto& clientDescriptorPtr : clientDescriptors) {
+            if (clientDescriptorPtr != nullptr) {
+                sp<BasicClient> client = clientDescriptorPtr->getValue();
+                if (client.get() != nullptr) {
+                    cacheClientTagDumpIfNeeded(clientDescriptorPtr->getKey(), client.get());
+                    clients.push_back(client);
+                }
+            }
+        }
+    } else {
+        auto clientDescriptorPtr = mActiveClientManager.remove(cameraId);
+        if (clientDescriptorPtr == nullptr) {
+            ALOGW("%s: Could not evict client, no client for camera ID %s", __FUNCTION__,
+                    cameraId.c_str());
+            return clients;
+        }
+
         sp<BasicClient> client = clientDescriptorPtr->getValue();
         if (client.get() != nullptr) {
             cacheClientTagDumpIfNeeded(clientDescriptorPtr->getKey(), client.get());
+            clients.push_back(client);
         }
-        clients.push_back(client);
     }
     return clients;
 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 9c75ede..6f29ff4 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -631,6 +631,9 @@
         CameraClientManager();
         virtual ~CameraClientManager();
 
+        // Bring all remove() functions into scope
+        using ClientManager::remove;
+
         virtual void remove(const DescriptorPtr& value) override;
 
         /**
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index b2b8685..0f0dc4c 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -746,9 +746,9 @@
         for (auto it = mClients.begin(); it != mClients.end();)
         {
             if ((*it)->getKey() == key) {
-                it = mClients.erase(it);
                 if (mListener != nullptr) mListener->onClientRemoved(**it);
                 clients.push_back(*it);
+                it = mClients.erase(it);
             } else {
                 ++it;
             }
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index ee4df4e..202ab96 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -1253,14 +1253,6 @@
         request->update(ANDROID_CONTROL_AUTOFRAMING, &kDefaultAutoframingMode, 1);
     }
 
-    if (flags::ae_priority()) {
-        // Fill in CONTROL_AE_PRIORITY_MODE if not available
-        if (!request->exists(ANDROID_CONTROL_AE_PRIORITY_MODE)) {
-            static const uint8_t kDefaultAePriorityMode = ANDROID_CONTROL_AE_PRIORITY_MODE_OFF;
-            request->update(ANDROID_CONTROL_AE_PRIORITY_MODE, &kDefaultAePriorityMode, 1);
-        }
-    }
-
     return OK;
 }