Merge "ServiceSingleton: Do not permit onServiceDied before onNewService" into main
diff --git a/Android.bp b/Android.bp
index 0c7ed6e..c716a06 100644
--- a/Android.bp
+++ b/Android.bp
@@ -135,6 +135,7 @@
 
 aidl_interface {
     name: "av-audio-types-aidl",
+    unstable: true,
     host_supported: true,
     vendor_available: true,
     double_loadable: true,
@@ -154,28 +155,4 @@
             sdk_version: "module_current",
         },
     },
-    versions_with_info: [
-        {
-            version: "1",
-            imports: ["android.hardware.audio.core-V2"],
-        },
-    ],
-    frozen: false,
-
-}
-
-latest_av_audio_types_aidl = "av-audio-types-aidl-V2"
-
-cc_defaults {
-    name: "latest_av_audio_types_aidl_ndk_shared",
-    shared_libs: [
-        latest_av_audio_types_aidl + "-ndk",
-    ],
-}
-
-cc_defaults {
-    name: "latest_av_audio_types_aidl_ndk_static",
-    static_libs: [
-        latest_av_audio_types_aidl + "-ndk",
-    ],
 }
diff --git a/aidl/com/android/media/permission/PermissionEnum.aidl b/aidl/com/android/media/permission/PermissionEnum.aidl
index b08db44..7badb87 100644
--- a/aidl/com/android/media/permission/PermissionEnum.aidl
+++ b/aidl/com/android/media/permission/PermissionEnum.aidl
@@ -37,5 +37,6 @@
     CAPTURE_TUNER_AUDIO_INPUT = 11,
     CAPTURE_VOICE_COMMUNICATION_OUTPUT = 12,
     BLUETOOTH_CONNECT = 13,
-    ENUM_SIZE = 14, // Not for actual usage, used by Java
+    BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION = 14,
+    ENUM_SIZE = 15, // Not for actual usage, used by Java
 }
diff --git a/aidl_api/av-audio-types-aidl/1/.hash b/aidl_api/av-audio-types-aidl/1/.hash
deleted file mode 100644
index 0002682..0000000
--- a/aidl_api/av-audio-types-aidl/1/.hash
+++ /dev/null
@@ -1 +0,0 @@
-ef1bc5ed9db445fbfc116cdec6e6ad081458ee40
diff --git a/aidl_api/av-audio-types-aidl/1/android/media/audio/IHalAdapterVendorExtension.aidl b/aidl_api/av-audio-types-aidl/1/android/media/audio/IHalAdapterVendorExtension.aidl
deleted file mode 100644
index a9aa2c1..0000000
--- a/aidl_api/av-audio-types-aidl/1/android/media/audio/IHalAdapterVendorExtension.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.media.audio;
-/* @hide */
-interface IHalAdapterVendorExtension {
-  @utf8InCpp String[] parseVendorParameterIds(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeys);
-  void parseVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeysAndValues, out android.hardware.audio.core.VendorParameter[] syncParameters, out android.hardware.audio.core.VendorParameter[] asyncParameters);
-  android.hardware.audio.core.VendorParameter[] parseBluetoothA2dpReconfigureOffload(in @utf8InCpp String rawValue);
-  android.hardware.audio.core.VendorParameter[] parseBluetoothLeReconfigureOffload(in @utf8InCpp String rawValue);
-  @utf8InCpp String processVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in android.hardware.audio.core.VendorParameter[] parameters);
-  enum ParameterScope {
-    MODULE = 0,
-    STREAM = 1,
-  }
-}
diff --git a/aidl_api/av-audio-types-aidl/current/android/media/audio/IHalAdapterVendorExtension.aidl b/aidl_api/av-audio-types-aidl/current/android/media/audio/IHalAdapterVendorExtension.aidl
deleted file mode 100644
index a9aa2c1..0000000
--- a/aidl_api/av-audio-types-aidl/current/android/media/audio/IHalAdapterVendorExtension.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.media.audio;
-/* @hide */
-interface IHalAdapterVendorExtension {
-  @utf8InCpp String[] parseVendorParameterIds(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeys);
-  void parseVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeysAndValues, out android.hardware.audio.core.VendorParameter[] syncParameters, out android.hardware.audio.core.VendorParameter[] asyncParameters);
-  android.hardware.audio.core.VendorParameter[] parseBluetoothA2dpReconfigureOffload(in @utf8InCpp String rawValue);
-  android.hardware.audio.core.VendorParameter[] parseBluetoothLeReconfigureOffload(in @utf8InCpp String rawValue);
-  @utf8InCpp String processVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in android.hardware.audio.core.VendorParameter[] parameters);
-  enum ParameterScope {
-    MODULE = 0,
-    STREAM = 1,
-  }
-}
diff --git a/camera/Android.bp b/camera/Android.bp
index 25b5e2c..71c1673 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -82,6 +82,8 @@
         include_dirs: [
             "frameworks/native/aidl/gui",
             "frameworks/native/libs/permission/aidl",
+            "hardware/interfaces/common/fmq/aidl",
+            "hardware/interfaces/common/aidl",
         ],
     },
 
@@ -112,6 +114,8 @@
     ],
 
     shared_libs: [
+        "android.hardware.common.fmq-V1-cpp",
+        "android.hardware.common-V2-cpp",
         "camera_platform_flags_c_lib",
         "framework-permission-aidl-cpp",
         "lib-platform-compat-native-api",
@@ -136,6 +140,8 @@
     ],
     export_shared_lib_headers: [
         "framework-permission-aidl-cpp",
+        "android.hardware.common.fmq-V1-cpp",
+        "android.hardware.common-V2-cpp",
         "libcamera_metadata",
         "libgui",
         "libnativewindow",
@@ -187,6 +193,7 @@
         "aidl/android/hardware/camera2/ICameraInjectionCallback.aidl",
         "aidl/android/hardware/camera2/ICameraInjectionSession.aidl",
         "aidl/android/hardware/camera2/ICameraOfflineSession.aidl",
+        "aidl/android/hardware/camera2/CameraMetadataInfo.aidl",
     ],
     path: "aidl",
 }
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
index 9ff2578..254984f 100644
--- a/camera/CaptureResult.cpp
+++ b/camera/CaptureResult.cpp
@@ -98,7 +98,6 @@
     status_t res;
 
     mPhysicalCameraId = "";
-    mPhysicalCameraMetadata.clear();
 
     String16 physicalCameraId;
     if ((res = parcel->readString16(&physicalCameraId)) != OK) {
@@ -107,10 +106,11 @@
     }
     mPhysicalCameraId = toStdString(physicalCameraId);
 
-    if ((res = mPhysicalCameraMetadata.readFromParcel(parcel)) != OK) {
+    if ((res = mCameraMetadataInfo.readFromParcel(parcel)) != OK) {
         ALOGE("%s: Failed to read metadata from parcel: %d", __FUNCTION__, res);
         return res;
     }
+
     return OK;
 }
 
@@ -121,11 +121,13 @@
                 __FUNCTION__, res);
         return res;
     }
-    if ((res = mPhysicalCameraMetadata.writeToParcel(parcel)) != OK) {
+
+    if ((res = mCameraMetadataInfo.writeToParcel(parcel)) != OK) {
         ALOGE("%s: Failed to write physical camera metadata to parcel: %d",
                 __FUNCTION__, res);
         return res;
     }
+
     return OK;
 }
 
@@ -178,20 +180,12 @@
     }
 
     for (int32_t i = 0; i < physicalMetadataCount; i++) {
-        String16 cameraId;
-        if ((res = parcel->readString16(&cameraId)) != OK) {
-            ALOGE("%s: Failed to read camera id: %d", __FUNCTION__, res);
+        PhysicalCaptureResultInfo result;
+        if ((res = result.readFromParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to read physical result from parcel: %d", __FUNCTION__, res);
             return res;
         }
-
-        CameraMetadata physicalMetadata;
-        if ((res = physicalMetadata.readFromParcel(parcel)) != OK) {
-            ALOGE("%s: Failed to read metadata from parcel: %d", __FUNCTION__, res);
-            return res;
-        }
-
-        mPhysicalMetadatas.emplace(mPhysicalMetadatas.end(), toStdString(cameraId),
-                physicalMetadata);
+        mPhysicalMetadatas.emplace(mPhysicalMetadatas.end(), result);
     }
     ALOGV("%s: Read physical metadata from parcel", __FUNCTION__);
 
@@ -232,13 +226,8 @@
         return BAD_VALUE;
     }
     for (const auto& physicalMetadata : mPhysicalMetadatas) {
-        if ((res = parcel->writeString16(toString16(physicalMetadata.mPhysicalCameraId))) != OK) {
-            ALOGE("%s: Failed to write physical camera ID to parcel: %d",
-                    __FUNCTION__, res);
-            return res;
-        }
-        if ((res = physicalMetadata.mPhysicalCameraMetadata.writeToParcel(parcel)) != OK) {
-            ALOGE("%s: Failed to write physical camera metadata to parcel: %d",
+        if ((res = physicalMetadata.writeToParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to write physicalMetadata to parcel: %d",
                     __FUNCTION__, res);
             return res;
         }
diff --git a/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl b/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl
new file mode 100644
index 0000000..74c207e
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/** @hide */
+union CameraMetadataInfo {
+    long fmqSize;
+    CameraMetadataNative metadata;
+}
\ No newline at end of file
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 49e9920..68e6354 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.hardware.camera2.CameraMetadataInfo;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
@@ -36,7 +37,7 @@
     oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
     oneway void onDeviceIdle();
     oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
-    oneway void onResultReceived(in CameraMetadataNative result,
+    oneway void onResultReceived(in CameraMetadataInfo resultInfo,
                                  in CaptureResultExtras resultExtras,
                                  in PhysicalCaptureResultInfo[] physicalCaptureResultInfos);
     oneway void onPrepared(int streamId);
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index c1da126..a9191eb 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -23,6 +23,8 @@
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.utils.SubmitInfo;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
 import android.view.Surface;
 
 /** @hide */
@@ -173,6 +175,7 @@
 
     void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
 
+    MQDescriptor<byte, SynchronizedReadWrite> getCaptureResultMetadataQueue();
 
     // Keep in sync with public API in
     // frameworks/base/core/java/android/hardware/camera2/CameraDevice.java
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index 071f34e..d2fcde6 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -24,6 +24,7 @@
 #include <camera/StringUtils.h>
 
 #include <binder/Parcel.h>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
 #include <gui/Surface.h>
 #include <gui/view/Surface.h>
 
@@ -112,11 +113,14 @@
             return err;
         }
 
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+        sp<Surface> surface = surfaceShim.toSurface();
+#else
         sp<Surface> surface;
         if (surfaceShim.graphicBufferProducer != NULL) {
             surface = new Surface(surfaceShim.graphicBufferProducer);
         }
-
+#endif
         mSurfaceList.push_back(surface);
     }
 
@@ -206,9 +210,13 @@
             parcel->writeString16(String16("android.view.Surface"));
 
             // Surface.writeToParcel
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+            view::Surface surfaceShim = view::Surface::fromSurface(mSurfaceList[i]);
+#else
             view::Surface surfaceShim;
             surfaceShim.name = String16("unknown_name");
             surfaceShim.graphicBufferProducer = mSurfaceList[i]->getIGraphicBufferProducer();
+#endif
             if ((err = surfaceShim.writeToParcel(parcel)) != OK) {
                 ALOGE("%s: Failed to write output target Surface %d to parcel: %s (%d)",
                         __FUNCTION__, i, strerror(-err), err);
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index a89d7ca..f67214b 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -37,9 +37,8 @@
 const int OutputConfiguration::ROTATION_0 = 0;
 const int OutputConfiguration::INVALID_SET_ID = -1;
 
-const std::vector<sp<IGraphicBufferProducer>>&
-        OutputConfiguration::getGraphicBufferProducers() const {
-    return mGbps;
+const std::vector<ParcelableSurfaceType>& OutputConfiguration::getSurfaces() const {
+    return mSurfaces;
 }
 
 int OutputConfiguration::getRotation() const {
@@ -102,24 +101,23 @@
     return mMirrorMode;
 }
 
-int OutputConfiguration::getMirrorMode(sp<IGraphicBufferProducer> surface) const {
+int OutputConfiguration::getMirrorMode(ParcelableSurfaceType surface) const {
     if (!flags::mirror_mode_shared_surfaces()) {
         return mMirrorMode;
     }
 
-    if (mGbps.size() != mMirrorModeForProducers.size()) {
-        ALOGE("%s: mGbps size doesn't match mMirrorModeForProducers: %zu vs %zu",
-                __FUNCTION__, mGbps.size(), mMirrorModeForProducers.size());
+    if (mSurfaces.size() != mMirrorModeForProducers.size()) {
+        ALOGE("%s: mSurfaces size doesn't match mMirrorModeForProducers: %zu vs %zu",
+                __FUNCTION__, mSurfaces.size(), mMirrorModeForProducers.size());
         return mMirrorMode;
     }
 
     // Use per-producer mirror mode if available.
-    for (size_t i = 0; i < mGbps.size(); i++) {
-        if (mGbps[i] == surface) {
+    for (size_t i = 0; i < mSurfaces.size(); i++) {
+        if (mSurfaces[i] == surface) {
             return mMirrorModeForProducers[i];
         }
     }
-
     // For surface that doesn't belong to this output configuration, use
     // mMirrorMode as default.
     ALOGW("%s: Surface doesn't belong to this OutputConfiguration!", __FUNCTION__);
@@ -144,9 +142,9 @@
 
 bool OutputConfiguration::isComplete() const {
     return !((mSurfaceType == SURFACE_TYPE_MEDIA_RECORDER ||
-             mSurfaceType == SURFACE_TYPE_MEDIA_CODEC ||
-             mSurfaceType == SURFACE_TYPE_IMAGE_READER) &&
-             mGbps.empty());
+              mSurfaceType == SURFACE_TYPE_MEDIA_CODEC ||
+              mSurfaceType == SURFACE_TYPE_IMAGE_READER) &&
+             mSurfaces.empty());
 }
 
 OutputConfiguration::OutputConfiguration() :
@@ -348,7 +346,7 @@
         ALOGV("%s: OutputConfiguration: %p, name %s", __FUNCTION__,
                 surface.graphicBufferProducer.get(),
                 toString8(surface.name).c_str());
-        mGbps.push_back(surface.graphicBufferProducer);
+        mSurfaces.push_back(flagtools::toParcelableSurfaceType(surface));
     }
 
     mSensorPixelModesUsed = std::move(sensorPixelModesUsed);
@@ -369,10 +367,10 @@
     return err;
 }
 
-OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+OutputConfiguration::OutputConfiguration(ParcelableSurfaceType& surface, int rotation,
         const std::string& physicalId,
         int surfaceSetID, bool isShared) {
-    mGbps.push_back(gbp);
+    mSurfaces.push_back(surface);
     mRotation = rotation;
     mSurfaceSetID = surfaceSetID;
     mIsDeferred = false;
@@ -392,17 +390,17 @@
 }
 
 OutputConfiguration::OutputConfiguration(
-        const std::vector<sp<IGraphicBufferProducer>>& gbps,
+        const std::vector<ParcelableSurfaceType>& surfaces,
     int rotation, const std::string& physicalCameraId, int surfaceSetID,  int surfaceType,
     int width, int height, bool isShared)
-  : mGbps(gbps), mRotation(rotation), mSurfaceSetID(surfaceSetID), mSurfaceType(surfaceType),
-    mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared),
-    mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false),
+  : mSurfaces(surfaces), mRotation(rotation), mSurfaceSetID(surfaceSetID),
+    mSurfaceType(surfaceType), mWidth(width), mHeight(height), mIsDeferred(false),
+    mIsShared(isShared), mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false),
     mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
     mColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
     mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
     mTimestampBase(TIMESTAMP_BASE_DEFAULT),
-    mMirrorMode(MIRROR_MODE_AUTO), mMirrorModeForProducers(gbps.size(), mMirrorMode),
+    mMirrorMode(MIRROR_MODE_AUTO), mMirrorModeForProducers(surfaces.size(), mMirrorMode),
     mUseReadoutTimestamp(false), mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
     mDataspace(0), mUsage(0) { }
 
@@ -432,14 +430,18 @@
     err = parcel->writeInt32(mIsShared ? 1 : 0);
     if (err != OK) return err;
 
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+    err = parcel->writeParcelableVector(mSurfaces);
+#else
     std::vector<view::Surface> surfaceShims;
-    for (auto& gbp : mGbps) {
+    for (auto& gbp : mSurfaces) {
         view::Surface surfaceShim;
         surfaceShim.name = String16("unknown_name"); // name of surface
         surfaceShim.graphicBufferProducer = gbp;
         surfaceShims.push_back(surfaceShim);
     }
     err = parcel->writeParcelableVector(surfaceShims);
+#endif
     if (err != OK) return err;
 
     String16 physicalCameraId = toString16(mPhysicalCameraId);
@@ -513,10 +515,9 @@
     return false;
 }
 
-bool OutputConfiguration::gbpsEqual(const OutputConfiguration& other) const {
-    const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
-            other.getGraphicBufferProducers();
-    return simpleVectorsEqual(otherGbps, mGbps);
+bool OutputConfiguration::surfacesEqual(const OutputConfiguration& other) const {
+    const std::vector<ParcelableSurfaceType>& otherSurfaces = other.getSurfaces();
+    return simpleVectorsEqual(otherSurfaces, mSurfaces);
 }
 
 bool OutputConfiguration::sensorPixelModesUsedEqual(const OutputConfiguration& other) const {
@@ -527,7 +528,6 @@
 bool OutputConfiguration::mirrorModesEqual(const OutputConfiguration& other) const {
     const std::vector<int>& otherMirrorModes = other.getMirrorModes();
     return simpleVectorsEqual(otherMirrorModes, mMirrorModeForProducers);
-
 }
 
 bool OutputConfiguration::sensorPixelModesUsedLessThan(const OutputConfiguration& other) const {
@@ -540,17 +540,16 @@
     return simpleVectorsLessThan(mMirrorModeForProducers, otherMirrorModes);
 }
 
-bool OutputConfiguration::gbpsLessThan(const OutputConfiguration& other) const {
-    const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
-            other.getGraphicBufferProducers();
+bool OutputConfiguration::surfacesLessThan(const OutputConfiguration& other) const {
+    const std::vector<ParcelableSurfaceType>& otherSurfaces = other.getSurfaces();
 
-    if (mGbps.size() !=  otherGbps.size()) {
-        return mGbps.size() < otherGbps.size();
+    if (mSurfaces.size() != otherSurfaces.size()) {
+        return mSurfaces.size() < otherSurfaces.size();
     }
 
-    for (size_t i = 0; i < mGbps.size(); i++) {
-        if (mGbps[i] != otherGbps[i]) {
-            return mGbps[i] < otherGbps[i];
+    for (size_t i = 0; i < mSurfaces.size(); i++) {
+        if (mSurfaces[i] != otherSurfaces[i]) {
+            return mSurfaces[i] < otherSurfaces[i];
         }
     }
 
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 2feebb4..5682ad2 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"
@@ -256,3 +263,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    namespace: "camera_platform"
+    name: "fmq_metadata"
+    description: "Allow CameraMetadata transfer for ndk / sdk clients."
+    bug: "362791857"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
\ No newline at end of file
diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
index 2903dfb..10ecc4f 100644
--- a/camera/include/camera/CameraMetadata.h
+++ b/camera/include/camera/CameraMetadata.h
@@ -247,6 +247,38 @@
      */
     metadata_vendor_id_t getVendorId() const;
 
+   // Needed for auto-generated code if CameraMetadata is used in
+   // parcelables in .aidl files.
+   inline bool operator == (const CameraMetadata& rhs) const {
+        return mBuffer == rhs.mBuffer;
+    }
+
+    inline bool operator < (const CameraMetadata& rhs) const {
+        return mBuffer < rhs.mBuffer;
+    }
+
+    inline bool operator != (const CameraMetadata& rhs) const {
+        return !(*this == rhs);
+    }
+
+    inline bool operator > (const CameraMetadata& rhs) const {
+        return rhs < *this;
+    }
+
+    inline bool operator >= (const CameraMetadata& rhs) const {
+        return !(*this < rhs);
+    }
+
+    inline bool operator <= (const CameraMetadata& rhs) const {
+        return !(rhs < *this);
+    }
+
+  inline std::string toString() const {
+        std::string descStr = "CameraMetadata";
+        return descStr;
+  }
+
+
   private:
     camera_metadata_t *mBuffer;
     mutable bool       mLocked;
@@ -265,7 +297,6 @@
      * Resize metadata buffer if needed by reallocating it and copying it over.
      */
     status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
-
 };
 
 namespace hardware {
diff --git a/camera/include/camera/CaptureResult.h b/camera/include/camera/CaptureResult.h
index e08c9ca..cc6b529 100644
--- a/camera/include/camera/CaptureResult.h
+++ b/camera/include/camera/CaptureResult.h
@@ -20,7 +20,7 @@
 #include <utils/RefBase.h>
 #include <binder/Parcelable.h>
 #include <camera/CameraMetadata.h>
-
+#include <android/hardware/camera2/CameraMetadataInfo.h>
 
 namespace android {
 
@@ -145,19 +145,26 @@
 };
 
 struct PhysicalCaptureResultInfo : public android::Parcelable {
-
+    using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
     PhysicalCaptureResultInfo()
         : mPhysicalCameraId(),
-          mPhysicalCameraMetadata() {
+          mCameraMetadataInfo() {
     }
     PhysicalCaptureResultInfo(const std::string& cameraId,
             const CameraMetadata& cameraMetadata)
-            : mPhysicalCameraId(cameraId),
-              mPhysicalCameraMetadata(cameraMetadata) {
+            : mPhysicalCameraId(cameraId) {
+              mCameraMetadataInfo.set<CameraMetadataInfo::metadata>(cameraMetadata);
+    }
+
+   PhysicalCaptureResultInfo(const std::string& cameraId,
+            uint64_t fmqSize)
+            : mPhysicalCameraId(cameraId) {
+              mCameraMetadataInfo.set<CameraMetadataInfo::fmqSize>(fmqSize);
     }
 
     std::string mPhysicalCameraId;
-    CameraMetadata mPhysicalCameraMetadata;
+
+    CameraMetadataInfo mCameraMetadataInfo;
 
     virtual status_t                readFromParcel(const android::Parcel* parcel) override;
     virtual status_t                writeToParcel(android::Parcel* parcel) const override;
diff --git a/camera/include/camera/android/hardware/ICamera.h b/camera/include/camera/android/hardware/ICamera.h
index eb887fb..3c1670a 100644
--- a/camera/include/camera/android/hardware/ICamera.h
+++ b/camera/include/camera/android/hardware/ICamera.h
@@ -34,8 +34,13 @@
 
 class ICameraClient;
 
-class ICamera: public android::IInterface
-{
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+typedef Surface ProducerType;
+#else
+typedef IGraphicBufferProducer ProducerType;
+#endif
+
+class ICamera : public android::IInterface {
     /**
      * Keep up-to-date with ICamera.aidl in frameworks/base
      */
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 671d065..13bedb3 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -19,7 +19,12 @@
 
 #include <string>
 
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#include <gui/view/Surface.h>
+#else
 #include <gui/IGraphicBufferProducer.h>
+#endif
 #include <binder/Parcelable.h>
 
 namespace android {
@@ -59,7 +64,7 @@
         MIRROR_MODE_V = 3,
     };
 
-    const std::vector<sp<IGraphicBufferProducer>>& getGraphicBufferProducers() const;
+    const std::vector<ParcelableSurfaceType>& getSurfaces() const;
     int                        getRotation() const;
     int                        getSurfaceSetID() const;
     int                        getSurfaceType() const;
@@ -73,7 +78,7 @@
     bool                       isMultiResolution() const;
     int64_t                    getStreamUseCase() const;
     int                        getTimestampBase() const;
-    int                        getMirrorMode(sp<IGraphicBufferProducer> surface) const;
+    int                        getMirrorMode(ParcelableSurfaceType surface) const;
     int                        getMirrorMode() const;
     bool                       useReadoutTimestamp() const;
     int                        getFormat() const;
@@ -100,11 +105,11 @@
     // getSurfaceSetID will be INVALID_SET_ID if error occurred
     OutputConfiguration(const android::Parcel& parcel);
 
-    OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+    OutputConfiguration(ParcelableSurfaceType& surface, int rotation,
             const std::string& physicalCameraId,
             int surfaceSetID = INVALID_SET_ID, bool isShared = false);
 
-    OutputConfiguration(const std::vector<sp<IGraphicBufferProducer>>& gbps,
+    OutputConfiguration(const std::vector<ParcelableSurfaceType>& surfaces,
                         int rotation, const std::string& physicalCameraId,
                         int surfaceSetID = INVALID_SET_ID,
                         int surfaceType = SURFACE_TYPE_UNKNOWN, int width = 0,
@@ -121,7 +126,7 @@
                 mHeight == other.mHeight &&
                 mIsDeferred == other.mIsDeferred &&
                 mIsShared == other.mIsShared &&
-                gbpsEqual(other) &&
+                surfacesEqual(other) &&
                 mPhysicalCameraId == other.mPhysicalCameraId &&
                 mIsMultiResolution == other.mIsMultiResolution &&
                 sensorPixelModesUsedEqual(other) &&
@@ -201,18 +206,21 @@
         if (mUsage != other.mUsage) {
             return mUsage < other.mUsage;
         }
-        return gbpsLessThan(other);
+        return surfacesLessThan(other);
     }
 
     bool operator > (const OutputConfiguration& other) const {
         return (*this != other && !(*this < other));
     }
 
-    bool gbpsEqual(const OutputConfiguration& other) const;
+    bool surfacesEqual(const OutputConfiguration& other) const;
     bool sensorPixelModesUsedEqual(const OutputConfiguration& other) const;
     bool sensorPixelModesUsedLessThan(const OutputConfiguration& other) const;
-    bool gbpsLessThan(const OutputConfiguration& other) const;
-    void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {mGbps.push_back(gbp);}
+    bool surfacesLessThan(const OutputConfiguration& other) const;
+    void addSurface(ParcelableSurfaceType surface) { mSurfaces.push_back(surface); }
+#if not WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+    void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {addSurface(gbp);}
+#endif
     bool mirrorModesEqual(const OutputConfiguration& other) const;
     bool mirrorModesLessThan(const OutputConfiguration& other) const;
     const std::vector<int32_t>& getMirrorModes() const {return mMirrorModeForProducers;}
@@ -239,7 +247,7 @@
     }
 
 private:
-    std::vector<sp<IGraphicBufferProducer>> mGbps;
+    std::vector<ParcelableSurfaceType>  mSurfaces;
     int                        mRotation;
     int                        mSurfaceSetID;
     int                        mSurfaceType;
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 508808f..fc1e547 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -79,6 +79,8 @@
     shared_libs: [
         "android.companion.virtual.virtualdevice_aidl-cpp",
         "android.companion.virtualdevice.flags-aconfig-cc",
+        "android.hardware.common-V2-cpp",
+        "android.hardware.common.fmq-V1-cpp",
         "camera_platform_flags_c_lib",
         "framework-permission-aidl-cpp",
         "libandroid_runtime",
@@ -86,6 +88,7 @@
         "libcamera_client",
         "libcamera_metadata",
         "libcutils",
+        "libfmq",
         "libgui",
         "liblog",
         "libmediandk",
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index aed740f..4d21467 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -37,6 +37,8 @@
 namespace android {
 namespace acam {
 
+using android::hardware::common::fmq::MQDescriptor;
+
 // Static member definitions
 const char* CameraDevice::kContextKey        = "Context";
 const char* CameraDevice::kDeviceKey         = "Device";
@@ -231,25 +233,27 @@
     SessionConfiguration sessionConfiguration(0 /*inputWidth*/, 0 /*inputHeight*/,
             -1 /*inputFormat*/, CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE);
     for (const auto& output : sessionOutputContainer->mOutputs) {
-        sp<IGraphicBufferProducer> iGBP(nullptr);
-        ret = getIGBPfromAnw(output.mWindow, iGBP);
+        sp<SurfaceType> surface(nullptr);
+        ret = getSurfacefromAnw(output.mWindow, surface);
         if (ret != ACAMERA_OK) {
             ALOGE("Camera device %s failed to extract graphic producer from native window",
                     getId());
             return ret;
         }
 
-        OutputConfiguration outConfig(iGBP, output.mRotation, output.mPhysicalCameraId,
+        ParcelableSurfaceType pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+        OutputConfiguration outConfig(pSurface, output.mRotation, output.mPhysicalCameraId,
                 OutputConfiguration::INVALID_SET_ID, true);
 
         for (auto& anw : output.mSharedWindows) {
-            ret = getIGBPfromAnw(anw, iGBP);
+            ret = getSurfacefromAnw(anw, surface);
             if (ret != ACAMERA_OK) {
                 ALOGE("Camera device %s failed to extract graphic producer from native window",
                         getId());
                 return ret;
             }
-            outConfig.addGraphicProducer(iGBP);
+            pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+            outConfig.addSurface(pSurface);
         }
 
         sessionConfiguration.addOutputConfiguration(outConfig);
@@ -295,25 +299,27 @@
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
 
-    sp<IGraphicBufferProducer> iGBP(nullptr);
-    ret = getIGBPfromAnw(output->mWindow, iGBP);
+    sp<SurfaceType> surface(nullptr);
+    ret = getSurfacefromAnw(output->mWindow, surface);
     if (ret != ACAMERA_OK) {
         ALOGE("Camera device %s failed to extract graphic producer from native window",
                 getId());
         return ret;
     }
 
-    OutputConfiguration outConfig(iGBP, output->mRotation, output->mPhysicalCameraId,
-            OutputConfiguration::INVALID_SET_ID, true);
+    ParcelableSurfaceType pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+    OutputConfiguration outConfig(pSurface, output->mRotation, output->mPhysicalCameraId,
+                                  OutputConfiguration::INVALID_SET_ID, true);
 
     for (auto& anw : output->mSharedWindows) {
-        ret = getIGBPfromAnw(anw, iGBP);
+        ret = getSurfacefromAnw(anw, surface);
         if (ret != ACAMERA_OK) {
             ALOGE("Camera device %s failed to extract graphic producer from native window",
                     getId());
             return ret;
         }
-        outConfig.addGraphicProducer(iGBP);
+        pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+        outConfig.addSurface(pSurface);
     }
 
     auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
@@ -427,9 +433,9 @@
         for (const auto& kvPair : mConfiguredOutputs) {
             int streamId = kvPair.first;
             const OutputConfiguration& outConfig = kvPair.second.second;
-            const auto& gbps = outConfig.getGraphicBufferProducers();
-            for (int surfaceId = 0; surfaceId < (int) gbps.size(); surfaceId++) {
-                if (gbps[surfaceId] == surface->getIGraphicBufferProducer()) {
+            const auto& surfaces = outConfig.getSurfaces();
+            for (int surfaceId = 0; surfaceId < (int)surfaces.size(); surfaceId++) {
+                if (surfaces[surfaceId] == flagtools::surfaceToSurfaceType(surface)) {
                     found = true;
                     req->mStreamIdxList.push_back(streamId);
                     req->mSurfaceIdxList.push_back(surfaceId);
@@ -634,16 +640,13 @@
     return ACAMERA_OK;
 }
 
-camera_status_t
-CameraDevice::getIGBPfromAnw(
-        ANativeWindow* anw,
-        sp<IGraphicBufferProducer>& out) {
+camera_status_t CameraDevice::getSurfacefromAnw(ANativeWindow* anw, sp<SurfaceType>& out) {
     sp<Surface> surface;
     camera_status_t ret = getSurfaceFromANativeWindow(anw, surface);
     if (ret != ACAMERA_OK) {
         return ret;
     }
-    out = surface->getIGraphicBufferProducer();
+    out = flagtools::surfaceToSurfaceType(surface);
     return ACAMERA_OK;
 }
 
@@ -681,14 +684,16 @@
     std::set<std::pair<ANativeWindow*, OutputConfiguration>> outputSet;
     for (const auto& outConfig : outputs->mOutputs) {
         ANativeWindow* anw = outConfig.mWindow;
-        sp<IGraphicBufferProducer> iGBP(nullptr);
-        ret = getIGBPfromAnw(anw, iGBP);
+        sp<SurfaceType> surface(nullptr);
+        ret = getSurfacefromAnw(anw, surface);
         if (ret != ACAMERA_OK) {
             return ret;
         }
+        ParcelableSurfaceType pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
         outputSet.insert(std::make_pair(
-                anw, OutputConfiguration(iGBP, outConfig.mRotation, outConfig.mPhysicalCameraId,
-                        OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
+                anw,
+                OutputConfiguration(pSurface, outConfig.mRotation, outConfig.mPhysicalCameraId,
+                                    OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
     }
     auto addSet = outputSet;
     std::vector<int> deleteList;
@@ -788,6 +793,27 @@
     mRemote = remote;
 }
 
+bool CameraDevice::setDeviceMetadataQueues() {
+    if (mRemote == nullptr) {
+        ALOGE("mRemote must not be null while trying to fetch metadata queues");
+        return false;
+    }
+    MQDescriptor<int8_t, SynchronizedReadWrite> resMqDescriptor;
+    binder::Status ret = mRemote->getCaptureResultMetadataQueue(&resMqDescriptor);
+    if (!ret.isOk()) {
+        ALOGE("Transaction error trying to get capture result metadata queue");
+        return false;
+    }
+    mCaptureResultMetadataQueue = std::make_unique<ResultMetadataQueue>(resMqDescriptor);
+    if (!mCaptureResultMetadataQueue->isValid()) {
+        ALOGE("Empty fmq from cameraserver");
+        mCaptureResultMetadataQueue = nullptr;
+        return false;
+    }
+
+    return true;
+}
+
 camera_status_t
 CameraDevice::checkCameraClosedOrErrorLocked() const {
     if (mRemote == nullptr) {
@@ -885,10 +911,14 @@
             return;
         }
 
-        const auto& gbps = outputPairIt->second.second.getGraphicBufferProducers();
-        for (const auto& outGbp : gbps) {
+        const auto& outSurfaces = outputPairIt->second.second.getSurfaces();
+        for (const auto& outSurface : outSurfaces) {
             for (const auto& surface : request->mSurfaceList) {
-                if (surface->getIGraphicBufferProducer() == outGbp) {
+                if ( outSurface == surface
+#if not WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                                ->getIGraphicBufferProducer()
+#endif
+                                            ) {
                     ANativeWindow* anw = static_cast<ANativeWindow*>(surface.get());
                     ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
                             getId(), anw, frameNumber);
@@ -1247,7 +1277,9 @@
                         String8 physicalId8 = toString8(physicalResultInfo[i].mPhysicalCameraId);
                         physicalCameraIds.push_back(physicalId8.c_str());
 
-                        CameraMetadata clone = physicalResultInfo[i].mPhysicalCameraMetadata;
+                        CameraMetadata clone =
+                                physicalResultInfo[i].
+                                        mCameraMetadataInfo.get<CameraMetadataInfo::metadata>();
                         clone.update(ANDROID_SYNC_FRAME_NUMBER,
                                 &physicalResult->mFrameNumber, /*data_count*/1);
                         sp<ACameraMetadata> metadata =
@@ -1777,7 +1809,7 @@
 
 binder::Status
 CameraDevice::ServiceCallback::onResultReceived(
-        const CameraMetadata& metadata,
+        const CameraMetadataInfo &resultMetadata,
         const CaptureResultExtras& resultExtras,
         const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
     binder::Status ret = binder::Status::ok();
@@ -1786,11 +1818,11 @@
     if (dev == nullptr) {
         return ret; // device has been closed
     }
+
     int sequenceId = resultExtras.requestId;
     int64_t frameNumber = resultExtras.frameNumber;
     int32_t burstId = resultExtras.burstId;
     bool    isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
-
     if (!isPartialResult) {
         ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
     }
@@ -1808,7 +1840,13 @@
         return ret;
     }
 
-    CameraMetadata metadataCopy = metadata;
+    CameraMetadata metadataCopy;
+    camera_status_t status = readOneResultMetadata(resultMetadata,
+            dev->mCaptureResultMetadataQueue.get(), &metadataCopy);
+    if (status != ACAMERA_OK) {
+        ALOGE("%s: result metadata couldn't be converted", __FUNCTION__);
+        return ret;
+    }
     metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
     metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /*data_count*/1);
 
@@ -1824,8 +1862,24 @@
         sp<CaptureRequest> request = cbh.mRequests[burstId];
         sp<ACameraMetadata> result(new ACameraMetadata(
                 metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+
+        std::vector<PhysicalCaptureResultInfo> localPhysicalResult;
+        localPhysicalResult.resize(physicalResultInfos.size());
+        for (size_t i = 0; i < physicalResultInfos.size(); i++) {
+            CameraMetadata physicalMetadata;
+            localPhysicalResult[i].mPhysicalCameraId = physicalResultInfos[i].mPhysicalCameraId;
+            status = readOneResultMetadata(physicalResultInfos[i].mCameraMetadataInfo,
+                    dev->mCaptureResultMetadataQueue.get(),
+                    &physicalMetadata);
+            if (status != ACAMERA_OK) {
+                ALOGE("%s: physical camera result metadata couldn't be converted", __FUNCTION__);
+                return ret;
+            }
+            localPhysicalResult[i].mCameraMetadataInfo.set<CameraMetadataInfo::metadata>(
+                    std::move(physicalMetadata));
+        }
         sp<ACameraPhysicalCaptureResultInfo> physicalResult(
-                new ACameraPhysicalCaptureResultInfo(physicalResultInfos, frameNumber));
+                new ACameraPhysicalCaptureResultInfo(localPhysicalResult, frameNumber));
 
         sp<AMessage> msg = new AMessage(
                 cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
@@ -1946,5 +2000,28 @@
     }
 }
 
+camera_status_t CameraDevice::ServiceCallback::readOneResultMetadata(
+        const CameraMetadataInfo& resultInfo, ResultMetadataQueue* metadataQueue,
+        CameraMetadata* metadata) {
+    if (metadataQueue == nullptr || metadata == nullptr) {
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if (resultInfo.getTag() == CameraMetadataInfo::fmqSize) {
+        int64_t metadataSize = resultInfo.get<CameraMetadataInfo::fmqSize>();
+        auto metadataVec = std::make_unique<int8_t []>(metadataSize);
+        bool read = metadataQueue->read(reinterpret_cast<int8_t*>(metadataVec.get()), metadataSize);
+        if (!read) {
+            ALOGE("%s capture request settings could't be read from fmq", __FUNCTION__);
+            return ACAMERA_ERROR_UNKNOWN;
+        }
+        *metadata = CameraMetadata(reinterpret_cast<camera_metadata_t *>(metadataVec.release()));
+    } else {
+        *metadata =
+                resultInfo.get<CameraMetadataInfo::metadata>();
+    }
+
+    return ACAMERA_OK;
+}
+
 } // namespace acam
 } // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index d3aed4b..ea7d9b6 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -37,15 +37,20 @@
 #include <camera/camera2/OutputConfiguration.h>
 #include <camera/camera2/SessionConfiguration.h>
 #include <camera/camera2/CaptureRequest.h>
+#include <fmq/AidlMessageQueueCpp.h>
 
-#include <camera/NdkCameraManager.h>
 #include <camera/NdkCameraCaptureSession.h>
+#include <camera/NdkCameraManager.h>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
 
 #include "ACameraMetadata.h"
 
 namespace android {
 namespace acam {
 
+using android::hardware::common::fmq::SynchronizedReadWrite;
+using ResultMetadataQueue = AidlMessageQueueCpp<int8_t, SynchronizedReadWrite>;
+
 // Wrap ACameraCaptureFailure so it can be ref-counted
 struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
 
@@ -61,6 +66,8 @@
 
 class CameraDevice final : public RefBase {
   public:
+
+    using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
     CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
                   sp<ACameraMetadata> chars,
                   ACameraDevice* wrapper, bool sharedMode);
@@ -91,7 +98,7 @@
         binder::Status onDeviceIdle() override;
         binder::Status onCaptureStarted(const CaptureResultExtras& resultExtras,
                               int64_t timestamp) override;
-        binder::Status onResultReceived(const CameraMetadata& metadata,
+        binder::Status onResultReceived(const CameraMetadataInfo &resultInfo,
                               const CaptureResultExtras& resultExtras,
                               const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) override;
         binder::Status onPrepared(int streamId) override;
@@ -100,6 +107,9 @@
                 int32_t stoppedSequenceId) override;
         binder::Status onClientSharedAccessPriorityChanged(bool isPrimaryClient) override;
       private:
+        camera_status_t readOneResultMetadata(
+                const CameraMetadataInfo& resultInfo, ResultMetadataQueue* metadataQueue,
+                CameraMetadata* metadata);
         const wp<CameraDevice> mDevice;
     };
     inline sp<hardware::camera2::ICameraDeviceCallbacks> getServiceCallback() {
@@ -108,6 +118,7 @@
 
     // Camera device is only functional after remote being set
     void setRemoteDevice(sp<hardware::camera2::ICameraDeviceUser> remote);
+    bool setDeviceMetadataQueues();
 
     inline ACameraDevice* getWrapper() const { return mWrapper; };
 
@@ -178,8 +189,10 @@
     // Input message will be posted and cleared after this returns
     void postSessionMsgAndCleanup(sp<AMessage>& msg);
 
-    static camera_status_t getIGBPfromAnw(
-            ANativeWindow* anw, sp<IGraphicBufferProducer>& out);
+    // Only used when WB_LIBCAMERASERVICE_WITH_DEPENDENCIES is active
+    static ParcelableSurfaceType convertSurfaceTypeToView(sp<SurfaceType> surface);
+
+    static camera_status_t getSurfacefromAnw(ANativeWindow* anw, sp<SurfaceType>& out);
 
     static camera_status_t getSurfaceFromANativeWindow(
             ANativeWindow* anw, sp<Surface>& out);
@@ -399,6 +412,9 @@
     int32_t mPartialResultCount;  // const after constructor
     std::vector<std::string> mPhysicalIds; // const after constructor
 
+    // Metadata queue to write the result metadata to.
+    std::unique_ptr<ResultMetadataQueue> mCaptureResultMetadataQueue;
+
 };
 
 } // namespace acam;
@@ -452,6 +468,10 @@
         mDevice->setRemoteDevice(remote);
     }
 
+    inline bool setDeviceMetadataQueues() {
+        return mDevice->setDeviceMetadataQueues();
+    }
+
     inline void setPrimaryClient(bool isPrimary) {
         mDevice->setPrimaryClient(isPrimary);
     }
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index f9c1a8a..acd7917 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -971,6 +971,7 @@
         return ACAMERA_ERROR_CAMERA_DISCONNECTED;
     }
     device->setRemoteDevice(deviceRemote);
+    device->setDeviceMetadataQueues();
     if (flags::camera_multi_client() && sharedMode) {
         binder::Status remoteRet = deviceRemote->isPrimaryClient(primaryClient);
         if (!remoteRet.isOk()) {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 4384df9..5f7f2f6 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -63,6 +63,7 @@
 using namespace android;
 using ::android::hardware::ICameraService;
 using ::android::hardware::camera2::ICameraDeviceUser;
+using ::android::hardware::camera2::CameraMetadataInfo;
 
 #define ASSERT_NOT_NULL(x) \
     ASSERT_TRUE((x) != nullptr)
@@ -249,10 +250,10 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onResultReceived(const CameraMetadata& metadata,
+    virtual binder::Status onResultReceived(const CameraMetadataInfo& resultInfo,
             const CaptureResultExtras& resultExtras,
             const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
-        (void) metadata;
+        (void) resultInfo;
         (void) resultExtras;
         (void) physicalResultInfos;
         Mutex::Autolock l(mLock);
diff --git a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
index b6fa817..22e04fc 100644
--- a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
@@ -19,6 +19,7 @@
 #include <fuzzer/FuzzedDataProvider.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
 #include <gui/SurfaceComposerClient.h>
 #include "camera2common.h"
 
@@ -37,11 +38,11 @@
   private:
     void invokeC2OutputConfigFuzzer();
     unique_ptr<OutputConfiguration> getC2OutputConfig();
-    sp<IGraphicBufferProducer> createIGraphicBufferProducer();
+    sp<SurfaceType> createSurface();
     FuzzedDataProvider* mFDP = nullptr;
 };
 
-sp<IGraphicBufferProducer> C2OutputConfigurationFuzzer::createIGraphicBufferProducer() {
+sp<SurfaceType> C2OutputConfigurationFuzzer::createSurface() {
     sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
     sp<SurfaceControl> surfaceControl = composerClient->createSurface(
             static_cast<String8>(mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()) /* name */,
@@ -51,10 +52,9 @@
             mFDP->ConsumeIntegral<int32_t>() /* flags */);
     if (surfaceControl) {
         sp<Surface> surface = surfaceControl->getSurface();
-        return surface->getIGraphicBufferProducer();
+        return flagtools::surfaceToSurfaceType(surface);
     } else {
-        sp<IGraphicBufferProducer> gbp;
-        return gbp;
+        return nullptr;
     }
 }
 
@@ -69,9 +69,9 @@
                         string physicalCameraId = mFDP->ConsumeRandomLengthString(kMaxBytes);
                         int32_t surfaceSetID = mFDP->ConsumeIntegral<int32_t>();
                         bool isShared = mFDP->ConsumeBool();
-                        sp<IGraphicBufferProducer> iGBP = createIGraphicBufferProducer();
+                        sp<SurfaceType> surface = createSurface();
                         outputConfiguration = make_unique<OutputConfiguration>(
-                                iGBP, rotation, physicalCameraId, surfaceSetID, isShared);
+                                surface, rotation, physicalCameraId, surfaceSetID, isShared);
                     },
 
                     [&]() {
@@ -79,14 +79,15 @@
                         string physicalCameraId = mFDP->ConsumeRandomLengthString(kMaxBytes);
                         int32_t surfaceSetID = mFDP->ConsumeIntegral<int32_t>();
                         bool isShared = mFDP->ConsumeBool();
-                        size_t iGBPSize = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
-                        vector<sp<IGraphicBufferProducer>> iGBPs;
-                        for (size_t idx = 0; idx < iGBPSize; ++idx) {
-                            sp<IGraphicBufferProducer> iGBP = createIGraphicBufferProducer();
-                            iGBPs.push_back(iGBP);
+                        size_t surfaceSize =
+                                mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+                        vector<sp<SurfaceType>> surfaces;
+                        for (size_t idx = 0; idx < surfaceSize; ++idx) {
+                            sp<SurfaceType> surface = createSurface();
+                            surfaces.push_back(surface);
                         }
                         outputConfiguration = make_unique<OutputConfiguration>(
-                                iGBPs, rotation, physicalCameraId, surfaceSetID, isShared);
+                                surfaces, rotation, physicalCameraId, surfaceSetID, isShared);
                     },
             });
     selectOutputConfigurationConstructor();
@@ -107,22 +108,22 @@
                 [&]() { outputConfiguration->isDeferred(); },
                 [&]() { outputConfiguration->isShared(); },
                 [&]() { outputConfiguration->getPhysicalCameraId(); },
-                [&]() { outputConfiguration->gbpsEqual(*outputConfiguration2); },
+                [&]() { outputConfiguration->surfacesEqual(*outputConfiguration2); },
                 [&]() { outputConfiguration->sensorPixelModesUsedEqual(*outputConfiguration2); },
-                [&]() { outputConfiguration->gbpsLessThan(*outputConfiguration2); },
+                [&]() { outputConfiguration->surfacesLessThan(*outputConfiguration2); },
                 [&]() { outputConfiguration->sensorPixelModesUsedLessThan(*outputConfiguration2); },
-                [&]() { outputConfiguration->getGraphicBufferProducers(); },
+                [&]() { outputConfiguration->getSurfaces(); },
                 [&]() {
-                    sp<IGraphicBufferProducer> gbp = createIGraphicBufferProducer();
-                    outputConfiguration->addGraphicProducer(gbp);
+                    sp<SurfaceType> surface = createSurface();
+                    outputConfiguration->addSurface(surface);
                 },
                 [&]() { outputConfiguration->isMultiResolution(); },
                 [&]() { outputConfiguration->getColorSpace(); },
                 [&]() { outputConfiguration->getStreamUseCase(); },
                 [&]() { outputConfiguration->getTimestampBase(); },
                 [&]() {
-                    sp<IGraphicBufferProducer> gbp = createIGraphicBufferProducer();
-                    outputConfiguration->getMirrorMode(gbp);
+                    sp<SurfaceType> surface = createSurface();
+                    outputConfiguration->getMirrorMode(surface);
                 },
                 [&]() { outputConfiguration->useReadoutTimestamp(); },
         });
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/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index c820a2c..af82982 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -7,6 +7,7 @@
 
 flag {
   name: "aidl_hal_input_surface"
+  is_exported: true
   namespace: "codec_fwk"
   description: "Feature flags for enabling AIDL HAL InputSurface handling"
   bug: "201479783"
@@ -28,6 +29,13 @@
 }
 
 flag {
+  name: "codec_availability_support"
+  namespace: "codec_fwk"
+  description: "Feature flag for codec availability HAL API implementation"
+  bug: "363282971"
+}
+
+flag {
   name: "codec_buffer_state_cleanup"
   namespace: "codec_fwk"
   description: "Bugfix flag for more buffer state cleanup in MediaCodec"
diff --git a/media/aconfig/swcodec_flags.aconfig b/media/aconfig/swcodec_flags.aconfig
index a435a43..9dd1fdd 100644
--- a/media/aconfig/swcodec_flags.aconfig
+++ b/media/aconfig/swcodec_flags.aconfig
@@ -12,3 +12,12 @@
   description: "Feature flag for APV Software C2 codec"
   bug: "376770121"
 }
+
+flag {
+  name: "mpeg2_keep_threads_active"
+  is_exported: true
+  is_fixed_read_only: true
+  namespace: "codec_fwk"
+  description: "Enable keep_threads_active in mpeg2 decoder"
+  bug: "343793479"
+}
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/components/mpeg2/Android.bp b/media/codec2/components/mpeg2/Android.bp
index e644ee3..ed711ee 100644
--- a/media/codec2/components/mpeg2/Android.bp
+++ b/media/codec2/components/mpeg2/Android.bp
@@ -14,11 +14,10 @@
         "libcodec2_soft_sanitize_signed-defaults",
     ],
 
-    cflags: [
-        "-DKEEP_THREADS_ACTIVE=0",
-    ],
-
     srcs: ["C2SoftMpeg2Dec.cpp"],
 
-    static_libs: ["libmpeg2dec"],
+    static_libs: [
+        "libmpeg2dec",
+        "android.media.swcodec.flags-aconfig-cc",
+    ],
 }
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index 52920c2..64e4bf0 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -16,11 +16,10 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2SoftMpeg2Dec"
-#ifndef KEEP_THREADS_ACTIVE
-#define KEEP_THREADS_ACTIVE 0
-#endif
 #include <log/log.h>
 
+#include <android_media_swcodec_flags.h>
+
 #include <media/stagefright/foundation/MediaDefs.h>
 
 #include <C2Debug.h>
@@ -320,14 +319,7 @@
         c2_node_id_t id,
         const std::shared_ptr<IntfImpl> &intfImpl)
     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
-        mIntf(intfImpl),
-        mDecHandle(nullptr),
-        mMemRecords(nullptr),
-        mOutBufferDrain(nullptr),
-        mIvColorformat(IV_YUV_420P),
-        mWidth(320),
-        mHeight(240),
-        mOutIndex(0u) {
+        mIntf(intfImpl) {
     // If input dump is enabled, then open create an empty file
     GENERATE_FILE_NAMES();
     CREATE_DUMP_FILE(mInFile);
@@ -436,7 +428,7 @@
 
     s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
     s_fill_mem_ip.u4_share_disp_buf = 0;
-    s_fill_mem_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
+    s_fill_mem_ip.u4_keep_threads_active = mKeepThreadsActive;
     s_fill_mem_ip.e_output_format = mIvColorformat;
     s_fill_mem_ip.u4_deinterlace = 1;
     s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
@@ -478,7 +470,7 @@
     s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
     s_init_ip.u4_share_disp_buf = 0;
     s_init_ip.u4_deinterlace = 1;
-    s_init_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
+    s_init_ip.u4_keep_threads_active = mKeepThreadsActive;
     s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
     s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
     s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
@@ -571,6 +563,7 @@
     status_t ret = getNumMemRecords();
     if (OK != ret) return ret;
 
+    mKeepThreadsActive = android::media::swcodec::flags::mpeg2_keep_threads_active();
     ret = fillMemRecords();
     if (OK != ret) return ret;
 
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
index 3965bcc..6d09694 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
@@ -144,21 +144,22 @@
     };
 
     std::shared_ptr<IntfImpl> mIntf;
-    iv_obj_t *mDecHandle;
-    iv_mem_rec_t *mMemRecords;
-    size_t mNumMemRecords;
+    iv_obj_t *mDecHandle = nullptr;
+    iv_mem_rec_t *mMemRecords = nullptr;
+    size_t mNumMemRecords = 0;
     std::shared_ptr<C2GraphicBlock> mOutBlock;
-    uint8_t *mOutBufferDrain;
+    uint8_t *mOutBufferDrain = nullptr;
 
-    size_t mNumCores;
-    IV_COLOR_FORMAT_T mIvColorformat;
+    size_t mNumCores = 1;
+    IV_COLOR_FORMAT_T mIvColorformat = IV_YUV_420P;
 
-    uint32_t mWidth;
-    uint32_t mHeight;
-    uint32_t mStride;
-    bool mSignalledOutputEos;
-    bool mSignalledError;
-    std::atomic_uint64_t mOutIndex;
+    uint32_t mWidth = 320;
+    uint32_t mHeight = 240;
+    uint32_t mStride = 0;
+    bool mSignalledOutputEos = false;
+    bool mSignalledError = false;
+    bool mKeepThreadsActive = false;
+    std::atomic_uint64_t mOutIndex = 0;
 
     // Color aspects. These are ISO values and are meant to detect changes in aspects to avoid
     // converting them to C2 values for each frame
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/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 80735cb..6348e42 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -21,7 +21,9 @@
 #include <utils/Trace.h>
 
 #include <codec2/aidl/GraphicBufferAllocator.h>
+#include <codec2/common/HalSelection.h>
 #include <codec2/hidl/client.h>
+
 #include <C2Debug.h>
 #include <C2BufferPriv.h>
 #include <C2Config.h> // for C2StreamUsageTuning
@@ -1832,9 +1834,7 @@
 
 std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface(
         char const* serviceName) {
-    int32_t inputSurfaceSetting = ::android::base::GetIntProperty(
-            "debug.stagefright.c2inputsurface", int32_t(0));
-    if (inputSurfaceSetting <= 0) {
+    if (!IsCodec2AidlInputSurfaceSelected()) {
         return nullptr;
     }
     size_t index = GetServiceNames().size();
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
index 0638363..886391b 100644
--- a/media/codec2/hal/common/Android.bp
+++ b/media/codec2/hal/common/Android.bp
@@ -56,13 +56,17 @@
         "libaconfig_storage_read_api_cc",
     ],
 
-    static_libs: ["aconfig_mediacodec_flags_c_lib"],
+    static_libs: [
+        "aconfig_mediacodec_flags_c_lib",
+        "android.media.codec-aconfig-cc",
+    ],
 }
 
 cc_defaults {
     name: "libcodec2_hal_selection",
     static_libs: [
         "aconfig_mediacodec_flags_c_lib",
+        "android.media.codec-aconfig-cc",
         "libcodec2_hal_selection_static",
     ],
     shared_libs: [
diff --git a/media/codec2/hal/common/HalSelection.cpp b/media/codec2/hal/common/HalSelection.cpp
index d3ea181..5bf4fbe 100644
--- a/media/codec2/hal/common/HalSelection.cpp
+++ b/media/codec2/hal/common/HalSelection.cpp
@@ -21,6 +21,7 @@
 // NOTE: due to dependency from mainline modules cannot use libsysprop
 // #include <android/sysprop/MediaProperties.sysprop.h>
 #include <android-base/properties.h>
+#include <android_media_codec.h>
 #include <com_android_media_codec_flags.h>
 
 #include <codec2/common/HalSelection.h>
@@ -66,4 +67,20 @@
     return false;
 }
 
+bool IsCodec2AidlInputSurfaceSelected() {
+    if (!IsCodec2AidlHalSelected()) {
+        return false;
+    }
+
+    int32_t inputSurfaceSetting = ::android::base::GetIntProperty(
+            "debug.stagefright.c2inputsurface", int32_t(0));
+    if (inputSurfaceSetting <= 0) {
+        return false;
+    }
+    if (!android::media::codec::provider_->aidl_hal_input_surface()) {
+        return false;
+    }
+    return true;
+}
+
 }  // namespace android
diff --git a/media/codec2/hal/common/include/codec2/common/HalSelection.h b/media/codec2/hal/common/include/codec2/common/HalSelection.h
index 7c77515..bf0c7c5 100644
--- a/media/codec2/hal/common/include/codec2/common/HalSelection.h
+++ b/media/codec2/hal/common/include/codec2/common/HalSelection.h
@@ -22,6 +22,9 @@
 // Returns true iff AIDL c2 HAL is selected for the system
 bool IsCodec2AidlHalSelected();
 
+// Returns true iff AIDL c2 InputSurface interface is selected for the system
+bool IsCodec2AidlInputSurfaceSelected();
+
 }  // namespace android
 
 #endif  // CODEC2_HAL_SELECTION_H
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/codec2/tests/aidl/GraphicsTracker_test.cpp b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
index 9008086..da79277 100644
--- a/media/codec2/tests/aidl/GraphicsTracker_test.cpp
+++ b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
@@ -92,8 +92,7 @@
         sp<IGraphicBufferConsumer> consumer = mConsumer.promote();
         if (consumer != nullptr && consumer->acquireBuffer(&buffer, 0) == android::NO_ERROR) {
             ::usleep(kRenderDelayUs);
-            consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber,
-                                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, buffer.mFence);
+            consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber, buffer.mFence);
         }
     }
     void onBuffersReleased() override {}
@@ -438,8 +437,7 @@
     // Consume one buffer and release
     BufferItem item;
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
-    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
-            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence));
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence));
     // Nothing to consume
     ASSERT_NE(OK, mConsumer->acquireBuffer(&item, 0));
 
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..c3e7583 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;
 
@@ -845,6 +895,180 @@
 };
 typedef uint32_t aaudio_channel_mask_t;
 
+// The values are copied from JAVA SDK device types defined in android/media/AudioDeviceInfo.java
+// When a new value is added, it should be added here and handled by the conversion at
+// AAudioConvert_aaudioToAndroidDeviceType.
+typedef enum AAudio_DeviceType : int32_t {
+    /**
+     * A device type describing the attached earphone speaker.
+     */
+    AAUDIO_DEVICE_BUILTIN_EARPIECE = 1,
+
+    /**
+     * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
+     * in a device.
+     */
+    AAUDIO_DEVICE_BUILTIN_SPEAKER = 2,
+
+    /**
+     * A device type describing a headset, which is the combination of a headphones and microphone.
+     */
+    AAUDIO_DEVICE_WIRED_HEADSET = 3,
+
+    /**
+     * A device type describing a pair of wired headphones.
+     */
+    AAUDIO_DEVICE_WIRED_HEADPHONES = 4,
+
+    /**
+     * A device type describing an analog line-level connection.
+     */
+    AAUDIO_DEVICE_LINE_ANALOG = 5,
+
+    /**
+     * A device type describing a digital line connection (e.g. SPDIF).
+     */
+    AAUDIO_DEVICE_LINE_DIGITAL = 6,
+
+    /**
+     * A device type describing a Bluetooth device typically used for telephony.
+     */
+    AAUDIO_DEVICE_BLUETOOTH_SCO = 7,
+
+    /**
+     * A device type describing a Bluetooth device supporting the A2DP profile.
+     */
+    AAUDIO_DEVICE_BLUETOOTH_A2DP = 8,
+
+    /**
+     * A device type describing an HDMI connection .
+     */
+    AAUDIO_DEVICE_HDMI = 9,
+
+    /**
+     * A device type describing the Audio Return Channel of an HDMI connection.
+     */
+    AAUDIO_DEVICE_HDMI_ARC = 10,
+
+    /**
+     * A device type describing a USB audio device.
+     */
+    AAUDIO_DEVICE_USB_DEVICE = 11,
+
+    /**
+     * A device type describing a USB audio device in accessory mode.
+     */
+    AAUDIO_DEVICE_USB_ACCESSORY = 12,
+
+    /**
+     * A device type describing the audio device associated with a dock.
+     * Starting at API 34, this device type only represents digital docks, while docks with an
+     * analog connection are represented with {@link #AAUDIO_DEVICE_DOCK_ANALOG}.
+     */
+    AAUDIO_DEVICE_DOCK = 13,
+
+    /**
+     * A device type associated with the transmission of audio signals over FM.
+     */
+    AAUDIO_DEVICE_FM = 14,
+
+    /**
+     * A device type describing the microphone(s) built in a device.
+     */
+    AAUDIO_DEVICE_BUILTIN_MIC = 15,
+
+    /**
+     * A device type for accessing the audio content transmitted over FM.
+     */
+    AAUDIO_DEVICE_FM_TUNER = 16,
+
+    /**
+     * A device type for accessing the audio content transmitted over the TV tuner system.
+     */
+    AAUDIO_DEVICE_TV_TUNER = 17,
+
+    /**
+     * A device type describing the transmission of audio signals over the telephony network.
+     */
+    AAUDIO_DEVICE_TELEPHONY = 18,
+
+    /**
+     * A device type describing the auxiliary line-level connectors.
+     */
+    AAUDIO_DEVICE_AUX_LINE = 19,
+
+    /**
+     * A device type connected over IP.
+     */
+    AAUDIO_DEVICE_IP = 20,
+
+    /**
+     * A type-agnostic device used for communication with external audio systems.
+     */
+    AAUDIO_DEVICE_BUS = 21,
+
+    /**
+     * A device type describing a USB audio headset.
+     */
+    AAUDIO_DEVICE_USB_HEADSET = 22,
+
+    /**
+     * A device type describing a Hearing Aid.
+     */
+    AAUDIO_DEVICE_HEARING_AID = 23,
+
+    /**
+     * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
+     * in a device, that is specifically tuned for outputting sounds like notifications and alarms
+     * (i.e. sounds the user couldn't necessarily anticipate).
+     * <p>Note that this physical audio device may be the same as {@link #TYPE_BUILTIN_SPEAKER}
+     * but is driven differently to safely accommodate the different use case.</p>
+     */
+    AAUDIO_DEVICE_BUILTIN_SPEAKER_SAFE = 24,
+
+    /**
+     * A device type for rerouting audio within the Android framework between mixes and
+     * system applications.
+     */
+    AAUDIO_DEVICE_REMOTE_SUBMIX = 25,
+    /**
+     * A device type describing a Bluetooth Low Energy (BLE) audio headset or headphones.
+     * Headphones are grouped with headsets when the device is a sink:
+     * the features of headsets and headphones with regard to playback are the same.
+     */
+    AAUDIO_DEVICE_BLE_HEADSET = 26,
+
+    /**
+     * A device type describing a Bluetooth Low Energy (BLE) audio speaker.
+     */
+    AAUDIO_DEVICE_BLE_SPEAKER = 27,
+
+    /**
+     * A device type describing an Echo Canceller loopback Reference.
+     * This device is only used when capturing with MediaRecorder.AudioSource.ECHO_REFERENCE,
+     * which requires privileged permission
+     * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}.
+     *
+     * Note that this is not exposed as it is a system API that requires privileged permission.
+     */
+    // AAUDIO_DEVICE_ECHO_REFERENCE = 28,
+
+    /**
+     * A device type describing the Enhanced Audio Return Channel of an HDMI connection.
+     */
+    AAUDIO_DEVICE_HDMI_EARC = 29,
+
+    /**
+     * A device type describing a Bluetooth Low Energy (BLE) broadcast group.
+     */
+    AAUDIO_DEVICE_BLE_BROADCAST = 30,
+
+    /**
+     * A device type describing the audio device associated with a dock using an analog connection.
+     */
+    AAUDIO_DEVICE_DOCK_ANALOG = 31
+} AAudio_DeviceType;
+
 typedef struct AAudioStreamStruct         AAudioStream;
 typedef struct AAudioStreamBuilderStruct  AAudioStreamBuilder;
 
@@ -1090,7 +1314,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 +1700,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
@@ -1909,18 +2172,17 @@
  * Available since API level 26.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return actual device id. If there are multiple device ids used, the first device picked by
- *         the audio policy engine will be returned.
+ * @return actual device id. If there are multiple device ids used,
+ *         this will return the first device id from AAudioStream_getDeviceIds().
  */
 AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
 
 /**
- * Available since API level 36.
- *
  * Call this function after AAudioStreamBuilder_openStream().
- * This function will crash if stream is null.
  * An array of size 16 should generally be large enough to fit all device identifiers.
  *
+ * Available since API level 36.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream().
  * @param ids reference to an array of ids.
  * @params numIds size allocated to the array of ids.
@@ -1933,7 +2195,7 @@
  *         Otherwise, if ids is null, return {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT}.
  */
 AAUDIO_API aaudio_result_t AAudioStream_getDeviceIds(AAudioStream* _Nonnull stream,
-        int32_t* _Nonnull ids, int32_t* _Nonnull numIds) __INTRODUCED_IN(36);
+        int32_t* _Nullable ids, int32_t* _Nullable numIds) __INTRODUCED_IN(36);
 
 /**
  * Available since API level 26.
@@ -2188,6 +2450,127 @@
 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);
+
+/************************************************************************************
+ * Helper functions for AAudio MMAP.
+ * AAudio MMAP data path uses a memory region that is shared between the hardware and
+ * the audio software. The shared memory is referenced using a file descriptor that is
+ * generated by the ALSA driver. Apps can read/write directly from/to the shared
+ * memory, which helps improve the audio latency.
+ ************************************************************************************/
+
+/**
+ * When the audio is played/recorded via AAudio MMAP data path, the apps can write to/read from
+ * a shared memory that will also be accessed directly by hardware. That reduces the audio latency.
+ * The following values are used to describe how AAudio MMAP is supported.
+ */
+enum {
+    /**
+     * AAudio MMAP is disabled and never used.
+     */
+    AAUDIO_POLICY_NEVER = 1,
+
+    /**
+     * AAudio MMAP support depends on device's availability. It will be used
+     * when it is possible or fallback to the normal path, where the audio data
+     * will be delivered via audio framework data pipeline.
+     */
+    AAUDIO_POLICY_AUTO,
+
+    /**
+     * AAudio MMAP must be used or fail.
+     */
+    AAUDIO_POLICY_ALWAYS
+};
+typedef int32_t aaudio_policy_t;
+
+/**
+ * Query how aaudio mmap is supported for the given device type.
+ *
+ * @param device device type
+ * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
+ * @return the mmap policy or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the device or direction
+ *         is invalid or {@link #AAUDIO_ERROR_INTERNAL} if the audio HAL returns error.
+ */
+AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapPolicy(
+        AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
+
+/**
+ * Query how aaudio exclusive mmap is supported for the given device type.
+ *
+ * @param device device type
+ * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
+ * @return the mmap exclusive policy or or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the device
+ *         or direction is invalid or {@link #AAUDIO_ERROR_INTERNAL} if the audio HAL returns error.
+ */
+AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapExclusivePolicy(
+        AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/media/libaaudio/include/aaudio/AAudioTesting.h b/media/libaaudio/include/aaudio/AAudioTesting.h
index 16d6c33..8758e07 100644
--- a/media/libaaudio/include/aaudio/AAudioTesting.h
+++ b/media/libaaudio/include/aaudio/AAudioTesting.h
@@ -32,225 +32,6 @@
  ************************************************************************************/
 
 /**
- * When the audio is played/recorded via AAudio MMAP data path, the apps can write to/read from
- * a shared memory that will also be accessed directly by hardware. That reduces the audio latency.
- * The following values are used to describe how AAudio MMAP is supported.
- */
-enum {
-    /**
-     * AAudio MMAP is disabled and never used.
-     */
-    AAUDIO_POLICY_NEVER = 1,
-
-    /**
-     * AAudio MMAP support depends on device's availability. It will be used
-     * when it is possible or fallback to the normal path, where the audio data
-     * will be delivered via audio framework data pipeline.
-     */
-    AAUDIO_POLICY_AUTO,
-
-    /**
-     * AAudio MMAP must be used or fail.
-     */
-    AAUDIO_POLICY_ALWAYS
-};
-typedef int32_t aaudio_policy_t;
-
-// The values are copied from JAVA SDK device types defined in android/media/AudioDeviceInfo.java
-// When a new value is added, it should be added here and handled by the conversion at
-// AAudioConvert_aaudioToAndroidDeviceType.
-typedef enum AAudio_DeviceType : int32_t {
-    /**
-     * A device type describing the attached earphone speaker.
-     */
-    AAUDIO_DEVICE_BUILTIN_EARPIECE = 1,
-
-    /**
-     * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
-     * in a device.
-     */
-    AAUDIO_DEVICE_BUILTIN_SPEAKER = 2,
-
-    /**
-     * A device type describing a headset, which is the combination of a headphones and microphone.
-     */
-    AAUDIO_DEVICE_WIRED_HEADSET = 3,
-
-    /**
-     * A device type describing a pair of wired headphones.
-     */
-    AAUDIO_DEVICE_WIRED_HEADPHONES = 4,
-
-    /**
-     * A device type describing an analog line-level connection.
-     */
-    AAUDIO_DEVICE_LINE_ANALOG = 5,
-
-    /**
-     * A device type describing a digital line connection (e.g. SPDIF).
-     */
-    AAUDIO_DEVICE_LINE_DIGITAL = 6,
-
-    /**
-     * A device type describing a Bluetooth device typically used for telephony.
-     */
-    AAUDIO_DEVICE_BLUETOOTH_SCO = 7,
-
-    /**
-     * A device type describing a Bluetooth device supporting the A2DP profile.
-     */
-    AAUDIO_DEVICE_BLUETOOTH_A2DP = 8,
-
-    /**
-     * A device type describing an HDMI connection .
-     */
-    AAUDIO_DEVICE_HDMI = 9,
-
-    /**
-     * A device type describing the Audio Return Channel of an HDMI connection.
-     */
-    AAUDIO_DEVICE_HDMI_ARC = 10,
-
-    /**
-     * A device type describing a USB audio device.
-     */
-    AAUDIO_DEVICE_USB_DEVICE = 11,
-
-    /**
-     * A device type describing a USB audio device in accessory mode.
-     */
-    AAUDIO_DEVICE_USB_ACCESSORY = 12,
-
-    /**
-     * A device type describing the audio device associated with a dock.
-     * Starting at API 34, this device type only represents digital docks, while docks with an
-     * analog connection are represented with {@link #AAUDIO_DEVICE_DOCK_ANALOG}.
-     */
-    AAUDIO_DEVICE_DOCK = 13,
-
-    /**
-     * A device type associated with the transmission of audio signals over FM.
-     */
-    AAUDIO_DEVICE_FM = 14,
-
-    /**
-     * A device type describing the microphone(s) built in a device.
-     */
-    AAUDIO_DEVICE_BUILTIN_MIC = 15,
-
-    /**
-     * A device type for accessing the audio content transmitted over FM.
-     */
-    AAUDIO_DEVICE_FM_TUNER = 16,
-
-    /**
-     * A device type for accessing the audio content transmitted over the TV tuner system.
-     */
-    AAUDIO_DEVICE_TV_TUNER = 17,
-
-    /**
-     * A device type describing the transmission of audio signals over the telephony network.
-     */
-    AAUDIO_DEVICE_TELEPHONY = 18,
-
-    /**
-     * A device type describing the auxiliary line-level connectors.
-     */
-    AAUDIO_DEVICE_AUX_LINE = 19,
-
-    /**
-     * A device type connected over IP.
-     */
-    AAUDIO_DEVICE_IP = 20,
-
-    /**
-     * A type-agnostic device used for communication with external audio systems.
-     */
-    AAUDIO_DEVICE_BUS = 21,
-
-    /**
-     * A device type describing a USB audio headset.
-     */
-    AAUDIO_DEVICE_USB_HEADSET = 22,
-
-    /**
-     * A device type describing a Hearing Aid.
-     */
-    AAUDIO_DEVICE_HEARING_AID = 23,
-
-    /**
-     * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
-     * in a device, that is specifically tuned for outputting sounds like notifications and alarms
-     * (i.e. sounds the user couldn't necessarily anticipate).
-     * <p>Note that this physical audio device may be the same as {@link #TYPE_BUILTIN_SPEAKER}
-     * but is driven differently to safely accommodate the different use case.</p>
-     */
-    AAUDIO_DEVICE_BUILTIN_SPEAKER_SAFE = 24,
-
-    /**
-     * A device type for rerouting audio within the Android framework between mixes and
-     * system applications.
-     */
-    AAUDIO_DEVICE_REMOTE_SUBMIX = 25,
-    /**
-     * A device type describing a Bluetooth Low Energy (BLE) audio headset or headphones.
-     * Headphones are grouped with headsets when the device is a sink:
-     * the features of headsets and headphones with regard to playback are the same.
-     */
-    AAUDIO_DEVICE_BLE_HEADSET = 26,
-
-    /**
-     * A device type describing a Bluetooth Low Energy (BLE) audio speaker.
-     */
-    AAUDIO_DEVICE_BLE_SPEAKER = 27,
-
-    /**
-     * A device type describing an Echo Canceller loopback Reference.
-     * This device is only used when capturing with MediaRecorder.AudioSource.ECHO_REFERENCE,
-     * which requires privileged permission
-     * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}.
-     *
-     * Note that this is not exposed as it is a system API that requires privileged permission.
-     */
-    // AAUDIO_DEVICE_ECHO_REFERENCE = 28,
-
-    /**
-     * A device type describing the Enhanced Audio Return Channel of an HDMI connection.
-     */
-    AAUDIO_DEVICE_HDMI_EARC = 29,
-
-    /**
-     * A device type describing a Bluetooth Low Energy (BLE) broadcast group.
-     */
-    AAUDIO_DEVICE_BLE_BROADCAST = 30,
-
-    /**
-     * A device type describing the audio device associated with a dock using an analog connection.
-     */
-    AAUDIO_DEVICE_DOCK_ANALOG = 31
-} AAudio_DeviceType;
-
-/**
- * Query how aaudio mmap is supported for the given device type.
- *
- * @param device device type
- * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
- * @return the mmap policy or negative error
- */
-AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapPolicy(
-        AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
-
-/**
- * Query how aaudio exclusive mmap is supported for the given device type.
- *
- * @param device device type
- * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
- * @return the mmap exclusive policy or negative error
- */
-AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapExclusivePolicy(
-        AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
-
-/**
  * Control whether AAudioStreamBuilder_openStream() will use the new MMAP data path
  * or the older "Legacy" data path.
  *
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 6bc7dc2..33f152c 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -42,7 +42,6 @@
 #include "fifo/FifoBuffer.h"
 #include "utility/AudioClock.h"
 #include <media/AidlConversion.h>
-#include <com_android_media_aaudio.h>
 
 #include "AudioStreamInternal.h"
 
@@ -197,15 +196,6 @@
         setSampleRate(configurationOutput.getSampleRate());
     }
 
-    if (!com::android::media::aaudio::sample_rate_conversion()) {
-        if (getSampleRate() != getDeviceSampleRate()) {
-            ALOGD("%s - skipping sample rate converter. SR = %d, Device SR = %d", __func__,
-                    getSampleRate(), getDeviceSampleRate());
-            result = AAUDIO_ERROR_INVALID_RATE;
-            goto error;
-        }
-    }
-
     // Save device format so we can do format conversion and volume scaling together.
     setDeviceFormat(configurationOutput.getFormat());
     setDeviceSamplesPerFrame(configurationOutput.getSamplesPerFrame());
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 b8dadb4..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);
@@ -1379,13 +1377,14 @@
 
     media::GetInputForAttrResponse response;
 
-    status_t status = statusTFromBinderStatus(
-            aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl, attributionSource,
-                configAidl, flagsAidl, selectedDeviceIdAidl, &response));
-    if (status != NO_ERROR) {
+    const Status res = aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl,
+                                            attributionSource, configAidl, flagsAidl,
+                                            selectedDeviceIdAidl, &response);
+    if (!res.isOk()) {
+        ALOGE("getInputForAttr error: %s", res.toString8().c_str());
         *config = VALUE_OR_RETURN_STATUS(
                 aidl2legacy_AudioConfigBase_audio_config_base_t(response.config, true /*isInput*/));
-        return status;
+        return statusTFromBinderStatus(res);
     }
 
     *input = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_io_handle_t(response.input));
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/GetInputForAttrResponse.aidl b/media/libaudioclient/aidl/android/media/GetInputForAttrResponse.aidl
index 347bf79..9e57820 100644
--- a/media/libaudioclient/aidl/android/media/GetInputForAttrResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/GetInputForAttrResponse.aidl
@@ -28,6 +28,8 @@
     int selectedDeviceId;
     /** Interpreted as audio_port_handle_t. */
     int portId;
+    /** The virtual device id corresponding to the opened input. */
+    int virtualDeviceId;
     /** The suggested config if fails to get an input. **/
     AudioConfigBase config;
 }
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/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index ddef852..00f3929 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -201,11 +201,11 @@
         "latest_android_hardware_audio_core_sounddose_ndk_shared",
         "latest_android_hardware_audio_effect_ndk_shared",
         "latest_android_media_audio_common_types_ndk_shared",
-        "latest_av_audio_types_aidl_ndk_shared",
     ],
     shared_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
+        "av-audio-types-aidl-ndk",
         "com.android.media.audio-aconfig-cc",
         "libaudio_aidl_conversion_common_cpp",
         "libaudio_aidl_conversion_common_ndk",
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/Android.bp b/media/libmedia/Android.bp
index 06dd27b..894c459 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -260,6 +260,8 @@
     srcs: [
         "AudioCapabilities.cpp",
         "CodecCapabilities.cpp",
+        "EncoderCapabilities.cpp",
+        "VideoCapabilities.cpp",
         "CodecCapabilitiesUtils.cpp",
     ],
 
diff --git a/media/libmedia/AudioCapabilities.cpp b/media/libmedia/AudioCapabilities.cpp
index 1a92307..dbbe9e8 100644
--- a/media/libmedia/AudioCapabilities.cpp
+++ b/media/libmedia/AudioCapabilities.cpp
@@ -30,19 +30,19 @@
     return mBitrateRange;
 }
 
-const std::vector<int>& AudioCapabilities::getSupportedSampleRates() const {
+const std::vector<int32_t>& AudioCapabilities::getSupportedSampleRates() const {
     return mSampleRates;
 }
 
-const std::vector<Range<int>>&
+const std::vector<Range<int32_t>>&
         AudioCapabilities::getSupportedSampleRateRanges() const {
     return mSampleRateRanges;
 }
 
-int AudioCapabilities::getMaxInputChannelCount() const {
-    int overallMax = 0;
+int32_t AudioCapabilities::getMaxInputChannelCount() const {
+    int32_t overallMax = 0;
     for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) {
-        int lmax = mInputChannelRanges[i].upper();
+        int32_t lmax = mInputChannelRanges[i].upper();
         if (lmax > overallMax) {
             overallMax = lmax;
         }
@@ -50,10 +50,10 @@
     return overallMax;
 }
 
-int AudioCapabilities::getMinInputChannelCount() const {
-    int overallMin = MAX_INPUT_CHANNEL_COUNT;
+int32_t AudioCapabilities::getMinInputChannelCount() const {
+    int32_t overallMin = MAX_INPUT_CHANNEL_COUNT;
     for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) {
-        int lmin = mInputChannelRanges[i].lower();
+        int32_t lmin = mInputChannelRanges[i].lower();
         if (lmin < overallMin) {
             overallMin = lmin;
         }
@@ -61,7 +61,7 @@
     return overallMin;
 }
 
-const std::vector<Range<int>>&
+const std::vector<Range<int32_t>>&
         AudioCapabilities::getInputChannelCountRanges() const {
     return mInputChannelRanges;
 }
@@ -86,40 +86,41 @@
 }
 
 void AudioCapabilities::initWithPlatformLimits() {
-    mBitrateRange = Range<int>(0, INT32_MAX);
-    mInputChannelRanges.push_back(Range<int>(1, MAX_INPUT_CHANNEL_COUNT));
+    mBitrateRange = Range<int32_t>(0, INT32_MAX);
+    mInputChannelRanges.push_back(Range<int32_t>(1, MAX_INPUT_CHANNEL_COUNT));
 
-    const int minSampleRate = base::GetIntProperty("ro.mediacodec.min_sample_rate", 7350);
-    const int maxSampleRate = base::GetIntProperty("ro.mediacodec.max_sample_rate", 192000);
-    mSampleRateRanges.push_back(Range<int>(minSampleRate, maxSampleRate));
+    const int32_t minSampleRate = base::GetIntProperty("ro.mediacodec.min_sample_rate", 7350);
+    const int32_t maxSampleRate = base::GetIntProperty("ro.mediacodec.max_sample_rate", 192000);
+    mSampleRateRanges.push_back(Range<int32_t>(minSampleRate, maxSampleRate));
 }
 
-bool AudioCapabilities::supports(std::optional<int> sampleRate,
-        std::optional<int> inputChannels) {
+bool AudioCapabilities::supports(std::optional<int32_t> sampleRate,
+        std::optional<int32_t> inputChannels) {
     // channels and sample rates are checked orthogonally
     if (inputChannels
             && !std::any_of(mInputChannelRanges.begin(), mInputChannelRanges.end(),
-            [inputChannels](const Range<int> &a) { return a.contains(inputChannels.value()); })) {
+            [inputChannels](const Range<int32_t> &a) {
+                    return a.contains(inputChannels.value()); })) {
         return false;
     }
     if (sampleRate
             && !std::any_of(mSampleRateRanges.begin(), mSampleRateRanges.end(),
-            [sampleRate](const Range<int> &a) { return a.contains(sampleRate.value()); })) {
+            [sampleRate](const Range<int32_t> &a) { return a.contains(sampleRate.value()); })) {
         return false;
     }
     return true;
 }
 
-bool AudioCapabilities::isSampleRateSupported(int sampleRate) {
-    return supports(std::make_optional<int>(sampleRate), std::nullopt);
+bool AudioCapabilities::isSampleRateSupported(int32_t sampleRate) {
+    return supports(std::make_optional<int32_t>(sampleRate), std::nullopt);
 }
 
-void AudioCapabilities::limitSampleRates(std::vector<int> rates) {
-    std::vector<Range<int>> sampleRateRanges;
+void AudioCapabilities::limitSampleRates(std::vector<int32_t> rates) {
+    std::vector<Range<int32_t>> sampleRateRanges;
     std::sort(rates.begin(), rates.end());
-    for (int rate : rates) {
-        if (supports(std::make_optional<int>(rate), std::nullopt /* channels */)) {
-            sampleRateRanges.push_back(Range<int>(rate, rate));
+    for (int32_t rate : rates) {
+        if (supports(std::make_optional<int32_t>(rate), std::nullopt /* channels */)) {
+            sampleRateRanges.push_back(Range<int32_t>(rate, rate));
         }
     }
     mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, sampleRateRanges);
@@ -133,11 +134,11 @@
     }
 }
 
-void AudioCapabilities::limitSampleRates(std::vector<Range<int>> rateRanges) {
+void AudioCapabilities::limitSampleRates(std::vector<Range<int32_t>> rateRanges) {
     sortDistinctRanges(&rateRanges);
     mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
     // check if all values are discrete
-    for (Range<int> range: mSampleRateRanges) {
+    for (Range<int32_t> range: mSampleRateRanges) {
         if (range.lower() != range.upper()) {
             mSampleRates.clear();
             return;
@@ -147,10 +148,10 @@
 }
 
 void AudioCapabilities::applyLevelLimits() {
-    std::vector<int> sampleRates;
-    std::optional<Range<int>> sampleRateRange;
-    std::optional<Range<int>> bitRates;
-    int maxChannels = MAX_INPUT_CHANNEL_COUNT;
+    std::vector<int32_t> sampleRates;
+    std::optional<Range<int32_t>> sampleRateRange;
+    std::optional<Range<int32_t>> bitRates;
+    int32_t maxChannels = MAX_INPUT_CHANNEL_COUNT;
 
     // const char *mediaType = mMediaType.c_str();
     if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MPEG)) {
@@ -158,15 +159,15 @@
                 8000, 11025, 12000,
                 16000, 22050, 24000,
                 32000, 44100, 48000 };
-        bitRates = Range<int>(8000, 320000);
+        bitRates = Range<int32_t>(8000, 320000);
         maxChannels = 2;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)) {
         sampleRates = { 8000 };
-        bitRates = Range<int>(4750, 12200);
+        bitRates = Range<int32_t>(4750, 12200);
         maxChannels = 1;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)) {
         sampleRates = { 16000 };
-        bitRates = Range<int>(6600, 23850);
+        bitRates = Range<int32_t>(6600, 23850);
         maxChannels = 1;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
         sampleRates = {
@@ -175,32 +176,32 @@
                 22050, 24000, 32000,
                 44100, 48000, 64000,
                 88200, 96000 };
-        bitRates = Range<int>(8000, 510000);
+        bitRates = Range<int32_t>(8000, 510000);
         maxChannels = 48;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_VORBIS)) {
-        bitRates = Range<int>(32000, 500000);
-        sampleRateRange = Range<int>(8000, 192000);
+        bitRates = Range<int32_t>(32000, 500000);
+        sampleRateRange = Range<int32_t>(8000, 192000);
         maxChannels = 255;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_OPUS)) {
-        bitRates = Range<int>(6000, 510000);
+        bitRates = Range<int32_t>(6000, 510000);
         sampleRates = { 8000, 12000, 16000, 24000, 48000 };
         maxChannels = 255;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_RAW)) {
-        sampleRateRange = Range<int>(1, 192000);
-        bitRates = Range<int>(1, 10000000);
+        sampleRateRange = Range<int32_t>(1, 192000);
+        bitRates = Range<int32_t>(1, 10000000);
         maxChannels = MAX_NUM_CHANNELS;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
-        sampleRateRange = Range<int>(1, 655350);
+        sampleRateRange = Range<int32_t>(1, 655350);
         // lossless codec, so bitrate is ignored
         maxChannels = 255;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW)
             || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW)) {
         sampleRates = { 8000 };
-        bitRates = Range<int>(64000, 64000);
+        bitRates = Range<int32_t>(64000, 64000);
         // platform allows multiple channels for this format
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) {
         sampleRates = { 8000 };
-        bitRates = Range<int>(13000, 13000);
+        bitRates = Range<int32_t>(13000, 13000);
         maxChannels = 1;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC3)) {
         maxChannels = 6;
@@ -208,34 +209,34 @@
         maxChannels = 16;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_EAC3_JOC)) {
         sampleRates = { 48000 };
-        bitRates = Range<int>(32000, 6144000);
+        bitRates = Range<int32_t>(32000, 6144000);
         maxChannels = 16;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC4)) {
         sampleRates = { 44100, 48000, 96000, 192000 };
-        bitRates = Range<int>(16000, 2688000);
+        bitRates = Range<int32_t>(16000, 2688000);
         maxChannels = 24;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS)) {
         sampleRates = { 44100, 48000 };
-        bitRates = Range<int>(96000, 1524000);
+        bitRates = Range<int32_t>(96000, 1524000);
         maxChannels = 6;
     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_HD)) {
         for (ProfileLevel profileLevel: mProfileLevels) {
             switch (profileLevel.mProfile) {
                 case DTS_HDProfileLBR:
                     sampleRates = { 22050, 24000, 44100, 48000 };
-                    bitRates = Range<int>(32000, 768000);
+                    bitRates = Range<int32_t>(32000, 768000);
                     break;
                 case DTS_HDProfileHRA:
                 case DTS_HDProfileMA:
                     sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
-                    bitRates = Range<int>(96000, 24500000);
+                    bitRates = Range<int32_t>(96000, 24500000);
                     break;
                 default:
                     ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile,
                             mMediaType.c_str());
                     mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
                     sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
-                    bitRates = Range<int>(96000, 24500000);
+                    bitRates = Range<int32_t>(96000, 24500000);
             }
         }
         maxChannels = 8;
@@ -244,12 +245,12 @@
             switch (profileLevel.mProfile) {
                 case DTS_UHDProfileP2:
                     sampleRates = { 48000 };
-                    bitRates = Range<int>(96000, 768000);
+                    bitRates = Range<int32_t>(96000, 768000);
                     maxChannels = 10;
                     break;
                 case DTS_UHDProfileP1:
                     sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
-                    bitRates = Range<int>(96000, 24500000);
+                    bitRates = Range<int32_t>(96000, 24500000);
                     maxChannels = 32;
                     break;
                 default:
@@ -257,7 +258,7 @@
                             mMediaType.c_str());
                     mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
                     sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
-                    bitRates = Range<int>(96000, 24500000);
+                    bitRates = Range<int32_t>(96000, 24500000);
                     maxChannels = 32;
             }
         }
@@ -270,24 +271,24 @@
     if (!sampleRates.empty()) {
         limitSampleRates(sampleRates);
     } else if (sampleRateRange) {
-        std::vector<Range<int>> rateRanges = { sampleRateRange.value() };
+        std::vector<Range<int32_t>> rateRanges = { sampleRateRange.value() };
         limitSampleRates(rateRanges);
     }
 
-    Range<int> channelRange = Range<int>(1, maxChannels);
-    std::vector<Range<int>> inputChannels = { channelRange };
+    Range<int32_t> channelRange = Range<int32_t>(1, maxChannels);
+    std::vector<Range<int32_t>> inputChannels = { channelRange };
     applyLimits(inputChannels, bitRates);
 }
 
 void AudioCapabilities::applyLimits(
-        const std::vector<Range<int>> &inputChannels,
+        const std::vector<Range<int32_t>> &inputChannels,
         const std::optional<Range<int32_t>> &bitRates) {
     // clamp & make a local copy
-    std::vector<Range<int>> inputChannelsCopy(inputChannels.size());
+    std::vector<Range<int32_t>> inputChannelsCopy(inputChannels.size());
     for (int i = 0; i < inputChannels.size(); i++) {
-        int lower = inputChannels[i].clamp(1);
-        int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT);
-        inputChannelsCopy[i] = Range<int>(lower, upper);
+        int32_t lower = inputChannels[i].clamp(1);
+        int32_t upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT);
+        inputChannelsCopy[i] = Range<int32_t>(lower, upper);
     }
 
     // sort, intersect with existing, & save channel list
@@ -300,16 +301,16 @@
 }
 
 void AudioCapabilities::parseFromInfo(const sp<AMessage> &format) {
-    int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
-    std::vector<Range<int>> channels = { Range<int>(1, maxInputChannels) };
+    int32_t maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
+    std::vector<Range<int32_t>> channels = { Range<int32_t>(1, maxInputChannels) };
     std::optional<Range<int32_t>> bitRates = POSITIVE_INT32;
 
     AString rateAString;
     if (format->findString("sample-rate-ranges", &rateAString)) {
         std::vector<std::string> rateStrings = base::Split(std::string(rateAString.c_str()), ",");
-        std::vector<Range<int>> rateRanges;
+        std::vector<Range<int32_t>> rateRanges;
         for (std::string rateString : rateStrings) {
-            std::optional<Range<int>> rateRange = ParseIntRange(rateString);
+            std::optional<Range<int32_t>> rateRange = Range<int32_t>::Parse(rateString);
             if (!rateRange) {
                 continue;
             }
@@ -322,9 +323,9 @@
     AString valueStr;
     if (format->findString("channel-ranges", &valueStr)) {
         std::vector<std::string> channelStrings = base::Split(std::string(valueStr.c_str()), ",");
-        std::vector<Range<int>> channelRanges;
+        std::vector<Range<int32_t>> channelRanges;
         for (std::string channelString : channelStrings) {
-            std::optional<Range<int>> channelRange = ParseIntRange(channelString);
+            std::optional<Range<int32_t>> channelRange = Range<int32_t>::Parse(channelString);
             if (!channelRange) {
                 continue;
             }
@@ -332,24 +333,25 @@
         }
         channels = channelRanges;
     } else if (format->findString("channel-range", &valueStr)) {
-        std::optional<Range<int>> oneRange = ParseIntRange(std::string(valueStr.c_str()));
+        std::optional<Range<int32_t>> oneRange
+                = Range<int32_t>::Parse(std::string(valueStr.c_str()));
         if (oneRange) {
             channels = { oneRange.value() };
         }
     } else if (format->findString("max-channel-count", &valueStr)) {
         maxInputChannels = std::atoi(valueStr.c_str());
         if (maxInputChannels == 0) {
-            channels = { Range<int>(0, 0) };
+            channels = { Range<int32_t>(0, 0) };
         } else {
-            channels = { Range<int>(1, maxInputChannels) };
+            channels = { Range<int32_t>(1, maxInputChannels) };
         }
     } else if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0) {
         maxInputChannels = 0;
-        channels = { Range<int>(0, 0) };
+        channels = { Range<int32_t>(0, 0) };
     }
 
     if (format->findString("bitrate-range", &valueStr)) {
-        std::optional<Range<int32_t>> parsedBitrate = ParseIntRange(valueStr.c_str());
+        std::optional<Range<int32_t>> parsedBitrate = Range<int32_t>::Parse(valueStr.c_str());
         if (parsedBitrate) {
             bitRates = bitRates.value().intersect(parsedBitrate.value());
         }
@@ -374,11 +376,11 @@
 
 bool AudioCapabilities::supportsFormat(const sp<AMessage> &format) {
     int32_t sampleRateValue;
-    std::optional<int> sampleRate = format->findInt32(KEY_SAMPLE_RATE, &sampleRateValue)
-            ? std::make_optional<int>(sampleRateValue) : std::nullopt;
+    std::optional<int32_t> sampleRate = format->findInt32(KEY_SAMPLE_RATE, &sampleRateValue)
+            ? std::make_optional<int32_t>(sampleRateValue) : std::nullopt;
     int32_t channelsValue;
-    std::optional<int> channels = format->findInt32(KEY_CHANNEL_COUNT, &channelsValue)
-            ? std::make_optional<int>(channelsValue) : std::nullopt;
+    std::optional<int32_t> channels = format->findInt32(KEY_CHANNEL_COUNT, &channelsValue)
+            ? std::make_optional<int32_t>(channelsValue) : std::nullopt;
 
     if (!supports(sampleRate, channels)) {
         return false;
diff --git a/media/libmedia/CodecCapabilities.cpp b/media/libmedia/CodecCapabilities.cpp
index 87eb4bc..407d376 100644
--- a/media/libmedia/CodecCapabilities.cpp
+++ b/media/libmedia/CodecCapabilities.cpp
@@ -17,6 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "CodecCapabilities"
 
+#include <android-base/strings.h>
 #include <utils/Log.h>
 #include <media/CodecCapabilities.h>
 #include <media/CodecCapabilitiesUtils.h>
@@ -25,6 +26,58 @@
 
 namespace android {
 
+static const int32_t HEVCHighTierLevels =
+        HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 |
+        HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 |
+        HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
+        HEVCHighTierLevel62;
+
+static const int32_t DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
+static const int32_t MAX_SUPPORTED_INSTANCES_LIMIT = 256;
+
+// must not contain KEY_PROFILE
+static const std::set<std::pair<std::string, AMessage::Type>> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = {
+    // We don't set level-specific limits for audio codecs today. Key candidates would
+    // be sample rate, bit rate or channel count.
+    // MediaFormat.KEY_SAMPLE_RATE,
+    // MediaFormat.KEY_CHANNEL_COUNT,
+    // MediaFormat.KEY_BIT_RATE,
+    { KEY_MIME, AMessage::kTypeString }
+};
+
+// CodecCapabilities Features
+static const std::vector<Feature> DECODER_FEATURES = {
+    Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
+    Feature(FEATURE_SecurePlayback,   (1 << 1), false),
+    Feature(FEATURE_TunneledPlayback, (1 << 2), false),
+    Feature(FEATURE_PartialFrame,     (1 << 3), false),
+    Feature(FEATURE_FrameParsing,     (1 << 4), false),
+    Feature(FEATURE_MultipleFrames,   (1 << 5), false),
+    Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
+    Feature(FEATURE_LowLatency,       (1 << 7), true),
+    // feature to exclude codec from REGULAR codec list
+    Feature(FEATURE_SpecialCodec,     (1 << 30), false, true),
+};
+static const std::vector<Feature> ENCODER_FEATURES = {
+    Feature(FEATURE_IntraRefresh, (1 << 0), false),
+    Feature(FEATURE_MultipleFrames, (1 << 1), false),
+    Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
+    Feature(FEATURE_QpBounds, (1 << 3), false),
+    Feature(FEATURE_EncodingStatistics, (1 << 4), false),
+    Feature(FEATURE_HdrEditing, (1 << 5), false),
+    // feature to exclude codec from REGULAR codec list
+    Feature(FEATURE_SpecialCodec,     (1 << 30), false, true),
+};
+
+// must not contain KEY_PROFILE
+static const std::set<std::pair<std::string, AMessage::Type>> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = {
+    { KEY_WIDTH, AMessage::kTypeInt32 },
+    { KEY_HEIGHT, AMessage::kTypeInt32 },
+    { KEY_FRAME_RATE, AMessage::kTypeInt32 },
+    { KEY_BIT_RATE, AMessage::kTypeInt32 },
+    { KEY_MIME, AMessage::kTypeString }
+};
+
 bool CodecCapabilities::SupportsBitrate(Range<int32_t> bitrateRange,
         const sp<AMessage> &format) {
     // consider max bitrate over average bitrate for support
@@ -46,6 +99,212 @@
     return true;
 }
 
+bool CodecCapabilities::isFeatureSupported(const std::string &name) const {
+    return mFeaturesSupported.contains(name);
+}
+
+bool CodecCapabilities::isFeatureRequired(const std::string &name) const {
+    return mFeaturesRequired.contains(name);
+}
+
+std::vector<std::string> CodecCapabilities::validFeatures() const {
+    std::vector<std::string> res;
+    for (const Feature& feature : getValidFeatures()) {
+        if (!feature.mInternal) {
+            res.push_back(feature.mName);
+        }
+    }
+    return res;
+}
+
+std::vector<Feature> CodecCapabilities::getValidFeatures() const {
+    if (isEncoder()) {
+        return ENCODER_FEATURES;
+    } else {
+        return DECODER_FEATURES;
+    }
+}
+
+bool CodecCapabilities::isRegular() const {
+    // regular codecs only require default features
+    std::vector<Feature> features = getValidFeatures();
+    return std::all_of(features.begin(), features.end(),
+            [this](Feature feat){ return (feat.mDefault || !isFeatureRequired(feat.mName)); });
+}
+
+bool CodecCapabilities::isFormatSupported(const sp<AMessage> &format) const {
+    AString mediaType;
+    format->findString(KEY_MIME, &mediaType);
+    // mediaType must match if present
+    if (!base::EqualsIgnoreCase(mMediaType, mediaType.c_str())) {
+        return false;
+    }
+
+    // check feature support
+    for (Feature feat: getValidFeatures()) {
+        if (feat.mInternal) {
+            continue;
+        }
+
+        int32_t yesNo;
+        std::string key = KEY_FEATURE_;
+        key = key + feat.mName;
+        if (format->findInt32(key.c_str(), &yesNo)) {
+            continue;
+        }
+        if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
+                (yesNo == 0 && isFeatureRequired(feat.mName))) {
+            return false;
+        }
+    }
+
+    int32_t profile;
+    if (format->findInt32(KEY_PROFILE, &profile)) {
+        int32_t level = -1;
+        format->findInt32(KEY_LEVEL, &level);
+        if (!supportsProfileLevel(profile, level)) {
+            return false;
+        }
+
+        // If we recognize this profile, check that this format is supported by the
+        // highest level supported by the codec for that profile. (Ignore specified
+        // level beyond the above profile/level check as level is only used as a
+        // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1
+        // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile
+        // 1080p format is not supported even if codec supports Main Profile Level High,
+        // as Simple Profile does not support 1080p.
+        int32_t maxLevel = 0;
+        for (ProfileLevel pl : mProfileLevels) {
+            if (pl.mProfile == profile && pl.mLevel > maxLevel) {
+                // H.263 levels are not completely ordered:
+                // Level45 support only implies Level10 support
+                if (!base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)
+                        || pl.mLevel != H263Level45
+                        || maxLevel == H263Level10) {
+                    maxLevel = pl.mLevel;
+                }
+            }
+        }
+        std::shared_ptr<CodecCapabilities> levelCaps
+                = CreateFromProfileLevel(mMediaType, profile, maxLevel);
+        // We must remove the profile from this format otherwise levelCaps.isFormatSupported
+        // will get into this same condition and loop forever. Furthermore, since levelCaps
+        // does not contain features and bitrate specific keys, keep only keys relevant for
+        // a level check.
+        sp<AMessage> levelCriticalFormat = new AMessage;
+
+        // critical keys will always contain KEY_MIME, but should also contain others to be
+        // meaningful
+        if ((isVideo() || isAudio()) && levelCaps != nullptr) {
+            const std::set<std::pair<std::string, AMessage::Type>> criticalKeys =
+                isVideo() ? VIDEO_LEVEL_CRITICAL_FORMAT_KEYS : AUDIO_LEVEL_CRITICAL_FORMAT_KEYS;
+            for (std::pair<std::string, AMessage::Type> key : criticalKeys) {
+                if (format->contains(key.first.c_str())) {
+                    // AMessage::ItemData value = format->findItem(key.c_str());
+                    // levelCriticalFormat->setItem(key.c_str(), value);
+                    switch (key.second) {
+                        case AMessage::kTypeInt32: {
+                            int32_t value;
+                            format->findInt32(key.first.c_str(), &value);
+                            levelCriticalFormat->setInt32(key.first.c_str(), value);
+                            break;
+                        }
+                        case AMessage::kTypeString: {
+                            AString value;
+                            format->findString(key.first.c_str(), &value);
+                            levelCriticalFormat->setString(key.first.c_str(), value);
+                            break;
+                        }
+                        default:
+                            ALOGE("Unsupported type");
+                    }
+                }
+            }
+            if (!levelCaps->isFormatSupported(levelCriticalFormat)) {
+                return false;
+            }
+        }
+    }
+    if (mAudioCaps && !mAudioCaps->supportsFormat(format)) {
+        return false;
+    }
+    if (mVideoCaps && !mVideoCaps->supportsFormat(format)) {
+        return false;
+    }
+    if (mEncoderCaps && !mEncoderCaps->supportsFormat(format)) {
+        return false;
+    }
+    return true;
+}
+
+bool CodecCapabilities::supportsProfileLevel(int32_t profile, int32_t level) const {
+    for (ProfileLevel pl: mProfileLevels) {
+        if (pl.mProfile != profile) {
+            continue;
+        }
+
+        // No specific level requested
+        if (level == -1) {
+            return true;
+        }
+
+        // AAC doesn't use levels
+        if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
+            return true;
+        }
+
+        // DTS doesn't use levels
+        if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS)
+                || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_HD)
+                || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_UHD)) {
+            return true;
+        }
+
+        // H.263 levels are not completely ordered:
+        // Level45 support only implies Level10 support
+        if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)) {
+            if (pl.mLevel != level && pl.mLevel == H263Level45
+                    && level > H263Level10) {
+                continue;
+            }
+        }
+
+        // MPEG4 levels are not completely ordered:
+        // Level1 support only implies Level0 (and not Level0b) support
+        if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG4)) {
+            if (pl.mLevel != level && pl.mLevel == MPEG4Level1
+                    && level > MPEG4Level0) {
+                continue;
+            }
+        }
+
+        // HEVC levels incorporate both tiers and levels. Verify tier support.
+        if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_HEVC)) {
+            bool supportsHighTier =
+                (pl.mLevel & HEVCHighTierLevels) != 0;
+            bool checkingHighTier = (level & HEVCHighTierLevels) != 0;
+            // high tier levels are only supported by other high tier levels
+            if (checkingHighTier && !supportsHighTier) {
+                continue;
+            }
+        }
+
+        if (pl.mLevel >= level) {
+            // if we recognize the listed profile/level, we must also recognize the
+            // profile/level arguments.
+            if (CreateFromProfileLevel(mMediaType, profile, pl.mLevel) != nullptr) {
+                return CreateFromProfileLevel(mMediaType, profile, level) != nullptr;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+sp<AMessage> CodecCapabilities::getDefaultFormat() const {
+    return mDefaultFormat;
+}
+
 const std::string& CodecCapabilities::getMediaType() {
     return mMediaType;
 }
@@ -54,4 +313,130 @@
     return mProfileLevels;
 }
 
+std::vector<uint32_t> CodecCapabilities::getColorFormats() const {
+    return mColorFormats;
+}
+
+int32_t CodecCapabilities::getMaxSupportedInstances() const {
+    return mMaxSupportedInstances;
+}
+
+bool CodecCapabilities::isAudio() const {
+    return mAudioCaps != nullptr;
+}
+
+std::shared_ptr<AudioCapabilities>
+        CodecCapabilities::getAudioCapabilities() const {
+    return mAudioCaps;
+}
+
+bool CodecCapabilities::isEncoder() const {
+    return mEncoderCaps != nullptr;
+}
+
+std::shared_ptr<EncoderCapabilities>
+        CodecCapabilities::getEncoderCapabilities() const {
+    return mEncoderCaps;
+}
+
+bool CodecCapabilities::isVideo() const {
+    return mVideoCaps != nullptr;
+}
+
+std::shared_ptr<VideoCapabilities> CodecCapabilities::getVideoCapabilities() const {
+    return mVideoCaps;
+}
+
+// static
+std::shared_ptr<CodecCapabilities> CodecCapabilities::CreateFromProfileLevel(
+        std::string mediaType, int32_t profile, int32_t level, int32_t maxConcurrentInstances) {
+    ProfileLevel pl;
+    pl.mProfile = profile;
+    pl.mLevel = level;
+    sp<AMessage> defaultFormat = new AMessage;
+    defaultFormat->setString(KEY_MIME, mediaType.c_str());
+
+    std::vector<ProfileLevel> pls;
+    pls.push_back(pl);
+    std::vector<uint32_t> colFmts;
+    sp<AMessage> capabilitiesInfo = new AMessage;
+    std::shared_ptr<CodecCapabilities> ret(new CodecCapabilities());
+    ret->init(pls, colFmts, true /* encoder */, defaultFormat, capabilitiesInfo,
+            maxConcurrentInstances);
+    if (ret->getErrors() != 0) {
+        return nullptr;
+    }
+    return ret;
+}
+
+void CodecCapabilities::init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts,
+        bool encoder, sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo,
+        int32_t maxConcurrentInstances) {
+    mColorFormats = colFmts;
+    mDefaultFormat = defaultFormat;
+    mCapabilitiesInfo = capabilitiesInfo;
+
+    AString mediaTypeAStr;
+    mDefaultFormat->findString(KEY_MIME, &mediaTypeAStr);
+    mMediaType = mediaTypeAStr.c_str();
+
+    /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any
+       supported profiles. Determine the level for them using the info they provide. */
+    if (profLevs.size() == 0 && mMediaType == MIMETYPE_VIDEO_VP9) {
+        ProfileLevel profLev;
+        profLev.mProfile = VP9Profile0;
+        profLev.mLevel = VideoCapabilities::EquivalentVP9Level(capabilitiesInfo);
+        profLevs.push_back(profLev);
+    }
+    mProfileLevels = profLevs;
+
+    if (mediaTypeAStr.startsWithIgnoreCase("audio/")) {
+        mAudioCaps = AudioCapabilities::Create(mMediaType, profLevs, capabilitiesInfo);
+        mAudioCaps->getDefaultFormat(mDefaultFormat);
+    } else if (mediaTypeAStr.startsWithIgnoreCase("video/")
+            || mediaTypeAStr.equalsIgnoreCase(MIMETYPE_IMAGE_ANDROID_HEIC)) {
+        mVideoCaps = VideoCapabilities::Create(mMediaType, profLevs, capabilitiesInfo);
+    }
+
+    if (encoder) {
+        mEncoderCaps = EncoderCapabilities::Create(mMediaType, profLevs, capabilitiesInfo);
+        mEncoderCaps->getDefaultFormat(mDefaultFormat);
+    }
+
+    mMaxSupportedInstances = maxConcurrentInstances > 0
+            ? maxConcurrentInstances : DEFAULT_MAX_SUPPORTED_INSTANCES;
+
+    int32_t maxInstances = mMaxSupportedInstances;
+    capabilitiesInfo->findInt32("max-concurrent-instances", &maxInstances);
+    mMaxSupportedInstances =
+            Range(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
+
+    mFeaturesRequired.clear();
+    mFeaturesSupported.clear();
+    for (Feature feat: getValidFeatures()) {
+        std::string key = KEY_FEATURE_;
+        key = key + feat.mName;
+        int yesNo = -1;
+        if (!capabilitiesInfo->findInt32(key.c_str(), &yesNo)) {
+            continue;
+        }
+        if (yesNo > 0) {
+            mFeaturesRequired.insert(feat.mName);
+        }
+        mFeaturesSupported.insert(feat.mName);
+        if (!feat.mInternal) {
+            mDefaultFormat->setInt32(key.c_str(), 1);
+        }
+    }
+}
+
+int32_t CodecCapabilities::getErrors() const {
+    if (mAudioCaps) {
+        return mAudioCaps->mError;
+    } else if (mVideoCaps) {
+        return mVideoCaps->mError;
+    }
+    return 0;
+}
+
 }  // namespace android
\ No newline at end of file
diff --git a/media/libmedia/CodecCapabilitiesUtils.cpp b/media/libmedia/CodecCapabilitiesUtils.cpp
index edfc9be..01bb24e 100644
--- a/media/libmedia/CodecCapabilitiesUtils.cpp
+++ b/media/libmedia/CodecCapabilitiesUtils.cpp
@@ -16,38 +16,146 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "CodecCapabilitiesUtils"
+
+#include <android-base/properties.h>
 #include <utils/Log.h>
 
 #include <algorithm>
 #include <cmath>
-#include <regex>
+#include <cstdlib>
 #include <string>
 #include <vector>
 
 #include <media/CodecCapabilitiesUtils.h>
-
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
 
 namespace android {
 
-std::optional<Range<int>> ParseIntRange(const std::string &str) {
+// VideoSize
+
+VideoSize::VideoSize(int32_t width, int32_t height) : mWidth(width), mHeight(height) {}
+
+VideoSize::VideoSize() : mWidth(0), mHeight(0) {}
+
+int32_t VideoSize::getWidth() const { return mWidth; }
+
+int32_t VideoSize::getHeight() const { return mHeight; }
+
+bool VideoSize::equals(VideoSize other) const {
+    return mWidth == other.mWidth && mHeight == other.mHeight;
+}
+
+bool VideoSize::empty() const {
+    return mWidth <= 0 || mHeight <= 0;
+}
+
+std::string VideoSize::toString() const {
+    return std::to_string(mWidth) + "x" + std::to_string(mHeight);
+}
+
+std::optional<VideoSize> VideoSize::ParseSize(std::string str) {
     if (str.empty()) {
-        ALOGW("could not parse empty integer range");
         return std::nullopt;
     }
-    int lower, upper;
-    std::regex regex("([0-9]+)-([0-9]+)");
+
+    std::regex regex("([0-9]+)([*x])([0-9]+)");
     std::smatch match;
     if (std::regex_match(str, match, regex)) {
-        lower = std::atoi(match[1].str().c_str());
-        upper = std::atoi(match[2].str().c_str());
-    } else if (std::atoi(str.c_str()) != 0) {
-        lower = upper = std::atoi(str.c_str());
+        long int w = strtol(match[1].str().c_str(), NULL, 10);
+        long int h = strtol(match[3].str().c_str(), NULL, 10);
+        return std::make_optional(VideoSize(w, h));
     } else {
-        ALOGW("could not parse integer range: %s", str.c_str());
+        ALOGW("could not parse size %s", str.c_str());
         return std::nullopt;
     }
-    return std::make_optional<Range<int>>(lower, upper);
+}
+
+std::optional<std::pair<VideoSize, VideoSize>> VideoSize::ParseSizeRange(const std::string str) {
+    size_t ix = str.find_first_of('-');
+    if (ix != std::string::npos) {
+        std::optional<VideoSize> lowerOpt = VideoSize::ParseSize(str.substr(0, ix));
+        std::optional<VideoSize> upperOpt = VideoSize::ParseSize(str.substr(ix + 1));
+        if (!lowerOpt || !upperOpt) {
+            return std::nullopt;
+        }
+        return std::make_optional(
+                std::pair<VideoSize, VideoSize>(lowerOpt.value(), upperOpt.value()));
+    } else {
+        std::optional<VideoSize> opt = VideoSize::ParseSize(str);
+        if (!opt) {
+            return std::nullopt;
+        }
+        return std::make_optional(std::pair<VideoSize, VideoSize>(opt.value(), opt.value()));
+    }
+}
+
+Range<int32_t> VideoSize::GetAllowedDimensionRange() {
+#ifdef __LP64__
+    return Range<int32_t>(1, 32768);
+#else
+    int32_t value = base::GetIntProperty("media.resolution.limit.32bit", (int32_t)4096);
+    return Range<int32_t>(1, value);
+#endif
+}
+
+// Rational
+
+std::optional<Rational> Rational::Parse(std::string str) {
+    if (str.compare("NaN") == 0) {
+        return std::make_optional(NaN);
+    } else if (str.compare("Infinity") == 0) {
+        return std::make_optional(POSITIVE_INFINITY);
+    } else if (str.compare("-Infinity") == 0) {
+        return std::make_optional(NEGATIVE_INFINITY);
+    }
+
+    std::regex regex("([0-9]+)([:/])([0-9]+)");
+    std::smatch match;
+    if (std::regex_match(str, match, regex)) {
+        long int numerator = strtol(match[1].str().c_str(), NULL, 10);
+        long int denominator = strtol(match[3].str().c_str(), NULL, 10);
+        return std::make_optional(Rational(numerator, denominator));
+    } else {
+        ALOGW("could not parse string: %s to Rational", str.c_str());
+        return std::nullopt;
+    }
+}
+
+Rational Rational::scale(int32_t num, int32_t den) {
+    int32_t common = std::gcd(num, den);
+    num /= common;
+    den /= common;
+    return Rational(
+            (int32_t)(mNumerator * (double)num),     // saturate to int
+            (int32_t)(mDenominator * (double)den));  // saturate to int
+}
+
+Range<Rational> Rational::ScaleRange(Range<Rational> range, int32_t num, int32_t den) {
+    if (num == den) {
+        return range;
+    }
+    return Range(
+            range.lower().scale(num, den),
+            range.upper().scale(num, den));
+}
+
+std::optional<Range<Rational>> Rational::ParseRange(const std::string str) {
+    size_t ix = str.find_first_of('-');
+    if (ix != std::string::npos) {
+        std::optional<Rational> lower = Parse(str.substr(0, ix));
+        std::optional<Rational> upper = Parse(str.substr(ix + 1));
+        if (!lower || !upper) {
+            return std::nullopt;
+        }
+        return std::make_optional<Range<Rational>>(lower.value(), upper.value());
+    } else {
+        std::optional<Rational> value = Parse(str);
+        if (!value) {
+            return std::nullopt;
+        }
+        return std::make_optional<Range<Rational>>(value.value(), value.value());
+    }
 }
 
 }  // namespace android
\ No newline at end of file
diff --git a/media/libmedia/EncoderCapabilities.cpp b/media/libmedia/EncoderCapabilities.cpp
new file mode 100644
index 0000000..a840220
--- /dev/null
+++ b/media/libmedia/EncoderCapabilities.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "EncoderCapabilities"
+
+#include <android-base/strings.h>
+
+#include <media/CodecCapabilities.h>
+#include <media/EncoderCapabilities.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+namespace android {
+
+const Range<int>& EncoderCapabilities::getQualityRange() {
+    return mQualityRange;
+}
+
+const Range<int>& EncoderCapabilities::getComplexityRange() {
+    return mComplexityRange;
+}
+
+// static
+int EncoderCapabilities::ParseBitrateMode(std::string mode) {
+    for (Feature feat: sBitrateModes) {
+        if (base::EqualsIgnoreCase(feat.mName, mode)) {
+            return feat.mValue;
+        }
+    }
+    return 0;
+}
+
+bool EncoderCapabilities::isBitrateModeSupported(int mode) {
+    for (Feature feat : sBitrateModes) {
+        if (mode == feat.mValue) {
+            return (mBitControl & (1 << mode)) != 0;
+        }
+    }
+    return false;
+}
+
+// static
+std::shared_ptr<EncoderCapabilities> EncoderCapabilities::Create(std::string mediaType,
+        std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
+    std::shared_ptr<EncoderCapabilities> caps(new EncoderCapabilities());
+    caps->init(mediaType, profLevs, format);
+    return caps;
+}
+
+void EncoderCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+        const sp<AMessage> &format) {
+    // no support for complexity or quality yet
+    mMediaType = mediaType;
+    mProfileLevels = profLevs;
+    mComplexityRange = Range(0, 0);
+    mQualityRange = Range(0, 0);
+    mBitControl = (1 << BITRATE_MODE_VBR);
+
+    applyLevelLimits();
+    parseFromInfo(format);
+}
+
+void EncoderCapabilities::applyLevelLimits() {
+    if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
+        mComplexityRange = Range(0, 8);
+        mBitControl = (1 << BITRATE_MODE_CQ);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)
+            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)
+            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW)
+            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW)
+            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) {
+        mBitControl = (1 << BITRATE_MODE_CBR);
+    }
+}
+
+void EncoderCapabilities::parseFromInfo(const sp<AMessage> &format) {
+    AString complexityRangeAStr;
+    if (format->findString("complexity-range", &complexityRangeAStr)) {
+        std::optional<Range<int>> complexityRangeOpt
+                = Range<int32_t>::Parse(std::string(complexityRangeAStr.c_str()));
+        mComplexityRange = complexityRangeOpt.value_or(mComplexityRange);
+        // TODO should we limit this to level limits?
+    }
+    AString qualityRangeAStr;
+    if (format->findString("quality-range", &qualityRangeAStr)) {
+        std::optional<Range<int>> qualityRangeOpt
+                = Range<int32_t>::Parse(std::string(qualityRangeAStr.c_str()));
+        mQualityRange = qualityRangeOpt.value_or(mQualityRange);
+    }
+    AString bitrateModesAStr;
+    if (format->findString("feature-bitrate-modes", &bitrateModesAStr)) {
+        mBitControl = 0;
+        for (std::string mode: base::Split(std::string(bitrateModesAStr.c_str()), ",")) {
+            mBitControl |= (1 << ParseBitrateMode(mode));
+        }
+    }
+    format->findInt32("complexity-default", &mDefaultComplexity);
+    format->findInt32("quality-default", &mDefaultQuality);
+    AString qualityScaleAStr;
+    if (format->findString("quality-scale", &qualityScaleAStr)) {
+        mQualityScale = std::string(qualityScaleAStr.c_str());
+    }
+}
+
+bool EncoderCapabilities::supports(
+        std::optional<int> complexity, std::optional<int> quality, std::optional<int> profile) {
+    bool ok = true;
+    if (complexity) {
+        ok &= mComplexityRange.contains(complexity.value());
+    }
+    if (quality) {
+        ok &= mQualityRange.contains(quality.value());
+    }
+    if (profile) {
+        ok &= std::any_of(mProfileLevels.begin(), mProfileLevels.end(),
+                [&profile](ProfileLevel pl){ return pl.mProfile == profile.value(); });
+    }
+    return ok;
+}
+
+void EncoderCapabilities::getDefaultFormat(sp<AMessage> &format) {
+    // don't list trivial quality/complexity as default for now
+    if (mQualityRange.upper() != mQualityRange.lower()
+            && mDefaultQuality != 0) {
+        format->setInt32(KEY_QUALITY, mDefaultQuality);
+    }
+    if (mComplexityRange.upper() != mComplexityRange.lower()
+            && mDefaultComplexity != 0) {
+        format->setInt32(KEY_COMPLEXITY, mDefaultComplexity);
+    }
+    // bitrates are listed in order of preference
+    for (Feature feat : sBitrateModes) {
+        if ((mBitControl & (1 << feat.mValue)) != 0) {
+            format->setInt32(KEY_BITRATE_MODE, feat.mValue);
+            break;
+        }
+    }
+}
+
+bool EncoderCapabilities::supportsFormat(const sp<AMessage> &format) {
+    int32_t mode;
+    if (format->findInt32(KEY_BITRATE_MODE, &mode) && !isBitrateModeSupported(mode)) {
+        return false;
+    }
+
+    int tmp;
+    std::optional<int> complexity = std::nullopt;
+    if (format->findInt32(KEY_COMPLEXITY, &tmp)) {
+        complexity = tmp;
+    }
+
+    if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
+        int flacComplexity;
+        if (format->findInt32(KEY_FLAC_COMPRESSION_LEVEL, &flacComplexity)) {
+            if (!complexity) {
+                complexity = flacComplexity;
+            } else if (flacComplexity != complexity.value()) {
+                ALOGE("Conflicting values for complexity and flac-compression-level,"
+                        " which are %d and %d", complexity.value(), flacComplexity);
+                return false;
+            }
+        }
+    }
+
+    // other audio parameters
+    std::optional<int> profile = std::nullopt;
+    if (format->findInt32(KEY_PROFILE, &tmp)) {
+        profile = tmp;
+    }
+
+    if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
+        int aacProfile;
+        if (format->findInt32(KEY_AAC_PROFILE, &aacProfile)) {
+            if (!profile) {
+                profile = aacProfile;
+            } else if (aacProfile != profile.value()) {
+                ALOGE("Conflicting values for profile and aac-profile, which are %d and %d",
+                        profile.value(), aacProfile);
+                return false;
+            }
+        }
+    }
+
+    std::optional<int> quality = std::nullopt;
+    if (format->findInt32(KEY_QUALITY, &tmp)) {
+        quality = tmp;
+    }
+
+    return supports(complexity, quality, profile);
+}
+
+}  // namespace android
\ No newline at end of file
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/VideoCapabilities.cpp b/media/libmedia/VideoCapabilities.cpp
new file mode 100644
index 0000000..bd26b8c
--- /dev/null
+++ b/media/libmedia/VideoCapabilities.cpp
@@ -0,0 +1,1702 @@
+/*
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VideoCapabilities"
+
+#include <android-base/strings.h>
+
+#include <media/CodecCapabilities.h>
+#include <media/VideoCapabilities.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+#include <utils/Errors.h>
+
+namespace android {
+
+static const Range<int64_t> POSITIVE_INT64 = Range((int64_t)1, INT64_MAX);
+static const Range<int32_t> BITRATE_RANGE = Range<int32_t>(0, 500000000);
+static const Range<int32_t> FRAME_RATE_RANGE = Range<int32_t>(0, 960);
+static const Range<Rational> POSITIVE_RATIONALS =
+            Range<Rational>(Rational((int32_t)1, INT32_MAX), Rational(INT32_MAX, (int32_t)1));
+
+const Range<int32_t>& VideoCapabilities::getBitrateRange() const {
+    return mBitrateRange;
+}
+
+const Range<int32_t>& VideoCapabilities::getSupportedWidths() const {
+    return mWidthRange;
+}
+
+const Range<int32_t>& VideoCapabilities::getSupportedHeights() const {
+    return mHeightRange;
+}
+
+int32_t VideoCapabilities::getWidthAlignment() const {
+    return mWidthAlignment;
+}
+
+int32_t VideoCapabilities::getHeightAlignment() const {
+    return mHeightAlignment;
+}
+
+int32_t VideoCapabilities::getSmallerDimensionUpperLimit() const {
+    return mSmallerDimensionUpperLimit;
+}
+
+const Range<int32_t>& VideoCapabilities::getSupportedFrameRates() const {
+    return mFrameRateRange;
+}
+
+std::optional<Range<int32_t>> VideoCapabilities::getSupportedWidthsFor(int32_t height) const {
+    Range<int32_t> range = mWidthRange;
+    if (!mHeightRange.contains(height)
+            || (height % mHeightAlignment) != 0) {
+        ALOGE("unsupported height");
+        return std::nullopt;
+    }
+    const int32_t heightInBlocks = divUp(height, mBlockHeight);
+
+    // constrain by block count and by block aspect ratio
+    const int32_t minWidthInBlocks = std::max(
+            divUp(mBlockCountRange.lower(), heightInBlocks),
+            (int32_t)std::ceil(mBlockAspectRatioRange.lower().asDouble()
+                    * heightInBlocks));
+    const int32_t maxWidthInBlocks = std::min(
+            mBlockCountRange.upper() / heightInBlocks,
+            (int32_t)(mBlockAspectRatioRange.upper().asDouble()
+                    * heightInBlocks));
+    range = range.intersect(
+            (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
+            maxWidthInBlocks * mBlockWidth);
+
+    // constrain by smaller dimension limit
+    if (height > mSmallerDimensionUpperLimit) {
+        range = range.intersect(1, mSmallerDimensionUpperLimit);
+    }
+
+    // constrain by aspect ratio
+    range = range.intersect(
+            (int32_t)std::ceil(mAspectRatioRange.lower().asDouble()
+                    * height),
+            (int32_t)(mAspectRatioRange.upper().asDouble() * height));
+    return range;
+}
+
+std::optional<Range<int32_t>> VideoCapabilities::getSupportedHeightsFor(int32_t width) const {
+    Range<int32_t> range = mHeightRange;
+    if (!mWidthRange.contains(width)
+            || (width % mWidthAlignment) != 0) {
+        ALOGE("unsupported width");
+        return std::nullopt;
+    }
+    const int32_t widthInBlocks = divUp(width, mBlockWidth);
+
+    // constrain by block count and by block aspect ratio
+    const int32_t minHeightInBlocks = std::max(
+            divUp(mBlockCountRange.lower(), widthInBlocks),
+            (int32_t)std::ceil(widthInBlocks /
+                    mBlockAspectRatioRange.upper().asDouble()));
+    const int32_t maxHeightInBlocks = std::min(
+            mBlockCountRange.upper() / widthInBlocks,
+            (int32_t)(widthInBlocks /
+                    mBlockAspectRatioRange.lower().asDouble()));
+    range = range.intersect(
+            (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
+            maxHeightInBlocks * mBlockHeight);
+
+    // constrain by smaller dimension limit
+    if (width > mSmallerDimensionUpperLimit) {
+        range = range.intersect(1, mSmallerDimensionUpperLimit);
+    }
+
+    // constrain by aspect ratio
+    range = range.intersect(
+            (int32_t)std::ceil(width /
+                    mAspectRatioRange.upper().asDouble()),
+            (int32_t)(width / mAspectRatioRange.lower().asDouble()));
+    return range;
+}
+
+std::optional<Range<double>> VideoCapabilities::getSupportedFrameRatesFor(
+        int32_t width, int32_t height) const {
+    if (!supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
+            std::nullopt /* rate */)) {
+        ALOGE("Unsupported size. width: %d, height: %d", width, height);
+        return std::nullopt;
+    }
+
+    const int32_t blockCount =
+            divUp(width, mBlockWidth) * divUp(height, mBlockHeight);
+
+    return std::make_optional(Range(
+            std::max(mBlocksPerSecondRange.lower() / (double) blockCount,
+                (double) mFrameRateRange.lower()),
+            std::min(mBlocksPerSecondRange.upper() / (double) blockCount,
+                (double) mFrameRateRange.upper())));
+}
+
+int32_t VideoCapabilities::getBlockCount(int32_t width, int32_t height) const {
+    return divUp(width, mBlockWidth) * divUp(height, mBlockHeight);
+}
+
+std::optional<VideoSize> VideoCapabilities::findClosestSize(
+        int32_t width, int32_t height) const {
+    int32_t targetBlockCount = getBlockCount(width, height);
+    std::optional<VideoSize> closestSize;
+    int32_t minDiff = INT32_MAX;
+    for (const auto &[size, range] : mMeasuredFrameRates) {
+        int32_t diff = std::abs(targetBlockCount -
+                getBlockCount(size.getWidth(), size.getHeight()));
+        if (diff < minDiff) {
+            minDiff = diff;
+            closestSize = size;
+        }
+    }
+    return closestSize;
+}
+
+std::optional<Range<double>> VideoCapabilities::estimateFrameRatesFor(
+        int32_t width, int32_t height) const {
+    std::optional<VideoSize> size = findClosestSize(width, height);
+    if (!size) {
+        return std::nullopt;
+    }
+    auto rangeItr = mMeasuredFrameRates.find(size.value());
+    if (rangeItr == mMeasuredFrameRates.end()) {
+        return std::nullopt;
+    }
+    Range<int64_t> range = rangeItr->second;
+    double ratio = getBlockCount(size.value().getWidth(), size.value().getHeight())
+            / (double)std::max(getBlockCount(width, height), 1);
+    return std::make_optional(Range(range.lower() * ratio, range.upper() * ratio));
+}
+
+std::optional<Range<double>> VideoCapabilities::getAchievableFrameRatesFor(
+        int32_t width, int32_t height) const {
+    if (!supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
+            std::nullopt /* rate */)) {
+        ALOGE("Unsupported size. width: %d, height: %d", width, height);
+        return std::nullopt;
+    }
+
+    if (mMeasuredFrameRates.empty()) {
+        ALOGW("Codec did not publish any measurement data.");
+        return std::nullopt;
+    }
+
+    return estimateFrameRatesFor(width, height);
+}
+
+// VideoCapabilities::PerformancePoint
+
+int32_t VideoCapabilities::PerformancePoint::getMaxMacroBlocks() const {
+    return saturateInt64ToInt32(mWidth * (int64_t)mHeight);
+}
+
+int32_t VideoCapabilities::PerformancePoint::getWidth() const {
+    return mWidth;
+}
+
+int32_t VideoCapabilities::PerformancePoint::getHeight() const {
+    return mHeight;
+}
+
+int32_t VideoCapabilities::PerformancePoint::getMaxFrameRate() const {
+    return mMaxFrameRate;
+}
+
+int64_t VideoCapabilities::PerformancePoint::getMaxMacroBlockRate() const {
+    return mMaxMacroBlockRate;
+}
+
+VideoSize VideoCapabilities::PerformancePoint::getBlockSize() const {
+    return mBlockSize;
+}
+
+std::string VideoCapabilities::PerformancePoint::toString() const {
+    int64_t blockWidth = 16 * (int64_t)mBlockSize.getWidth();
+    int64_t blockHeight = 16 * (int64_t)mBlockSize.getHeight();
+    int32_t origRate = (int32_t)divUp(mMaxMacroBlockRate, (int64_t)getMaxMacroBlocks());
+    std::string info = std::to_string(mWidth * (int64_t)16) + "x"
+            + std::to_string(mHeight * (int64_t)16) + "@" + std::to_string(origRate);
+    if (origRate < mMaxFrameRate) {
+        info += ", max " + std::to_string(mMaxFrameRate) + "fps";
+    }
+    if (blockWidth > 16 || blockHeight > 16) {
+        info += ", " + std::to_string(blockWidth) + "x"
+                + std::to_string(blockHeight) + " blocks";
+    }
+    return "PerformancePoint(" + info + ")";
+}
+
+void VideoCapabilities::PerformancePoint::init(int32_t width, int32_t height,
+        int32_t frameRate, int32_t maxFrameRate, VideoSize blockSize) {
+    mBlockSize = VideoSize(divUp(blockSize.getWidth(), (int32_t)16),
+                            divUp(blockSize.getHeight(), (int32_t)16));
+    // Use  IsPowerOfTwoStrict as we do not want width and height to be 0;
+    if (!IsPowerOfTwoStrict(blockSize.getWidth()) || !IsPowerOfTwoStrict(blockSize.getHeight())) {
+        ALOGE("The width and height of a PerformancePoint must be the power of two and not zero."
+                " width: %d, height: %d", blockSize.getWidth(), blockSize.getHeight());
+    }
+
+    // these are guaranteed not to overflow as we decimate by 16
+    mWidth = (int32_t)(divUp(std::max(width, 1),
+                            std::max(blockSize.getWidth(), 16))
+                        * mBlockSize.getWidth());
+    mHeight = (int32_t)(divUp(std::max(height, 1),
+                            std::max(blockSize.getHeight(), 16))
+                        * mBlockSize.getHeight());
+    mMaxFrameRate = std::max(std::max(frameRate, maxFrameRate), 1);
+    mMaxMacroBlockRate = std::max(frameRate, 1) * (int64_t)getMaxMacroBlocks();
+}
+
+VideoCapabilities::PerformancePoint::PerformancePoint(int32_t width, int32_t height,
+        int32_t frameRate, int32_t maxFrameRate, VideoSize blockSize) {
+    init(width, height, frameRate, maxFrameRate, blockSize);
+}
+
+VideoCapabilities::PerformancePoint::PerformancePoint(VideoSize blockSize, int32_t width,
+        int32_t height, int32_t maxFrameRate, int64_t maxMacroBlockRate) :
+        mBlockSize(blockSize), mWidth(width), mHeight(height), mMaxFrameRate(maxFrameRate),
+        mMaxMacroBlockRate(maxMacroBlockRate) {}
+
+VideoCapabilities::PerformancePoint::PerformancePoint(
+        const PerformancePoint &pp, VideoSize newBlockSize) {
+    init(16 * pp.mWidth, 16 * pp.mHeight,
+            // guaranteed not to overflow as these were multiplied at construction
+            (int32_t)divUp(pp.mMaxMacroBlockRate, (int64_t)pp.getMaxMacroBlocks()),
+            pp.mMaxFrameRate,
+            VideoSize(std::max(newBlockSize.getWidth(), 16 * pp.mBlockSize.getWidth()),
+                 std::max(newBlockSize.getHeight(), 16 * pp.mBlockSize.getHeight())));
+}
+
+VideoCapabilities::PerformancePoint::PerformancePoint(
+        int32_t width, int32_t height, int32_t frameRate) {
+    init(width, height, frameRate, frameRate /* maxFrameRate */, VideoSize(16, 16));
+}
+
+int32_t VideoCapabilities::PerformancePoint::saturateInt64ToInt32(int64_t value) const {
+    if (value < INT32_MIN) {
+        return INT32_MIN;
+    } else if (value > INT32_MAX) {
+        return INT32_MAX;
+    } else {
+        return (int32_t)value;
+    }
+}
+
+/* This method may overflow */
+int32_t VideoCapabilities::PerformancePoint::align(
+        int32_t value, int32_t alignment) const {
+    return divUp(value, alignment) * alignment;
+}
+
+bool VideoCapabilities::PerformancePoint::covers(
+        const sp<AMessage> &format) const {
+    int32_t width, height;
+    format->findInt32(KEY_WIDTH, &width);
+    format->findInt32(KEY_HEIGHT, &height);
+    double frameRate;
+    format->findDouble(KEY_FRAME_RATE, &frameRate);
+    PerformancePoint other = PerformancePoint(
+            width, height,
+            // safely convert ceil(double) to int through float cast and std::round
+            std::round((float)(std::ceil(frameRate)))
+    );
+    return covers(other);
+}
+
+bool VideoCapabilities::PerformancePoint::covers(
+        const PerformancePoint &other) const {
+    // convert performance points to common block size
+    VideoSize commonSize = getCommonBlockSize(other);
+    PerformancePoint aligned = PerformancePoint(*this, commonSize);
+    PerformancePoint otherAligned = PerformancePoint(other, commonSize);
+
+    return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks()
+            && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate
+            && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
+}
+
+VideoSize VideoCapabilities::PerformancePoint::getCommonBlockSize(
+        const PerformancePoint &other) const {
+    return VideoSize(
+            16 * std::max(mBlockSize.getWidth(), other.mBlockSize.getWidth()),
+            16 * std::max(mBlockSize.getHeight(), other.mBlockSize.getHeight()));
+}
+
+bool VideoCapabilities::PerformancePoint::equals(
+        const PerformancePoint &other) const {
+    // convert performance points to common block size
+    VideoSize commonSize = getCommonBlockSize(other);
+    PerformancePoint aligned = PerformancePoint(*this, commonSize);
+    PerformancePoint otherAligned = PerformancePoint(other, commonSize);
+
+    return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks()
+            && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate
+            && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate);
+}
+
+// VideoCapabilities
+
+const std::vector<VideoCapabilities::PerformancePoint>&
+        VideoCapabilities::getSupportedPerformancePoints() const {
+    return mPerformancePoints;
+}
+
+bool VideoCapabilities::areSizeAndRateSupported(
+        int32_t width, int32_t height, double frameRate) const {
+    return supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
+            std::make_optional<double>(frameRate));
+}
+
+bool VideoCapabilities::isSizeSupported(int32_t width, int32_t height) const {
+    return supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
+            std::nullopt /* rate */);
+}
+
+bool VideoCapabilities::supports(std::optional<int32_t> width, std::optional<int32_t> height,
+        std::optional<double> rate) const {
+    bool ok = true;
+
+    if (width) {
+        ok &= mWidthRange.contains(width.value())
+                && (width.value() % mWidthAlignment == 0);
+    }
+    if (height) {
+        ok &= mHeightRange.contains(height.value())
+                && (height.value() % mHeightAlignment == 0);
+    }
+    if (rate) {
+        ok &= mFrameRateRange.contains(Range<int32_t>::RangeFor(rate.value()));
+    }
+    if (height && width) {
+        ok &= std::min(height.value(), width.value()) <= mSmallerDimensionUpperLimit;
+
+        const int32_t widthInBlocks = divUp(width.value(), mBlockWidth);
+        const int32_t heightInBlocks = divUp(height.value(), mBlockHeight);
+        const int32_t blockCount = widthInBlocks * heightInBlocks;
+        ok &= mBlockCountRange.contains(blockCount)
+                && mBlockAspectRatioRange.contains(
+                        Rational(widthInBlocks, heightInBlocks))
+                && mAspectRatioRange.contains(Rational(width.value(), height.value()));
+        if (rate) {
+            double blocksPerSec = blockCount * rate.value();
+            ok &= mBlocksPerSecondRange.contains(
+                    Range<int64_t>::RangeFor(blocksPerSec));
+        }
+    }
+    return ok;
+}
+
+bool VideoCapabilities::supportsFormat(const sp<AMessage> &format) const {
+    int32_t widthVal, heightVal;
+    std::optional<int32_t> width = format->findInt32(KEY_WIDTH, &widthVal)
+            ? std::make_optional<int32_t>(widthVal) : std::nullopt;
+    std::optional<int32_t> height = format->findInt32(KEY_HEIGHT, &heightVal)
+            ? std::make_optional<int32_t>(heightVal) : std::nullopt;
+    double rateVal;
+    std::optional<double> rate = format->findDouble(KEY_FRAME_RATE, &rateVal)
+            ? std::make_optional<double>(rateVal) : std::nullopt;
+
+    if (!supports(width, height, rate)) {
+        return false;
+    }
+
+    if (!CodecCapabilities::SupportsBitrate(mBitrateRange, format)) {
+        return false;
+    }
+
+    // we ignore color-format for now as it is not reliably reported by codec
+    return true;
+}
+
+// static
+std::shared_ptr<VideoCapabilities> VideoCapabilities::Create(std::string mediaType,
+        std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
+    std::shared_ptr<VideoCapabilities> caps(new VideoCapabilities());
+    caps->init(mediaType, profLevs, format);
+    return caps;
+}
+
+void VideoCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+        const sp<AMessage> &format) {
+    mMediaType = mediaType;
+    mProfileLevels = profLevs;
+    mError = 0;
+
+    initWithPlatformLimits();
+    applyLevelLimits();
+    parseFromInfo(format);
+    updateLimits();
+}
+
+VideoSize VideoCapabilities::getBlockSize() const {
+    return VideoSize(mBlockWidth, mBlockHeight);
+}
+
+const Range<int32_t>& VideoCapabilities::getBlockCountRange() const {
+    return mBlockCountRange;
+}
+
+const Range<int64_t>& VideoCapabilities::getBlocksPerSecondRange() const {
+    return mBlocksPerSecondRange;
+}
+
+Range<Rational> VideoCapabilities::getAspectRatioRange(bool blocks) const {
+    return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
+}
+
+void VideoCapabilities::initWithPlatformLimits() {
+    mBitrateRange = BITRATE_RANGE;
+
+    mWidthRange  = VideoSize::GetAllowedDimensionRange();
+    mHeightRange = VideoSize::GetAllowedDimensionRange();
+    mFrameRateRange = FRAME_RATE_RANGE;
+
+    mHorizontalBlockRange = VideoSize::GetAllowedDimensionRange();
+    mVerticalBlockRange   = VideoSize::GetAllowedDimensionRange();
+
+    // full positive ranges are supported as these get calculated
+    mBlockCountRange      = POSITIVE_INT32;
+    mBlocksPerSecondRange = POSITIVE_INT64;
+
+    mBlockAspectRatioRange = POSITIVE_RATIONALS;
+    mAspectRatioRange      = POSITIVE_RATIONALS;
+
+    // YUV 4:2:0 requires 2:2 alignment
+    mWidthAlignment = 2;
+    mHeightAlignment = 2;
+    mBlockWidth = 2;
+    mBlockHeight = 2;
+    mSmallerDimensionUpperLimit = VideoSize::GetAllowedDimensionRange().upper();
+}
+
+std::vector<VideoCapabilities::PerformancePoint>
+        VideoCapabilities::getPerformancePoints(
+        const sp<AMessage> &format) const {
+    std::vector<PerformancePoint> ret;
+    AMessage::Type type;
+    for (int i = 0; i < format->countEntries(); i++) {
+        const char *name = format->getEntryNameAt(i, &type);
+        AString rangeStr;
+        if (!format->findString(name, &rangeStr)) {
+            continue;
+        }
+
+        const std::string key = std::string(name);
+        // looking for: performance-point-WIDTHxHEIGHT-range
+
+        // check none performance point
+        if (key == "performance-point-none" && ret.size() == 0) {
+            // This means that component knowingly did not publish performance points.
+            // This is different from when the component forgot to publish performance
+            // points.
+            return ret;
+        }
+
+        // parse size from key
+        std::regex sizeRegex("performance-point-(.+)-range");
+        std::smatch sizeMatch;
+        if (!std::regex_match(key, sizeMatch, sizeRegex)) {
+            continue;
+        }
+        std::optional<VideoSize> size = VideoSize::ParseSize(sizeMatch[1].str());
+        if (!size || size.value().getWidth() * size.value().getHeight() <= 0) {
+            continue;
+        }
+
+        // parse range from value
+        std::optional<Range<int64_t>> range = Range<int64_t>::Parse(std::string(rangeStr.c_str()));
+        if (!range || range.value().lower() < 0 || range.value().upper() < 0) {
+            continue;
+        }
+
+        PerformancePoint given = PerformancePoint(
+                size.value().getWidth(), size.value().getHeight(), (int32_t)range.value().lower(),
+                (int32_t)range.value().upper(), VideoSize(mBlockWidth, mBlockHeight));
+        PerformancePoint rotated = PerformancePoint(
+                size.value().getHeight(), size.value().getWidth(), (int32_t)range.value().lower(),
+                (int32_t)range.value().upper(), VideoSize(mBlockWidth, mBlockHeight));
+        ret.push_back(given);
+        if (!given.covers(rotated)) {
+            ret.push_back(rotated);
+        }
+    }
+
+    // check if the component specified no performance point indication
+    if (ret.size() == 0) {
+        return ret;
+    }
+
+    // sort reversed by area first, then by frame rate
+    std::sort(ret.begin(), ret.end(), [](const PerformancePoint &a, const PerformancePoint &b) {
+        return -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ?
+                        (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) :
+                (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ?
+                        (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) :
+                (a.getMaxFrameRate() != b.getMaxFrameRate()) ?
+                        (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0);
+    });
+
+    return ret;
+}
+
+std::map<VideoSize, Range<int64_t>, VideoSizeCompare> VideoCapabilities
+        ::getMeasuredFrameRates(const sp<AMessage> &format) const {
+    std::map<VideoSize, Range<int64_t>, VideoSizeCompare> ret;
+    AMessage::Type type;
+    for (int i = 0; i < format->countEntries(); i++) {
+        const char *name = format->getEntryNameAt(i, &type);
+        AString rangeStr;
+        if (!format->findString(name, &rangeStr)) {
+            continue;
+        }
+
+        const std::string key = std::string(name);
+        // looking for: measured-frame-rate-WIDTHxHEIGHT-range
+
+        std::regex sizeRegex("measured-frame-rate-(.+)-range");
+        std::smatch sizeMatch;
+        if (!std::regex_match(key, sizeMatch, sizeRegex)) {
+            continue;
+        }
+
+        std::optional<VideoSize> size = VideoSize::ParseSize(sizeMatch[1].str());
+        if (!size || size.value().getWidth() * size.value().getHeight() <= 0) {
+            continue;
+        }
+
+        std::optional<Range<int64_t>> range = Range<int64_t>::Parse(std::string(rangeStr.c_str()));
+        if (!range || range.value().lower() < 0 || range.value().upper() < 0) {
+            continue;
+        }
+
+        ret.emplace(size.value(), range.value());
+    }
+    return ret;
+}
+
+// static
+std::optional<std::pair<Range<int32_t>, Range<int32_t>>> VideoCapabilities
+        ::ParseWidthHeightRanges(const std::string &str) {
+    std::optional<std::pair<VideoSize, VideoSize>> range = VideoSize::ParseSizeRange(str);
+    if (!range) {
+        ALOGW("could not parse size range: %s", str.c_str());
+        return std::nullopt;
+    }
+
+    return std::make_optional(std::pair(
+            Range(range.value().first.getWidth(), range.value().second.getWidth()),
+            Range(range.value().first.getHeight(), range.value().second.getHeight())));
+}
+
+// static
+int32_t VideoCapabilities::EquivalentVP9Level(const sp<AMessage> &format) {
+    int32_t blockSizeWidth = 8;
+    int32_t blockSizeHeight = 8;
+    // VideoSize *blockSizePtr = &VideoSize(8, 8);
+    AString blockSizeStr;
+    if (format->findString("block-size", &blockSizeStr)) {
+        std::optional<VideoSize> parsedBlockSize
+                = VideoSize::ParseSize(std::string(blockSizeStr.c_str()));
+        if (parsedBlockSize) {
+            // blockSize = parsedBlockSize.value();
+            blockSizeWidth = parsedBlockSize.value().getWidth();
+            blockSizeHeight = parsedBlockSize.value().getHeight();
+        }
+    }
+    int32_t BS = blockSizeWidth * blockSizeHeight;
+
+    int32_t FS = 0;
+    AString blockCountRangeStr;
+    if (format->findString("block-count-range", &blockCountRangeStr)) {
+        std::optional<Range<int>> counts = Range<int32_t>::Parse(
+                std::string(blockCountRangeStr.c_str()));
+        if (counts) {
+            FS = BS * counts.value().upper();
+        }
+    }
+
+    int64_t SR = 0;
+    AString blockRatesStr;
+    if (format->findString("blocks-per-second-range", &blockRatesStr)) {
+        std::optional<Range<int64_t>> blockRates
+                = Range<int64_t>::Parse(std::string(blockRatesStr.c_str()));
+        if (blockRates) {
+            // ToDo: Catch the potential overflow issue.
+            SR = BS * blockRates.value().upper();
+        }
+    }
+
+    int32_t D = 0;
+    AString dimensionRangesStr;
+    if (format->findString("size-range", &dimensionRangesStr)) {
+        std::optional<std::pair<Range<int>, Range<int>>> dimensionRanges =
+                ParseWidthHeightRanges(std::string(dimensionRangesStr.c_str()));
+        if (dimensionRanges) {
+            D = std::max(dimensionRanges.value().first.upper(),
+                    dimensionRanges.value().second.upper());
+        }
+    }
+
+    int32_t BR = 0;
+    AString bitrateRangeStr;
+    if (format->findString("bitrate-range", &bitrateRangeStr)) {
+        std::optional<Range<int>> bitRates = Range<int32_t>::Parse(
+                std::string(bitrateRangeStr.c_str()));
+        if (bitRates) {
+            BR = divUp(bitRates.value().upper(), 1000);
+        }
+    }
+
+    if (SR <=      829440 && FS <=    36864 && BR <=    200 && D <=   512)
+        return VP9Level1;
+    if (SR <=     2764800 && FS <=    73728 && BR <=    800 && D <=   768)
+        return VP9Level11;
+    if (SR <=     4608000 && FS <=   122880 && BR <=   1800 && D <=   960)
+        return VP9Level2;
+    if (SR <=     9216000 && FS <=   245760 && BR <=   3600 && D <=  1344)
+        return VP9Level21;
+    if (SR <=    20736000 && FS <=   552960 && BR <=   7200 && D <=  2048)
+        return VP9Level3;
+    if (SR <=    36864000 && FS <=   983040 && BR <=  12000 && D <=  2752)
+        return VP9Level31;
+    if (SR <=    83558400 && FS <=  2228224 && BR <=  18000 && D <=  4160)
+        return VP9Level4;
+    if (SR <=   160432128 && FS <=  2228224 && BR <=  30000 && D <=  4160)
+        return VP9Level41;
+    if (SR <=   311951360 && FS <=  8912896 && BR <=  60000 && D <=  8384)
+        return VP9Level5;
+    if (SR <=   588251136 && FS <=  8912896 && BR <= 120000 && D <=  8384)
+        return VP9Level51;
+    if (SR <=  1176502272 && FS <=  8912896 && BR <= 180000 && D <=  8384)
+        return VP9Level52;
+    if (SR <=  1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832)
+        return VP9Level6;
+    if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832)
+        return VP9Level61;
+    if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832)
+        return VP9Level62;
+    // returning largest level
+    return VP9Level62;
+}
+
+void VideoCapabilities::parseFromInfo(const sp<AMessage> &format) {
+    VideoSize blockSize = VideoSize(mBlockWidth, mBlockHeight);
+    VideoSize alignment = VideoSize(mWidthAlignment, mHeightAlignment);
+    std::optional<Range<int32_t>> counts, widths, heights;
+    std::optional<Range<int32_t>> frameRates, bitRates;
+    std::optional<Range<int64_t>> blockRates;
+    std::optional<Range<Rational>> ratios, blockRatios;
+
+    AString blockSizeStr;
+    if (format->findString("block-size", &blockSizeStr)) {
+        std::optional<VideoSize> parsedBlockSize
+                = VideoSize::ParseSize(std::string(blockSizeStr.c_str()));
+        blockSize = parsedBlockSize.value_or(blockSize);
+    }
+    AString alignmentStr;
+    if (format->findString("alignment", &alignmentStr)) {
+        std::optional<VideoSize> parsedAlignment
+            = VideoSize::ParseSize(std::string(alignmentStr.c_str()));
+        alignment = parsedAlignment.value_or(alignment);
+    }
+    AString blockCountRangeStr;
+    if (format->findString("block-count-range", &blockCountRangeStr)) {
+        std::optional<Range<int>> parsedBlockCountRange =
+                Range<int32_t>::Parse(std::string(blockCountRangeStr.c_str()));
+        if (parsedBlockCountRange) {
+            counts = parsedBlockCountRange.value();
+        }
+    }
+    AString blockRatesStr;
+    if (format->findString("blocks-per-second-range", &blockRatesStr)) {
+        blockRates = Range<int64_t>::Parse(std::string(blockRatesStr.c_str()));
+    }
+    mMeasuredFrameRates = getMeasuredFrameRates(format);
+    mPerformancePoints = getPerformancePoints(format);
+    AString sizeRangesStr;
+    if (format->findString("size-range", &sizeRangesStr)) {
+        std::optional<std::pair<Range<int>, Range<int>>> sizeRanges =
+            ParseWidthHeightRanges(std::string(sizeRangesStr.c_str()));
+        if (sizeRanges) {
+            widths = sizeRanges.value().first;
+            heights = sizeRanges.value().second;
+        }
+    }
+    // for now this just means using the smaller max size as 2nd
+    // upper limit.
+    // for now we are keeping the profile specific "width/height
+    // in macroblocks" limits.
+    if (format->contains("feature-can-swap-width-height")) {
+        if (widths && heights) {
+            mSmallerDimensionUpperLimit =
+                std::min(widths.value().upper(), heights.value().upper());
+            widths = heights = widths.value().extend(heights.value());
+        } else {
+            ALOGW("feature can-swap-width-height is best used with size-range");
+            mSmallerDimensionUpperLimit =
+                std::min(mWidthRange.upper(), mHeightRange.upper());
+            mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
+        }
+    }
+
+    AString ratioStr;
+    if (format->findString("block-aspect-ratio-range", &ratioStr)) {
+        ratios = Rational::ParseRange(std::string(ratioStr.c_str()));
+    }
+    AString blockRatiosStr;
+    if (format->findString("pixel-aspect-ratio-range", &blockRatiosStr)) {
+        blockRatios = Rational::ParseRange(std::string(blockRatiosStr.c_str()));
+    }
+    AString frameRatesStr;
+    if (format->findString("frame-rate-range", &frameRatesStr)) {
+        frameRates = Range<int32_t>::Parse(std::string(frameRatesStr.c_str()));
+        if (frameRates) {
+            frameRates = frameRates.value().intersect(FRAME_RATE_RANGE);
+            if (frameRates.value().empty()) {
+                ALOGW("frame rate range is out of limits");
+                frameRates = std::nullopt;
+            }
+        }
+    }
+    AString bitRatesStr;
+    if (format->findString("bitrate-range", &bitRatesStr)) {
+        bitRates = Range<int32_t>::Parse(std::string(bitRatesStr.c_str()));
+        if (bitRates) {
+            bitRates = bitRates.value().intersect(BITRATE_RANGE);
+            if (bitRates.value().empty()) {
+                ALOGW("bitrate range is out of limits");
+                bitRates = std::nullopt;
+            }
+        }
+    }
+
+    if (!IsPowerOfTwo(blockSize.getWidth()) || !IsPowerOfTwo(blockSize.getHeight())
+            || !IsPowerOfTwo(alignment.getWidth()) || !IsPowerOfTwo(alignment.getHeight())) {
+        ALOGE("The widths and heights of blockSizes and alignments must be the power of two."
+                " blockSize width: %d; blockSize height: %d;"
+                " alignment width: %d; alignment height: %d.",
+                blockSize.getWidth(), blockSize.getHeight(),
+                alignment.getWidth(), alignment.getHeight());
+        mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
+        return;
+    }
+
+    // update block-size and alignment
+    applyMacroBlockLimits(
+            INT32_MAX, INT32_MAX, INT32_MAX, INT64_MAX,
+            blockSize.getWidth(), blockSize.getHeight(),
+            alignment.getWidth(), alignment.getHeight());
+
+    if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0 || mAllowMbOverride) {
+        // codec supports profiles that we don't know.
+        // Use supplied values clipped to platform limits
+        if (widths) {
+            mWidthRange = VideoSize::GetAllowedDimensionRange().intersect(widths.value());
+        }
+        if (heights) {
+            mHeightRange = VideoSize::GetAllowedDimensionRange().intersect(heights.value());
+        }
+        if (counts) {
+            mBlockCountRange = POSITIVE_INT32.intersect(
+                    counts.value().factor(mBlockWidth * mBlockHeight
+                            / blockSize.getWidth() / blockSize.getHeight()));
+        }
+        if (blockRates) {
+            mBlocksPerSecondRange = POSITIVE_INT64.intersect(
+                    blockRates.value().factor(mBlockWidth * mBlockHeight
+                            / blockSize.getWidth() / blockSize.getHeight()));
+        }
+        if (blockRatios) {
+            mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
+                    Rational::ScaleRange(blockRatios.value(),
+                            mBlockHeight / blockSize.getHeight(),
+                            mBlockWidth / blockSize.getWidth()));
+        }
+        if (ratios) {
+            mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios.value());
+        }
+        if (frameRates) {
+            mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates.value());
+        }
+        if (bitRates) {
+            // only allow bitrate override if unsupported profiles were encountered
+            if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0) {
+                mBitrateRange = BITRATE_RANGE.intersect(bitRates.value());
+            } else {
+                mBitrateRange = mBitrateRange.intersect(bitRates.value());
+            }
+        }
+    } else {
+        // no unsupported profile/levels, so restrict values to known limits
+        if (widths) {
+            mWidthRange = mWidthRange.intersect(widths.value());
+        }
+        if (heights) {
+            mHeightRange = mHeightRange.intersect(heights.value());
+        }
+        if (counts) {
+            mBlockCountRange = mBlockCountRange.intersect(
+                    counts.value().factor(mBlockWidth * mBlockHeight
+                            / blockSize.getWidth() / blockSize.getHeight()));
+        }
+        if (blockRates) {
+            mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
+                    blockRates.value().factor(mBlockWidth * mBlockHeight
+                            / blockSize.getWidth() / blockSize.getHeight()));
+        }
+        if (blockRatios) {
+            mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
+                    Rational::ScaleRange(blockRatios.value(),
+                            mBlockHeight / blockSize.getHeight(),
+                            mBlockWidth / blockSize.getWidth()));
+        }
+        if (ratios) {
+            mAspectRatioRange = mAspectRatioRange.intersect(ratios.value());
+        }
+        if (frameRates) {
+            mFrameRateRange = mFrameRateRange.intersect(frameRates.value());
+        }
+        if (bitRates) {
+            mBitrateRange = mBitrateRange.intersect(bitRates.value());
+        }
+    }
+    updateLimits();
+}
+
+void VideoCapabilities::applyBlockLimits(
+        int32_t blockWidth, int32_t blockHeight,
+        Range<int32_t> counts, Range<int64_t> rates, Range<Rational> ratios) {
+
+    if (!IsPowerOfTwo(blockWidth) || !IsPowerOfTwo(blockHeight)) {
+        ALOGE("blockWidth and blockHeight must be the power of two."
+                " blockWidth: %d; blockHeight: %d", blockWidth, blockHeight);
+        mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
+        return;
+    }
+
+    const int32_t newBlockWidth = std::max(blockWidth, mBlockWidth);
+    const int32_t newBlockHeight = std::max(blockHeight, mBlockHeight);
+
+    // factor will always be a power-of-2
+    int32_t factor =
+        newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
+    if (factor != 1) {
+        mBlockCountRange = mBlockCountRange.factor(factor);
+        mBlocksPerSecondRange = mBlocksPerSecondRange.factor(factor);
+        mBlockAspectRatioRange = Rational::ScaleRange(
+                mBlockAspectRatioRange,
+                newBlockHeight / mBlockHeight,
+                newBlockWidth / mBlockWidth);
+        mHorizontalBlockRange = mHorizontalBlockRange.factor(newBlockWidth / mBlockWidth);
+        mVerticalBlockRange = mVerticalBlockRange.factor(newBlockHeight / mBlockHeight);
+    }
+    factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
+    if (factor != 1) {
+        counts = counts.factor(factor);
+        rates = rates.factor((int64_t)factor);
+        ratios = Rational::ScaleRange(
+                ratios, newBlockHeight / blockHeight,
+                newBlockWidth / blockWidth);
+    }
+    mBlockCountRange = mBlockCountRange.intersect(counts);
+    mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
+    mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
+    mBlockWidth = newBlockWidth;
+    mBlockHeight = newBlockHeight;
+}
+
+void VideoCapabilities::applyAlignment(
+        int32_t widthAlignment, int32_t heightAlignment) {
+    if (!IsPowerOfTwo(widthAlignment) || !IsPowerOfTwo(heightAlignment)) {
+        ALOGE("width and height alignments must be the power of two."
+                " widthAlignment: %d; heightAlignment: %d", widthAlignment, heightAlignment);
+        mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
+        return;
+    }
+
+    if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
+        // maintain assumption that 0 < alignment <= block-size
+        applyBlockLimits(
+                std::max(widthAlignment, mBlockWidth),
+                std::max(heightAlignment, mBlockHeight),
+                POSITIVE_INT32, POSITIVE_INT64, POSITIVE_RATIONALS);
+    }
+
+    mWidthAlignment = std::max(widthAlignment, mWidthAlignment);
+    mHeightAlignment = std::max(heightAlignment, mHeightAlignment);
+
+    mWidthRange = mWidthRange.align(mWidthAlignment);
+    mHeightRange = mHeightRange.align(mHeightAlignment);
+}
+
+void VideoCapabilities::updateLimits() {
+    // pixels -> blocks <- counts
+    mHorizontalBlockRange = mHorizontalBlockRange.intersect(
+            mWidthRange.factor(mBlockWidth));
+    mHorizontalBlockRange = mHorizontalBlockRange.intersect(
+            Range(  mBlockCountRange.lower() / mVerticalBlockRange.upper(),
+                    mBlockCountRange.upper() / mVerticalBlockRange.lower()));
+    mVerticalBlockRange = mVerticalBlockRange.intersect(
+            mHeightRange.factor(mBlockHeight));
+    mVerticalBlockRange = mVerticalBlockRange.intersect(
+            Range(  mBlockCountRange.lower() / mHorizontalBlockRange.upper(),
+                    mBlockCountRange.upper() / mHorizontalBlockRange.lower()));
+    mBlockCountRange = mBlockCountRange.intersect(
+            Range(  mHorizontalBlockRange.lower()
+                            * mVerticalBlockRange.lower(),
+                    mHorizontalBlockRange.upper()
+                            * mVerticalBlockRange.upper()));
+    mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
+            Rational(mHorizontalBlockRange.lower(), mVerticalBlockRange.upper()),
+            Rational(mHorizontalBlockRange.upper(), mVerticalBlockRange.lower()));
+
+    // blocks -> pixels
+    mWidthRange = mWidthRange.intersect(
+            (mHorizontalBlockRange.lower() - 1) * mBlockWidth + mWidthAlignment,
+            mHorizontalBlockRange.upper() * mBlockWidth);
+    mHeightRange = mHeightRange.intersect(
+            (mVerticalBlockRange.lower() - 1) * mBlockHeight + mHeightAlignment,
+            mVerticalBlockRange.upper() * mBlockHeight);
+    mAspectRatioRange = mAspectRatioRange.intersect(
+            Rational(mWidthRange.lower(), mHeightRange.upper()),
+            Rational(mWidthRange.upper(), mHeightRange.lower()));
+
+    mSmallerDimensionUpperLimit = std::min(
+            mSmallerDimensionUpperLimit,
+            std::min(mWidthRange.upper(), mHeightRange.upper()));
+
+    // blocks -> rate
+    mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
+            mBlockCountRange.lower() * (int64_t)mFrameRateRange.lower(),
+            mBlockCountRange.upper() * (int64_t)mFrameRateRange.upper());
+    mFrameRateRange = mFrameRateRange.intersect(
+            (int32_t)(mBlocksPerSecondRange.lower()
+                    / mBlockCountRange.upper()),
+            (int32_t)(mBlocksPerSecondRange.upper()
+                    / (double)mBlockCountRange.lower()));
+}
+
+void VideoCapabilities::applyMacroBlockLimits(
+        int32_t maxHorizontalBlocks, int32_t maxVerticalBlocks,
+        int32_t maxBlocks, int64_t maxBlocksPerSecond,
+        int32_t blockWidth, int32_t blockHeight,
+        int32_t widthAlignment, int32_t heightAlignment) {
+    applyMacroBlockLimits(
+            1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */,
+            maxHorizontalBlocks, maxVerticalBlocks,
+            maxBlocks, maxBlocksPerSecond,
+            blockWidth, blockHeight, widthAlignment, heightAlignment);
+}
+
+void VideoCapabilities::applyMacroBlockLimits(
+        int32_t minHorizontalBlocks, int32_t minVerticalBlocks,
+        int32_t maxHorizontalBlocks, int32_t maxVerticalBlocks,
+        int32_t maxBlocks, int64_t maxBlocksPerSecond,
+        int32_t blockWidth, int32_t blockHeight,
+        int32_t widthAlignment, int32_t heightAlignment) {
+    applyAlignment(widthAlignment, heightAlignment);
+    applyBlockLimits(
+            blockWidth, blockHeight, Range((int32_t)1, maxBlocks),
+            Range((int64_t)1, maxBlocksPerSecond),
+            Range(Rational(1, maxVerticalBlocks), Rational(maxHorizontalBlocks, 1)));
+    mHorizontalBlockRange =
+            mHorizontalBlockRange.intersect(
+                    divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)),
+                    maxHorizontalBlocks / (mBlockWidth / blockWidth));
+    mVerticalBlockRange =
+            mVerticalBlockRange.intersect(
+                    divUp(minVerticalBlocks, (mBlockHeight / blockHeight)),
+                    maxVerticalBlocks / (mBlockHeight / blockHeight));
+}
+
+void VideoCapabilities::applyLevelLimits() {
+    int64_t maxBlocksPerSecond = 0;
+    int32_t maxBlocks = 0;
+    int32_t maxBps = 0;
+    int32_t maxDPBBlocks = 0;
+
+    int errors = ERROR_CAPABILITIES_NONE_SUPPORTED;
+    const char *mediaType = mMediaType.c_str();
+    if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_AVC)) {
+        maxBlocks = 99;
+        maxBlocksPerSecond = 1485;
+        maxBps = 64000;
+        maxDPBBlocks = 396;
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            int32_t MBPS = 0, FS = 0, BR = 0, DPB = 0;
+            bool supported = true;
+            switch (profileLevel.mLevel) {
+                case AVCLevel1:
+                    MBPS =     1485; FS =     99; BR =     64; DPB =    396; break;
+                case AVCLevel1b:
+                    MBPS =     1485; FS =     99; BR =    128; DPB =    396; break;
+                case AVCLevel11:
+                    MBPS =     3000; FS =    396; BR =    192; DPB =    900; break;
+                case AVCLevel12:
+                    MBPS =     6000; FS =    396; BR =    384; DPB =   2376; break;
+                case AVCLevel13:
+                    MBPS =    11880; FS =    396; BR =    768; DPB =   2376; break;
+                case AVCLevel2:
+                    MBPS =    11880; FS =    396; BR =   2000; DPB =   2376; break;
+                case AVCLevel21:
+                    MBPS =    19800; FS =    792; BR =   4000; DPB =   4752; break;
+                case AVCLevel22:
+                    MBPS =    20250; FS =   1620; BR =   4000; DPB =   8100; break;
+                case AVCLevel3:
+                    MBPS =    40500; FS =   1620; BR =  10000; DPB =   8100; break;
+                case AVCLevel31:
+                    MBPS =   108000; FS =   3600; BR =  14000; DPB =  18000; break;
+                case AVCLevel32:
+                    MBPS =   216000; FS =   5120; BR =  20000; DPB =  20480; break;
+                case AVCLevel4:
+                    MBPS =   245760; FS =   8192; BR =  20000; DPB =  32768; break;
+                case AVCLevel41:
+                    MBPS =   245760; FS =   8192; BR =  50000; DPB =  32768; break;
+                case AVCLevel42:
+                    MBPS =   522240; FS =   8704; BR =  50000; DPB =  34816; break;
+                case AVCLevel5:
+                    MBPS =   589824; FS =  22080; BR = 135000; DPB = 110400; break;
+                case AVCLevel51:
+                    MBPS =   983040; FS =  36864; BR = 240000; DPB = 184320; break;
+                case AVCLevel52:
+                    MBPS =  2073600; FS =  36864; BR = 240000; DPB = 184320; break;
+                case AVCLevel6:
+                    MBPS =  4177920; FS = 139264; BR = 240000; DPB = 696320; break;
+                case AVCLevel61:
+                    MBPS =  8355840; FS = 139264; BR = 480000; DPB = 696320; break;
+                case AVCLevel62:
+                    MBPS = 16711680; FS = 139264; BR = 800000; DPB = 696320; break;
+                default:
+                    ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            switch (profileLevel.mProfile) {
+                case AVCProfileConstrainedHigh:
+                case AVCProfileHigh:
+                    BR *= 1250; break;
+                case AVCProfileHigh10:
+                    BR *= 3000; break;
+                case AVCProfileExtended:
+                case AVCProfileHigh422:
+                case AVCProfileHigh444:
+                    ALOGW("Unsupported profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+                    supported = false;
+                    FALLTHROUGH_INTENDED;
+                    // fall through - treat as base profile
+                case AVCProfileConstrainedBaseline:
+                    FALLTHROUGH_INTENDED;
+                case AVCProfileBaseline:
+                    FALLTHROUGH_INTENDED;
+                case AVCProfileMain:
+                    BR *= 1000; break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+                    BR *= 1000;
+            }
+            if (supported) {
+                errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+            }
+            maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
+            maxBlocks = std::max(FS, maxBlocks);
+            maxBps = std::max(BR, maxBps);
+            maxDPBBlocks = std::max(maxDPBBlocks, DPB);
+        }
+
+        int32_t maxLengthInBlocks = (int32_t)(std::sqrt(8 * maxBlocks));
+        applyMacroBlockLimits(
+                maxLengthInBlocks, maxLengthInBlocks,
+                maxBlocks, maxBlocksPerSecond,
+                16 /* blockWidth */, 16 /* blockHeight */,
+                1 /* widthAlignment */, 1 /* heightAlignment */);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG2)) {
+        int32_t maxWidth = 11, maxHeight = 9, maxRate = 15;
+        maxBlocks = 99;
+        maxBlocksPerSecond = 1485;
+        maxBps = 64000;
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            int32_t MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
+            bool supported = true;
+            switch (profileLevel.mProfile) {
+                case MPEG2ProfileSimple:
+                    switch (profileLevel.mLevel) {
+                        case MPEG2LevelML:
+                            FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR =  15000; break;
+                        default:
+                            ALOGW("Unrecognized profile/level %d/%d for %s",
+                                    profileLevel.mProfile, profileLevel.mLevel, mediaType);
+                            errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+                    }
+                    break;
+                case MPEG2ProfileMain:
+                    switch (profileLevel.mLevel) {
+                        case MPEG2LevelLL:
+                            FR = 30; W = 22; H =  18; MBPS =  11880; FS =   396; BR =  4000; break;
+                        case MPEG2LevelML:
+                            FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR = 15000; break;
+                        case MPEG2LevelH14:
+                            FR = 60; W = 90; H =  68; MBPS = 183600; FS =  6120; BR = 60000; break;
+                        case MPEG2LevelHL:
+                            FR = 60; W = 120; H = 68; MBPS = 244800; FS =  8160; BR = 80000; break;
+                        case MPEG2LevelHP:
+                            FR = 60; W = 120; H = 68; MBPS = 489600; FS =  8160; BR = 80000; break;
+                        default:
+                            ALOGW("Unrecognized profile/level %d / %d for %s",
+                                    profileLevel.mProfile, profileLevel.mLevel, mediaType);
+                            errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+                    }
+                    break;
+                case MPEG2Profile422:
+                case MPEG2ProfileSNR:
+                case MPEG2ProfileSpatial:
+                case MPEG2ProfileHigh:
+                    ALOGW("Unsupported profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNSUPPORTED;
+                    supported = false;
+                    break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            if (supported) {
+                errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+            }
+            maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
+            maxBlocks = std::max(FS, maxBlocks);
+            maxBps = std::max(BR * 1000, maxBps);
+            maxWidth = std::max(W, maxWidth);
+            maxHeight = std::max(H, maxHeight);
+            maxRate = std::max(FR, maxRate);
+        }
+        applyMacroBlockLimits(maxWidth, maxHeight,
+                maxBlocks, maxBlocksPerSecond,
+                16 /* blockWidth */, 16 /* blockHeight */,
+                1 /* widthAlignment */, 1 /* heightAlignment */);
+        mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG4)) {
+        int32_t maxWidth = 11, maxHeight = 9, maxRate = 15;
+        maxBlocks = 99;
+        maxBlocksPerSecond = 1485;
+        maxBps = 64000;
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            int32_t MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
+            bool strict = false; // true: W, H and FR are individual max limits
+            bool supported = true;
+            switch (profileLevel.mProfile) {
+                case MPEG4ProfileSimple:
+                    switch (profileLevel.mLevel) {
+                        case MPEG4Level0:
+                            strict = true;
+                            FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
+                        case MPEG4Level1:
+                            FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
+                        case MPEG4Level0b:
+                            strict = true;
+                            FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR = 128; break;
+                        case MPEG4Level2:
+                            FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
+                        case MPEG4Level3:
+                            FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
+                        case MPEG4Level4a:
+                            FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break;
+                        case MPEG4Level5:
+                            FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break;
+                        case MPEG4Level6:
+                            FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break;
+                        default:
+                            ALOGW("Unrecognized profile/level %d/%d for %s",
+                                    profileLevel.mProfile, profileLevel.mLevel, mediaType);
+                            errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+                    }
+                    break;
+                case MPEG4ProfileAdvancedSimple:
+                    switch (profileLevel.mLevel) {
+                        case MPEG4Level0:
+                        case MPEG4Level1:
+                            FR = 30; W = 11; H =  9; MBPS =  2970; FS =   99; BR =  128; break;
+                        case MPEG4Level2:
+                            FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
+                        case MPEG4Level3:
+                            FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
+                        case MPEG4Level3b:
+                            FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR = 1500; break;
+                        case MPEG4Level4:
+                            FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
+                        case MPEG4Level5:
+                            FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
+                        default:
+                            ALOGW("Unrecognized profile/level %d/%d for %s",
+                                    profileLevel.mProfile, profileLevel.mLevel, mediaType);
+                            errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+                    }
+                    break;
+                case MPEG4ProfileMain:             // 2-4
+                case MPEG4ProfileNbit:             // 2
+                case MPEG4ProfileAdvancedRealTime: // 1-4
+                case MPEG4ProfileCoreScalable:     // 1-3
+                case MPEG4ProfileAdvancedCoding:   // 1-4
+                case MPEG4ProfileCore:             // 1-2
+                case MPEG4ProfileAdvancedCore:     // 1-4
+                case MPEG4ProfileSimpleScalable:   // 0-2
+                case MPEG4ProfileHybrid:           // 1-2
+
+                // Studio profiles are not supported by our codecs.
+
+                // Only profiles that can decode simple object types are considered.
+                // The following profiles are not able to.
+                case MPEG4ProfileBasicAnimated:    // 1-2
+                case MPEG4ProfileScalableTexture:  // 1
+                case MPEG4ProfileSimpleFace:       // 1-2
+                case MPEG4ProfileAdvancedScalable: // 1-3
+                case MPEG4ProfileSimpleFBA:        // 1-2
+                    ALOGV("Unsupported profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNSUPPORTED;
+                    supported = false;
+                    break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            if (supported) {
+                errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+            }
+            maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
+            maxBlocks = std::max(FS, maxBlocks);
+            maxBps = std::max(BR * 1000, maxBps);
+            if (strict) {
+                maxWidth = std::max(W, maxWidth);
+                maxHeight = std::max(H, maxHeight);
+                maxRate = std::max(FR, maxRate);
+            } else {
+                // assuming max 60 fps frame rate and 1:2 aspect ratio
+                int32_t maxDim = (int32_t)std::sqrt(2 * FS);
+                maxWidth = std::max(maxDim, maxWidth);
+                maxHeight = std::max(maxDim, maxHeight);
+                maxRate = std::max(std::max(FR, 60), maxRate);
+            }
+        }
+        applyMacroBlockLimits(maxWidth, maxHeight,
+                maxBlocks, maxBlocksPerSecond,
+                16 /* blockWidth */, 16 /* blockHeight */,
+                1 /* widthAlignment */, 1 /* heightAlignment */);
+        mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)) {
+        int32_t maxWidth = 11, maxHeight = 9, maxRate = 15;
+        int32_t minWidth = maxWidth, minHeight = maxHeight;
+        int32_t minAlignment = 16;
+        maxBlocks = 99;
+        maxBlocksPerSecond = 1485;
+        maxBps = 64000;
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            int32_t MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight;
+            bool strict = false; // true: support only sQCIF, QCIF (maybe CIF)
+            switch (profileLevel.mLevel) {
+                case H263Level10:
+                    strict = true; // only supports sQCIF & QCIF
+                    FR = 15; W = 11; H =  9; BR =   1; MBPS =  W * H * FR; break;
+                case H263Level20:
+                    strict = true; // only supports sQCIF, QCIF & CIF
+                    FR = 30; W = 22; H = 18; BR =   2; MBPS =  W * H * 15; break;
+                case H263Level30:
+                    strict = true; // only supports sQCIF, QCIF & CIF
+                    FR = 30; W = 22; H = 18; BR =   6; MBPS =  W * H * FR; break;
+                case H263Level40:
+                    strict = true; // only supports sQCIF, QCIF & CIF
+                    FR = 30; W = 22; H = 18; BR =  32; MBPS =  W * H * FR; break;
+                case H263Level45:
+                    // only implies level 10 support
+                    strict = profileLevel.mProfile == H263ProfileBaseline
+                            || profileLevel.mProfile ==
+                                    H263ProfileBackwardCompatible;
+                    if (!strict) {
+                        minW = 1; minH = 1; minAlignment = 4;
+                    }
+                    FR = 15; W = 11; H =  9; BR =   2; MBPS =  W * H * FR; break;
+                case H263Level50:
+                    // only supports 50fps for H > 15
+                    minW = 1; minH = 1; minAlignment = 4;
+                    FR = 60; W = 22; H = 18; BR =  64; MBPS =  W * H * 50; break;
+                case H263Level60:
+                    // only supports 50fps for H > 15
+                    minW = 1; minH = 1; minAlignment = 4;
+                    FR = 60; W = 45; H = 18; BR = 128; MBPS =  W * H * 50; break;
+                case H263Level70:
+                    // only supports 50fps for H > 30
+                    minW = 1; minH = 1; minAlignment = 4;
+                    FR = 60; W = 45; H = 36; BR = 256; MBPS =  W * H * 50; break;
+                default:
+                    ALOGW("Unrecognized profile/level %d/%d for %s",
+                            profileLevel.mProfile, profileLevel.mLevel, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            switch (profileLevel.mProfile) {
+                case H263ProfileBackwardCompatible:
+                case H263ProfileBaseline:
+                case H263ProfileH320Coding:
+                case H263ProfileHighCompression:
+                case H263ProfileHighLatency:
+                case H263ProfileInterlace:
+                case H263ProfileInternet:
+                case H263ProfileISWV2:
+                case H263ProfileISWV3:
+                    break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            if (strict) {
+                // Strict levels define sub-QCIF min size and enumerated sizes. We cannot
+                // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities
+                // but we can express "only QCIF (& CIF)", so set minimume size at QCIF.
+                // minW = 8; minH = 6;
+                minW = 11; minH = 9;
+            } else {
+                // any support for non-strict levels (including unrecognized profiles or
+                // levels) allow custom frame size support beyond supported limits
+                // (other than bitrate)
+                mAllowMbOverride = true;
+            }
+            errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+            maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
+            maxBlocks = std::max(W * H, maxBlocks);
+            maxBps = std::max(BR * 64000, maxBps);
+            maxWidth = std::max(W, maxWidth);
+            maxHeight = std::max(H, maxHeight);
+            maxRate = std::max(FR, maxRate);
+            minWidth = std::min(minW, minWidth);
+            minHeight = std::min(minH, minHeight);
+        }
+        // unless we encountered custom frame size support, limit size to QCIF and CIF
+        // using aspect ratio.
+        if (!mAllowMbOverride) {
+            mBlockAspectRatioRange =
+                Range(Rational(11, 9), Rational(11, 9));
+        }
+        applyMacroBlockLimits(
+                minWidth, minHeight,
+                maxWidth, maxHeight,
+                maxBlocks, maxBlocksPerSecond,
+                16 /* blockWidth */, 16 /* blockHeight */,
+                minAlignment /* widthAlignment */, minAlignment /* heightAlignment */);
+        mFrameRateRange = Range(1, maxRate);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_VP8)) {
+        maxBlocks = INT_MAX;
+        maxBlocksPerSecond = INT_MAX;
+
+        // TODO: set to 100Mbps for now, need a number for VP8
+        maxBps = 100000000;
+
+        // profile levels are not indicative for VPx, but verify
+        // them nonetheless
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            switch (profileLevel.mLevel) {
+                case VP8Level_Version0:
+                case VP8Level_Version1:
+                case VP8Level_Version2:
+                case VP8Level_Version3:
+                    break;
+                default:
+                    ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            switch (profileLevel.mProfile) {
+                case VP8ProfileMain:
+                    break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+        }
+
+        const int32_t blockSize = 16;
+        applyMacroBlockLimits(SHRT_MAX, SHRT_MAX,
+                maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
+                1 /* widthAlignment */, 1 /* heightAlignment */);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_VP9)) {
+        maxBlocksPerSecond = 829440;
+        maxBlocks = 36864;
+        maxBps = 200000;
+        int32_t maxDim = 512;
+
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            int64_t SR = 0; // luma sample rate
+            int32_t FS = 0;  // luma picture size
+            int32_t BR = 0;  // bit rate kbps
+            int32_t D = 0;   // luma dimension
+            switch (profileLevel.mLevel) {
+                case VP9Level1:
+                    SR =      829440; FS =    36864; BR =    200; D =   512; break;
+                case VP9Level11:
+                    SR =     2764800; FS =    73728; BR =    800; D =   768; break;
+                case VP9Level2:
+                    SR =     4608000; FS =   122880; BR =   1800; D =   960; break;
+                case VP9Level21:
+                    SR =     9216000; FS =   245760; BR =   3600; D =  1344; break;
+                case VP9Level3:
+                    SR =    20736000; FS =   552960; BR =   7200; D =  2048; break;
+                case VP9Level31:
+                    SR =    36864000; FS =   983040; BR =  12000; D =  2752; break;
+                case VP9Level4:
+                    SR =    83558400; FS =  2228224; BR =  18000; D =  4160; break;
+                case VP9Level41:
+                    SR =   160432128; FS =  2228224; BR =  30000; D =  4160; break;
+                case VP9Level5:
+                    SR =   311951360; FS =  8912896; BR =  60000; D =  8384; break;
+                case VP9Level51:
+                    SR =   588251136; FS =  8912896; BR = 120000; D =  8384; break;
+                case VP9Level52:
+                    SR =  1176502272; FS =  8912896; BR = 180000; D =  8384; break;
+                case VP9Level6:
+                    SR =  1176502272; FS = 35651584; BR = 180000; D = 16832; break;
+                case VP9Level61:
+                    SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break;
+                case VP9Level62:
+                    SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break;
+                default:
+                    ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            switch (profileLevel.mProfile) {
+                case VP9Profile0:
+                case VP9Profile1:
+                case VP9Profile2:
+                case VP9Profile3:
+                case VP9Profile2HDR:
+                case VP9Profile3HDR:
+                case VP9Profile2HDR10Plus:
+                case VP9Profile3HDR10Plus:
+                    break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+            maxBlocksPerSecond = std::max(SR, maxBlocksPerSecond);
+            maxBlocks = std::max(FS, maxBlocks);
+            maxBps = std::max(BR * 1000, maxBps);
+            maxDim = std::max(D, maxDim);
+        }
+
+        const int32_t blockSize = 8;
+        int32_t maxLengthInBlocks = divUp(maxDim, blockSize);
+        maxBlocks = divUp(maxBlocks, blockSize * blockSize);
+        maxBlocksPerSecond = divUp(maxBlocksPerSecond, blockSize * (int64_t)blockSize);
+
+        applyMacroBlockLimits(
+                maxLengthInBlocks, maxLengthInBlocks,
+                maxBlocks, maxBlocksPerSecond,
+                blockSize, blockSize,
+                1 /* widthAlignment */, 1 /* heightAlignment */);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_HEVC)) {
+        // CTBs are at least 8x8 so use 8x8 block size
+        maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks
+        maxBlocksPerSecond = maxBlocks * 15;
+        maxBps = 128000;
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            double FR = 0;
+            int32_t FS = 0, BR = 0;
+            switch (profileLevel.mLevel) {
+                /* The HEVC spec talks only in a very convoluted manner about the
+                    existence of levels 1-3.1 for High tier, which could also be
+                    understood as 'decoders and encoders should treat these levels
+                    as if they were Main tier', so we do that. */
+                case HEVCMainTierLevel1:
+                case HEVCHighTierLevel1:
+                    FR =    15; FS =    36864; BR =    128; break;
+                case HEVCMainTierLevel2:
+                case HEVCHighTierLevel2:
+                    FR =    30; FS =   122880; BR =   1500; break;
+                case HEVCMainTierLevel21:
+                case HEVCHighTierLevel21:
+                    FR =    30; FS =   245760; BR =   3000; break;
+                case HEVCMainTierLevel3:
+                case HEVCHighTierLevel3:
+                    FR =    30; FS =   552960; BR =   6000; break;
+                case HEVCMainTierLevel31:
+                case HEVCHighTierLevel31:
+                    FR = 33.75; FS =   983040; BR =  10000; break;
+                case HEVCMainTierLevel4:
+                    FR =    30; FS =  2228224; BR =  12000; break;
+                case HEVCHighTierLevel4:
+                    FR =    30; FS =  2228224; BR =  30000; break;
+                case HEVCMainTierLevel41:
+                    FR =    60; FS =  2228224; BR =  20000; break;
+                case HEVCHighTierLevel41:
+                    FR =    60; FS =  2228224; BR =  50000; break;
+                case HEVCMainTierLevel5:
+                    FR =    30; FS =  8912896; BR =  25000; break;
+                case HEVCHighTierLevel5:
+                    FR =    30; FS =  8912896; BR = 100000; break;
+                case HEVCMainTierLevel51:
+                    FR =    60; FS =  8912896; BR =  40000; break;
+                case HEVCHighTierLevel51:
+                    FR =    60; FS =  8912896; BR = 160000; break;
+                case HEVCMainTierLevel52:
+                    FR =   120; FS =  8912896; BR =  60000; break;
+                case HEVCHighTierLevel52:
+                    FR =   120; FS =  8912896; BR = 240000; break;
+                case HEVCMainTierLevel6:
+                    FR =    30; FS = 35651584; BR =  60000; break;
+                case HEVCHighTierLevel6:
+                    FR =    30; FS = 35651584; BR = 240000; break;
+                case HEVCMainTierLevel61:
+                    FR =    60; FS = 35651584; BR = 120000; break;
+                case HEVCHighTierLevel61:
+                    FR =    60; FS = 35651584; BR = 480000; break;
+                case HEVCMainTierLevel62:
+                    FR =   120; FS = 35651584; BR = 240000; break;
+                case HEVCHighTierLevel62:
+                    FR =   120; FS = 35651584; BR = 800000; break;
+                default:
+                    ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            switch (profileLevel.mProfile) {
+                case HEVCProfileMain:
+                case HEVCProfileMain10:
+                case HEVCProfileMainStill:
+                case HEVCProfileMain10HDR10:
+                case HEVCProfileMain10HDR10Plus:
+                    break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+
+            /* DPB logic:
+            if      (width * height <= FS / 4)    DPB = 16;
+            else if (width * height <= FS / 2)    DPB = 12;
+            else if (width * height <= FS * 0.75) DPB = 8;
+            else                                  DPB = 6;
+            */
+
+            FS >>= 6; // convert pixels to blocks
+            errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+            maxBlocksPerSecond = std::max((int64_t)(FR * FS), maxBlocksPerSecond);
+            maxBlocks = std::max(FS, maxBlocks);
+            maxBps = std::max(1000 * BR, maxBps);
+        }
+
+        int32_t maxLengthInBlocks = (int32_t)(std::sqrt(8 * maxBlocks));
+        applyMacroBlockLimits(
+                maxLengthInBlocks, maxLengthInBlocks,
+                maxBlocks, maxBlocksPerSecond,
+                8 /* blockWidth */, 8 /* blockHeight */,
+                1 /* widthAlignment */, 1 /* heightAlignment */);
+    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_AV1)) {
+        maxBlocksPerSecond = 829440;
+        maxBlocks = 36864;
+        maxBps = 200000;
+        int32_t maxDim = 512;
+
+        // Sample rate, Picture Size, Bit rate and luma dimension for AV1 Codec,
+        // corresponding to the definitions in
+        // "AV1 Bitstream & Decoding Process Specification", Annex A
+        // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
+        for (ProfileLevel profileLevel: mProfileLevels) {
+            int64_t SR = 0; // luma sample rate
+            int32_t FS = 0;  // luma picture size
+            int32_t BR = 0;  // bit rate kbps
+            int32_t D = 0;   // luma D
+            switch (profileLevel.mLevel) {
+                case AV1Level2:
+                    SR =     5529600; FS =   147456; BR =   1500; D =  2048; break;
+                case AV1Level21:
+                case AV1Level22:
+                case AV1Level23:
+                    SR =    10454400; FS =   278784; BR =   3000; D =  2816; break;
+
+                case AV1Level3:
+                    SR =    24969600; FS =   665856; BR =   6000; D =  4352; break;
+                case AV1Level31:
+                case AV1Level32:
+                case AV1Level33:
+                    SR =    39938400; FS =  1065024; BR =  10000; D =  5504; break;
+
+                case AV1Level4:
+                    SR =    77856768; FS =  2359296; BR =  12000; D =  6144; break;
+                case AV1Level41:
+                case AV1Level42:
+                case AV1Level43:
+                    SR =   155713536; FS =  2359296; BR =  20000; D =  6144; break;
+
+                case AV1Level5:
+                    SR =   273715200; FS =  8912896; BR =  30000; D =  8192; break;
+                case AV1Level51:
+                    SR =   547430400; FS =  8912896; BR =  40000; D =  8192; break;
+                case AV1Level52:
+                    SR =  1094860800; FS =  8912896; BR =  60000; D =  8192; break;
+                case AV1Level53:
+                    SR =  1176502272; FS =  8912896; BR =  60000; D =  8192; break;
+
+                case AV1Level6:
+                    SR =  1176502272; FS = 35651584; BR =  60000; D = 16384; break;
+                case AV1Level61:
+                    SR = 2189721600L; FS = 35651584; BR = 100000; D = 16384; break;
+                case AV1Level62:
+                    SR = 4379443200L; FS = 35651584; BR = 160000; D = 16384; break;
+                case AV1Level63:
+                    SR = 4706009088L; FS = 35651584; BR = 160000; D = 16384; break;
+
+                default:
+                    ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            switch (profileLevel.mProfile) {
+                case AV1ProfileMain8:
+                case AV1ProfileMain10:
+                case AV1ProfileMain10HDR10:
+                case AV1ProfileMain10HDR10Plus:
+                    break;
+                default:
+                    ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
+                    errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
+            }
+            errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
+            maxBlocksPerSecond = std::max(SR, maxBlocksPerSecond);
+            maxBlocks = std::max(FS, maxBlocks);
+            maxBps = std::max(BR * 1000, maxBps);
+            maxDim = std::max(D, maxDim);
+        }
+
+        const int32_t blockSize = 8;
+        int32_t maxLengthInBlocks = divUp(maxDim, blockSize);
+        maxBlocks = divUp(maxBlocks, blockSize * blockSize);
+        maxBlocksPerSecond = divUp(maxBlocksPerSecond, blockSize * (int64_t)blockSize);
+        applyMacroBlockLimits(
+                maxLengthInBlocks, maxLengthInBlocks,
+                maxBlocks, maxBlocksPerSecond,
+                blockSize, blockSize,
+                1 /* widthAlignment */, 1 /* heightAlignment */);
+    } else {
+        ALOGW("Unsupported mime %s", mediaType);
+        // using minimal bitrate here.  should be overridden by
+        // info from media_codecs.xml
+        maxBps = 64000;
+        errors |= ERROR_CAPABILITIES_UNSUPPORTED;
+    }
+    mBitrateRange = Range(1, maxBps);
+    mError |= errors;
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/media/libmedia/include/media/AudioCapabilities.h b/media/libmedia/include/media/AudioCapabilities.h
index d2bd9d7..3e1c9df 100644
--- a/media/libmedia/include/media/AudioCapabilities.h
+++ b/media/libmedia/include/media/AudioCapabilities.h
@@ -44,14 +44,14 @@
      * supports only discrete values. Otherwise, it returns an empty array.
      * The array is sorted in ascending order.
      */
-    const std::vector<int>& getSupportedSampleRates() const;
+    const std::vector<int32_t>& getSupportedSampleRates() const;
 
     /**
      * Returns the array of supported sample rate ranges.  The
      * array is sorted in ascending order, and the ranges are
      * distinct.
      */
-    const std::vector<Range<int>>& getSupportedSampleRateRanges() const;
+    const std::vector<Range<int32_t>>& getSupportedSampleRateRanges() const;
 
     /**
      * Returns the maximum number of input channels supported.
@@ -68,7 +68,7 @@
      * The {@link #getMaxInputChannelCount} method will return the highest value
      * in the ranges returned by {@link #getInputChannelCountRanges}
      */
-    int getMaxInputChannelCount() const;
+    int32_t getMaxInputChannelCount() const;
 
     /**
      * Returns the minimum number of input channels supported.
@@ -77,7 +77,7 @@
      * This returns the lowest channel count in the ranges returned by
      * {@link #getInputChannelCountRanges}.
      */
-    int getMinInputChannelCount() const;
+    int32_t getMinInputChannelCount() const;
 
     /**
      * Returns an array of ranges representing the number of input channels supported.
@@ -89,12 +89,12 @@
      *
      * The returned array cannot be empty.
      */
-    const std::vector<Range<int>>& getInputChannelCountRanges() const;
+    const std::vector<Range<int32_t>>& getInputChannelCountRanges() const;
 
     /**
      * Query whether the sample rate is supported by the codec.
      */
-    bool isSampleRateSupported(int sampleRate);
+    bool isSampleRateSupported(int32_t sampleRate);
 
     /* For internal use only. Not exposed as a public API */
     void getDefaultFormat(sp<AMessage> &format);
@@ -103,7 +103,7 @@
     bool supportsFormat(const sp<AMessage> &format);
 
 private:
-    static constexpr int MAX_INPUT_CHANNEL_COUNT = 30;
+    static constexpr int32_t MAX_INPUT_CHANNEL_COUNT = 30;
     static constexpr uint32_t MAX_NUM_CHANNELS = FCC_LIMIT;
 
     int mError;
@@ -112,21 +112,21 @@
 
     Range<int32_t> mBitrateRange;
 
-    std::vector<int> mSampleRates;
-    std::vector<Range<int>> mSampleRateRanges;
-    std::vector<Range<int>> mInputChannelRanges;
+    std::vector<int32_t> mSampleRates;
+    std::vector<Range<int32_t>> mSampleRateRanges;
+    std::vector<Range<int32_t>> mInputChannelRanges;
 
     /* no public constructor */
     AudioCapabilities() {}
     void init(std::string mediaType, std::vector<ProfileLevel> profLevs,
             const sp<AMessage> &format);
     void initWithPlatformLimits();
-    bool supports(std::optional<int> sampleRate, std::optional<int> inputChannels);
-    void limitSampleRates(std::vector<int> rates);
+    bool supports(std::optional<int32_t> sampleRate, std::optional<int32_t> inputChannels);
+    void limitSampleRates(std::vector<int32_t> rates);
     void createDiscreteSampleRates();
-    void limitSampleRates(std::vector<Range<int>> rateRanges);
+    void limitSampleRates(std::vector<Range<int32_t>> rateRanges);
     void applyLevelLimits();
-    void applyLimits(const std::vector<Range<int>> &inputChannels,
+    void applyLimits(const std::vector<Range<int32_t>> &inputChannels,
             const std::optional<Range<int32_t>> &bitRates);
     void parseFromInfo(const sp<AMessage> &format);
 
diff --git a/media/libmedia/include/media/CodecCapabilities.h b/media/libmedia/include/media/CodecCapabilities.h
index 570c8b5..0611d8c 100644
--- a/media/libmedia/include/media/CodecCapabilities.h
+++ b/media/libmedia/include/media/CodecCapabilities.h
@@ -20,6 +20,8 @@
 
 #include <media/AudioCapabilities.h>
 #include <media/CodecCapabilitiesUtils.h>
+#include <media/EncoderCapabilities.h>
+#include <media/VideoCapabilities.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
@@ -38,6 +40,26 @@
             const sp<AMessage> &format);
 
     /**
+     * Retrieve the codec capabilities for a certain {@code mime type}, {@code
+     * profile} and {@code level}.  If the type, or profile-level combination
+     * is not understood by the framework, it returns null.
+     * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this
+     * method without calling any method of the {@link MediaCodecList} class beforehand
+     * results in a {@link NullPointerException}.</p>
+     */
+    static std::shared_ptr<CodecCapabilities> CreateFromProfileLevel(std::string mediaType,
+                int32_t profile, int32_t level, int32_t maxConcurrentInstances = -1);
+
+    CodecCapabilities() {};
+
+    /**
+     * Init CodecCapabilities with settings.
+     */
+    void init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts, bool encoder,
+            sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo,
+            int32_t maxConcurrentInstances = 0);
+
+    /**
      * Returns the media type for which this codec-capability object was created.
      */
     const std::string& getMediaType();
@@ -47,11 +69,209 @@
      */
     const std::vector<ProfileLevel>& getProfileLevels();
 
+    /**
+     * Returns the supported color formats.
+     */
+    std::vector<uint32_t> getColorFormats() const;
+
+    /**
+     * Returns a media format with default values for configurations that have defaults.
+     */
+    sp<AMessage> getDefaultFormat() const;
+
+    /**
+     * Returns the max number of the supported concurrent codec instances.
+     * <p>
+     * This is a hint for an upper bound. Applications should not expect to successfully
+     * operate more instances than the returned value, but the actual number of
+     * concurrently operable instances may be less as it depends on the available
+     * resources at time of use.
+     */
+    int32_t getMaxSupportedInstances() const;
+
+    /**
+     * Returns the audio capabilities or {@code null} if this is not an audio codec.
+     */
+    std::shared_ptr<AudioCapabilities> getAudioCapabilities() const;
+
+    /**
+     * Returns the video capabilities or {@code null} if this is not a video codec.
+     */
+    std::shared_ptr<VideoCapabilities> getVideoCapabilities() const;
+
+    /**
+     * Returns the encoding capabilities or {@code null} if this is not an encoder.
+     */
+    std::shared_ptr<EncoderCapabilities> getEncoderCapabilities() const;
+
+    std::vector<std::string> validFeatures() const;
+
+    /**
+     * Query codec feature capabilities.
+     * <p>
+     * These features are supported to be used by the codec.  These
+     * include optional features that can be turned on, as well as
+     * features that are always on.
+     */
+    bool isFeatureSupported(const std::string &name) const;
+
+    /**
+     * Query codec feature requirements.
+     * <p>
+     * These features are required to be used by the codec, and as such,
+     * they are always turned on.
+     */
+    bool isFeatureRequired(const std::string &name) const;
+
+    bool isRegular() const;
+
+    /**
+    * Query whether codec supports a given {@link MediaFormat}.
+    *
+    * <p class=note>
+    * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
+    * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
+    * frame rate}. Use
+    * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
+    * to clear any existing frame rate setting in the format.
+    * <p>
+    *
+    * The following table summarizes the format keys considered by this method.
+    * This is especially important to consider when targeting a higher SDK version than the
+    * minimum SDK version, as this method will disregard some keys on devices below the target
+    * SDK version.
+    *
+    * <table style="width: 0%">
+    *  <thead>
+    *   <tr>
+    *    <th rowspan=3>OS Version(s)</th>
+    *    <td colspan=3>{@code MediaFormat} keys considered for</th>
+    *   </tr><tr>
+    *    <th>Audio Codecs</th>
+    *    <th>Video Codecs</th>
+    *    <th>Encoders</th>
+    *   </tr>
+    *  </thead>
+    *  <tbody>
+    *   <tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</td>
+    *    <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
+    *        {@link MediaFormat#KEY_SAMPLE_RATE},<br>
+    *        {@link MediaFormat#KEY_CHANNEL_COUNT},</td>
+    *    <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
+    *        {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br>
+    *        {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br>
+    *        {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br>
+    *        {@link MediaFormat#KEY_WIDTH},<br>
+    *        {@link MediaFormat#KEY_HEIGHT},<br>
+    *        <strong>no</strong> {@code KEY_FRAME_RATE}</td>
+    *    <td rowspan=10>as to the left, plus<br>
+    *        {@link MediaFormat#KEY_BITRATE_MODE},<br>
+    *        {@link MediaFormat#KEY_PROFILE}
+    *        (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br>
+    *        <!-- {link MediaFormat#KEY_QUALITY},<br> -->
+    *        {@link MediaFormat#KEY_COMPLEXITY}
+    *        (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</td>
+    *    <td rowspan=2>as above, plus<br>
+    *        {@link MediaFormat#KEY_FRAME_RATE}</td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#M}</td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#N}</td>
+    *    <td rowspan=2>as above, plus<br>
+    *        {@link MediaFormat#KEY_PROFILE},<br>
+    *        <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
+    *        {@link MediaFormat#KEY_BIT_RATE}</td>
+    *    <td rowspan=2>as above, plus<br>
+    *        {@link MediaFormat#KEY_PROFILE},<br>
+    *        {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br>
+    *        <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
+    *        {@link MediaFormat#KEY_BIT_RATE},<br>
+    *        {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#N_MR1}</td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#O}</td>
+    *    <td rowspan=3 colspan=2>as above, plus<br>
+    *        {@link CodecCapabilities#FEATURE_PartialFrame}<sup>D</sup></td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#O_MR1}</td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#P}</td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#Q}</td>
+    *    <td colspan=2>as above, plus<br>
+    *        {@link CodecCapabilities#FEATURE_FrameParsing}<sup>D</sup>,<br>
+    *        {@link CodecCapabilities#FEATURE_MultipleFrames},<br>
+    *        {@link CodecCapabilities#FEATURE_DynamicTimestamp}</td>
+    *   </tr><tr>
+    *    <td>{@link android.os.Build.VERSION_CODES#R}</td>
+    *    <td colspan=2>as above, plus<br>
+    *        {@link CodecCapabilities#FEATURE_LowLatency}<sup>D</sup></td>
+    *   </tr>
+    *   <tr>
+    *    <td colspan=4>
+    *     <p class=note><strong>Notes:</strong><br>
+    *      *: must be specified; otherwise, method returns {@code false}.<br>
+    *      +: method does not verify that the format parameters are supported
+    *      by the specified level.<br>
+    *      D: decoders only<br>
+    *      E: encoders only<br>
+    *      ~: if both keys are provided values must match
+    *    </td>
+    *   </tr>
+    *  </tbody>
+    * </table>
+    *
+    * @param format media format with optional feature directives.
+    * @return whether the codec capabilities support the given format
+    *         and feature requests.
+    */
+    bool isFormatSupported(const sp<AMessage> &format) const;
+
+    /**
+     * If the CodecCapabilities contains an AudioCapabilities.
+     *
+     * Not a public API to users.
+     */
+    bool isAudio() const;
+
+    /**
+     * If the CodecCapabilities contains a VideoCapabilities.
+     *
+     * Not a public API to users.
+     */
+    bool isVideo() const;
+
+    /**
+     * If the CodecCapabilities contains an EncoderCapabilities.
+     *
+     * Not a public API to users.
+     */
+    bool isEncoder() const;
+
 private:
     std::string mMediaType;
     std::vector<ProfileLevel> mProfileLevels;
+    std::vector<uint32_t> mColorFormats;
+    int32_t mMaxSupportedInstances;
+
+    sp<AMessage> mDefaultFormat;
+    sp<AMessage> mCapabilitiesInfo;
+
+    // Features
+    std::set<std::string> mFeaturesSupported;
+    std::set<std::string> mFeaturesRequired;
 
     std::shared_ptr<AudioCapabilities> mAudioCaps;
+    std::shared_ptr<VideoCapabilities> mVideoCaps;
+    std::shared_ptr<EncoderCapabilities> mEncoderCaps;
+
+    bool supportsProfileLevel(int32_t profile, int32_t level) const;
+    std::vector<Feature> getValidFeatures() const;
+    int32_t getErrors() const;
 };
 
 }  // namespace android
diff --git a/media/libmedia/include/media/CodecCapabilitiesUtils.h b/media/libmedia/include/media/CodecCapabilitiesUtils.h
index 89a452c..eb62bf9 100644
--- a/media/libmedia/include/media/CodecCapabilitiesUtils.h
+++ b/media/libmedia/include/media/CodecCapabilitiesUtils.h
@@ -19,8 +19,12 @@
 #define CODEC_CAPABILITIES__UTILS_H_
 
 #include <algorithm>
+#include <cerrno>
 #include <cmath>
+#include <cstdlib>
+#include <numeric>
 #include <optional>
+#include <regex>
 #include <string>
 #include <vector>
 
@@ -38,6 +42,21 @@
     }
 };
 
+struct Feature {
+    std::string mName;
+    int mValue;
+    bool mDefault;
+    bool mInternal;
+    Feature(std::string name, int value, bool def, bool internal) {
+        mName = name;
+        mValue = value;
+        mDefault = def;
+        mInternal = internal;
+    }
+    Feature(std::string name, int value, bool def) :
+        Feature(name, value, def, false /* internal */) {}
+};
+
 /**
  * Immutable class for describing the range of two numeric values.
  *
@@ -113,6 +132,74 @@
         return Range(std::max(lower_, lower), std::min(upper_, upper));
     }
 
+    /**
+     * Returns the smallest range that includes this range and
+     * another range.
+     *
+     * E.g. if a < b < c < d, the
+     * extension of [a, c] and [b, d] ranges is [a, d].
+     * As the endpoints are object references, there is no guarantee
+     * which specific endpoint reference is used from the input ranges:
+     *
+     * E.g. if a == a' < b < c, the
+     * extension of [a, b] and [a', c] ranges could be either
+     * [a, c] or ['a, c], where ['a, c] could be either the exact
+     * input range, or a newly created range with the same endpoints.
+     *
+     * @param range a non-null Range<T> reference
+     * @return the extension of this range and the other range.
+     */
+    Range<T> extend(Range<T> range) {
+        return Range<T>(std::min(lower_, range.lower_), std::max(upper_, range.upper_));
+    }
+
+    Range<T> align(T align) {
+        return this->intersect(
+                divUp(lower_, align) * align, (upper_ / align) * align);
+    }
+
+    Range<T> factor(T factor) {
+        if (factor == 1) {
+            return *this;
+        }
+        return Range(divUp(this->lower(), factor), this->upper() / factor);
+    }
+
+    // parse a string into a range
+    static std::optional<Range<T>> Parse(const std::string &str) {
+        if (str.empty()) {
+            ALOGW("could not parse empty integer range");
+            return std::nullopt;
+        }
+        long long lower, upper;
+        std::regex regex("^([0-9]+)-([0-9]+)$");
+        std::smatch match;
+        errno = 0;
+        if (std::regex_match(str, match, regex)) {
+            lower = std::strtoll(match[1].str().c_str(), NULL, 10);
+            upper = std::strtoll(match[2].str().c_str(), NULL, 10);
+        } else {
+            char *end;
+            lower = upper = std::strtoll(str.c_str(), &end, 10);
+            if (*end != '\0') {
+                ALOGW("could not parse integer range: %s", str.c_str());
+                return std::nullopt;
+            }
+        }
+
+        if (errno == ERANGE || lower < std::numeric_limits<T>::min()
+                || std::numeric_limits<T>::max() < upper || upper < lower) {
+            ALOGW("could not parse integer range: %s", str.c_str());
+            return std::nullopt;
+        }
+
+        return std::make_optional<Range<T>>((T)lower, (T)upper);
+    }
+
+    static Range<T> RangeFor(double v) {
+        return Range((T)v, (T)ceil(v));
+    }
+
 private:
     T lower_;
     T upper_;
@@ -125,7 +212,7 @@
 // found profile/level for which we don't have capability estimates
 constexpr int ERROR_CAPABILITIES_UNSUPPORTED    = (1 << 1);
 // have not found any profile/level for which we don't have capability estimate
-// constexpr int ERROR_NONE_SUPPORTED = (1 << 2);
+constexpr int ERROR_CAPABILITIES_NONE_SUPPORTED = (1 << 2);
 
 /**
  * Sorts distinct (non-intersecting) range array in ascending order.
@@ -176,8 +263,464 @@
     return result;
 }
 
-// parse string into int range
-std::optional<Range<int>> ParseIntRange(const std::string &str);
+/**
+ * Immutable class for describing width and height dimensions in pixels.
+ */
+struct VideoSize {
+    /**
+     * Create a new immutable VideoSize instance.
+     *
+     * @param width The width of the size, in pixels
+     * @param height The height of the size, in pixels
+     */
+    VideoSize(int32_t width, int32_t height);
+
+    // default constructor
+    VideoSize();
+
+    /**
+     * Get the width of the size (in pixels).
+     * @return width
+     */
+    int32_t getWidth() const;
+
+    /**
+     * Get the height of the size (in pixels).
+     * @return height
+     */
+    int32_t getHeight() const;
+
+    /**
+     * Check if this size is equal to another size.
+     *
+     * Two sizes are equal if and only if both their widths and heights are
+     * equal.
+     *
+     * A size object is never equal to any other type of object.
+     *
+     * @return true if the objects were equal, false otherwise
+     */
+    bool equals(VideoSize other) const;
+
+    bool empty() const;
+
+    std::string toString() const;
+
+    /**
+     * Parses the specified string as a size value.
+     *
+     * The ASCII characters {@code \}{@code u002a} ('*') and
+     * {@code \}{@code u0078} ('x') are recognized as separators between
+     * the width and height.
+     *
+     * For any {@code VideoSize s}: {@code VideoSize::ParseSize(s.toString()).equals(s)}.
+     * However, the method also handles sizes expressed in the
+     * following forms:
+     *
+     * "<i>width</i>{@code x}<i>height</i>" or
+     * "<i>width</i>{@code *}<i>height</i>" {@code => new VideoSize(width, height)},
+     * where <i>width</i> and <i>height</i> are string integers potentially
+     * containing a sign, such as "-10", "+7" or "5".
+     *
+     * <pre>{@code
+     * VideoSize::ParseSize("3*+6").equals(new VideoSize(3, 6)) == true
+     * VideoSize::ParseSize("-3x-6").equals(new VideoSize(-3, -6)) == true
+     * VideoSize::ParseSize("4 by 3") => throws NumberFormatException
+     * }</pre>
+     *
+     * @param string the string representation of a size value.
+     * @return the size value represented by {@code string}.
+     */
+    static std::optional<VideoSize> ParseSize(std::string str);
+
+    static std::optional<std::pair<VideoSize, VideoSize>> ParseSizeRange(const std::string str);
+
+    static Range<int32_t> GetAllowedDimensionRange();
+
+private:
+    int32_t mWidth;
+    int32_t mHeight;
+};
+
+// This is used for the std::map<VideoSize> in VideoCapabilities
+struct VideoSizeCompare {
+    bool operator() (const VideoSize& lhs, const VideoSize& rhs) const {
+        if (lhs.getWidth() == rhs.getWidth()) {
+            return lhs.getHeight() < rhs.getHeight();
+        } else {
+            return lhs.getWidth() < rhs.getWidth();
+        }
+    }
+};
+
+/**
+ * An immutable data type representation a rational number.
+ *
+ * Contains a pair of ints representing the numerator and denominator of a
+ * Rational number.
+ */
+struct Rational {
+    /**
+     * <p>Create a {@code Rational} with a given numerator and denominator.</p>
+     *
+     * <p>The signs of the numerator and the denominator may be flipped such that the denominator
+     * is always positive. Both the numerator and denominator will be converted to their reduced
+     * forms (see {@link #equals} for more details).</p>
+     *
+     * <p>For example,
+     * <ul>
+     * <li>a rational of {@code 2/4} will be reduced to {@code 1/2}.
+     * <li>a rational of {@code 1/-1} will be flipped to {@code -1/1}
+     * <li>a rational of {@code 5/0} will be reduced to {@code 1/0}
+     * <li>a rational of {@code 0/5} will be reduced to {@code 0/1}
+     * </ul>
+     * </p>
+     *
+     * @param numerator the numerator of the rational
+     * @param denominator the denominator of the rational
+     *
+     * @see #equals
+     */
+    Rational(int32_t numerator, int32_t denominator) {
+        if (denominator < 0) {
+            numerator = -numerator;
+            denominator = -denominator;
+        }
+
+        // Convert to reduced form
+        if (denominator == 0 && numerator > 0) {
+            mNumerator = 1; // +Inf
+            mDenominator = 0;
+        } else if (denominator == 0 && numerator < 0) {
+            mNumerator = -1; // -Inf
+            mDenominator = 0;
+        } else if (denominator == 0 && numerator == 0) {
+            mNumerator = 0; // NaN
+            mDenominator = 0;
+        } else if (numerator == 0) {
+            mNumerator = 0;
+            mDenominator = 1;
+        } else {
+            int gcd = std::gcd(numerator, denominator);
+
+            mNumerator = numerator / gcd;
+            mDenominator = denominator / gcd;
+        }
+    }
+
+    // default constructor;
+    Rational() {
+        Rational(0, 0);
+    }
+
+    /**
+     * Gets the numerator of the rational.
+     *
+     * <p>The numerator will always return {@code 1} if this rational represents
+     * infinity (that is, the denominator is {@code 0}).</p>
+     */
+    int32_t getNumerator() const {
+        return mNumerator;
+    }
+
+    /**
+     * Gets the denominator of the rational
+     *
+     * <p>The denominator may return {@code 0}, in which case the rational may represent
+     * positive infinity (if the numerator was positive), negative infinity (if the numerator
+     * was negative), or {@code NaN} (if the numerator was {@code 0}).</p>
+     *
+     * <p>The denominator will always return {@code 1} if the numerator is {@code 0}.
+     */
+    int32_t getDenominator() const {
+        return mDenominator;
+    }
+
+    /**
+     * Indicates whether this rational is a <em>Not-a-Number (NaN)</em> value.
+     *
+     * <p>A {@code NaN} value occurs when both the numerator and the denominator are {@code 0}.</p>
+     *
+     * @return {@code true} if this rational is a <em>Not-a-Number (NaN)</em> value;
+     *         {@code false} if this is a (potentially infinite) number value
+     */
+    bool isNaN() const {
+        return mDenominator == 0 && mNumerator == 0;
+    }
+
+    /**
+     * Indicates whether this rational represents an infinite value.
+     *
+     * <p>An infinite value occurs when the denominator is {@code 0} (but the numerator is not).</p>
+     *
+     * @return {@code true} if this rational is a (positive or negative) infinite value;
+     *         {@code false} if this is a finite number value (or {@code NaN})
+     */
+    bool isInfinite() const {
+        return mNumerator != 0 && mDenominator == 0;
+    }
+
+    /**
+     * Indicates whether this rational represents a finite value.
+     *
+     * <p>A finite value occurs when the denominator is not {@code 0}; in other words
+     * the rational is neither infinity or {@code NaN}.</p>
+     *
+     * @return {@code true} if this rational is a (positive or negative) infinite value;
+     *         {@code false} if this is a finite number value (or {@code NaN})
+     */
+    bool isFinite() const {
+        return mDenominator != 0;
+    }
+
+    /**
+     * Indicates whether this rational represents a zero value.
+     *
+     * <p>A zero value is a {@link #isFinite finite} rational with a numerator of {@code 0}.</p>
+     *
+     * @return {@code true} if this rational is finite zero value;
+     *         {@code false} otherwise
+     */
+    bool isZero() const {
+        return isFinite() && mNumerator == 0;
+    }
+
+    /**
+     * Return a string representation of this rational, e.g. {@code "1/2"}.
+     *
+     * <p>The following rules of conversion apply:
+     * <ul>
+     * <li>{@code NaN} values will return {@code "NaN"}
+     * <li>Positive infinity values will return {@code "Infinity"}
+     * <li>Negative infinity values will return {@code "-Infinity"}
+     * <li>All other values will return {@code "numerator/denominator"} where {@code numerator}
+     * and {@code denominator} are substituted with the appropriate numerator and denominator
+     * values.
+     * </ul></p>
+     */
+    std::string toString() const {
+        if (isNaN()) {
+            return "NaN";
+        } else if (isPosInf()) {
+            return "Infinity";
+        } else if (isNegInf()) {
+            return "-Infinity";
+        } else {
+            return std::to_string(mNumerator) + "/" + std::to_string(mDenominator);
+        }
+    }
+
+    /**
+     * Returns the value of the specified number as a {@code double}.
+     *
+     * <p>The {@code double} is calculated by converting both the numerator and denominator
+     * to a {@code double}; then returning the result of dividing the numerator by the
+     * denominator.</p>
+     *
+     * @return the divided value of the numerator and denominator as a {@code double}.
+     */
+    double asDouble() const {
+        double num = mNumerator;
+        double den = mDenominator;
+
+        return num / den;
+    }
+
+    /**
+     * Returns the value of the specified number as a {@code float}.
+     *
+     * <p>The {@code float} is calculated by converting both the numerator and denominator
+     * to a {@code float}; then returning the result of dividing the numerator by the
+     * denominator.</p>
+     *
+     * @return the divided value of the numerator and denominator as a {@code float}.
+     */
+    float asfloat() const {
+        float num = mNumerator;
+        float den = mDenominator;
+
+        return num / den;
+    }
+
+    /**
+     * Returns the value of the specified number as a {@code int}.
+     *
+     * <p>{@link #isInfinite Finite} rationals are converted to an {@code int} value
+     * by dividing the numerator by the denominator; conversion for non-finite values happens
+     * identically to casting a floating point value to an {@code int}, in particular:
+     *
+     * @return the divided value of the numerator and denominator as a {@code int}.
+     */
+    int32_t asInt32() const {
+        // Mimic float to int conversion rules from JLS 5.1.3
+
+        if (isPosInf()) {
+            return INT32_MAX;
+        } else if (isNegInf()) {
+            return INT32_MIN;
+        } else if (isNaN()) {
+            return 0;
+        } else { // finite
+            return mNumerator / mDenominator;
+        }
+    }
+
+    /**
+     * Returns the value of the specified number as a {@code long}.
+     *
+     * <p>{@link #isInfinite Finite} rationals are converted to an {@code long} value
+     * by dividing the numerator by the denominator; conversion for non-finite values happens
+     * identically to casting a floating point value to a {@code long}, in particular:
+     *
+     * @return the divided value of the numerator and denominator as a {@code long}.
+     */
+    int64_t asInt64() const {
+        // Mimic float to long conversion rules from JLS 5.1.3
+
+        if (isPosInf()) {
+            return INT64_MAX;
+        } else if (isNegInf()) {
+            return INT64_MIN;
+        } else if (isNaN()) {
+            return 0;
+        } else { // finite
+            return mNumerator / mDenominator;
+        }
+    }
+
+    /**
+     * Returns the value of the specified number as a {@code short}.
+     *
+     * <p>{@link #isInfinite Finite} rationals are converted to a {@code short} value
+     * identically to {@link #intValue}; the {@code int} result is then truncated to a
+     * {@code short} before returning the value.</p>
+     *
+     * @return the divided value of the numerator and denominator as a {@code short}.
+     */
+    int16_t asInt16() const {
+        return (int16_t) asInt32();
+    }
+
+    /**
+     * Compare this rational to the specified rational to determine their natural order.
+     *
+     * Nan is considered to be equal to itself and greater than all other
+     * Rational values. Otherwise, if the objects are not equal, then
+     * the following rules apply:
+     *
+     * Positive infinity is greater than any other finite number (or negative infinity)
+     * Negative infinity is less than any other finite number (or positive infinity)
+     * The finite number represented by this rational is checked numerically
+     * against the other finite number by converting both rationals to a common denominator multiple
+     * and comparing their numerators.
+     *
+     * @param another the rational to be compared
+     *
+     * @return a negative integer, zero, or a positive integer as this object is less than,
+     *         equal to, or greater than the specified rational.
+     */
+    // bool operator> (const Rational& another) {
+    int compareTo(Rational another) const {
+        if (equals(another)) {
+            return 0;
+        } else if (isNaN()) { // NaN is greater than the other non-NaN value
+            return 1;
+        } else if (another.isNaN()) { // the other NaN is greater than this non-NaN value
+            return -1;
+        } else if (isPosInf() || another.isNegInf()) {
+            return 1; // positive infinity is greater than any non-NaN/non-posInf value
+        } else if (isNegInf() || another.isPosInf()) {
+            return -1; // negative infinity is less than any non-NaN/non-negInf value
+        }
+
+        // else both this and another are finite numbers
+
+        // make the denominators the same, then compare numerators. int64_t to avoid overflow
+        int64_t thisNumerator = ((int64_t)mNumerator) * another.mDenominator;
+        int64_t otherNumerator = ((int64_t)another.mNumerator) * mDenominator;
+
+        // avoid underflow from subtraction by doing comparisons
+        if (thisNumerator < otherNumerator) {
+            return -1;
+        } else if (thisNumerator > otherNumerator) {
+            return 1;
+        } else {
+            // This should be covered by #equals, but have this code path just in case
+            return 0;
+        }
+    }
+
+    bool operator > (const Rational& another) const {
+        return compareTo(another) > 0;
+    }
+
+    bool operator >= (const Rational& another) const {
+        return compareTo(another) >= 0;
+    }
+
+    bool operator < (const Rational& another) const {
+        return compareTo(another) < 0;
+    }
+
+    bool operator <= (const Rational& another) const {
+        return compareTo(another) <= 0;
+    }
+
+    bool operator == (const Rational& another) const {
+        return equals(another);
+    }
+
+    static std::optional<Range<Rational>> ParseRange(const std::string str);
+
+    static Range<Rational> ScaleRange(Range<Rational> range, int32_t num, int32_t den);
+
+private:
+    int32_t mNumerator;
+    int32_t mDenominator;
+
+    bool isPosInf() const {
+        return mDenominator == 0 && mNumerator > 0;
+    }
+
+    bool isNegInf() const {
+        return mDenominator == 0 && mNumerator < 0;
+    }
+
+    bool equals(Rational other) const {
+        return (mNumerator == other.mNumerator && mDenominator == other.mDenominator);
+    }
+
+    Rational scale(int32_t num, int32_t den);
+
+    /**
+     * Parses the specified string as a rational value.
+     * The ASCII characters {@code \}{@code u003a} (':') and
+     * {@code \}{@code u002f} ('/') are recognized as separators between
+     * the numerator and denominator.
+     *
+     * For any {@code Rational r}: {@code Rational::parseRational(r.toString()).equals(r)}.
+     * However, the method also handles rational numbers expressed in the
+     * following forms:
+     *
+     * "<i>num</i>{@code /}<i>den</i>" or
+     * "<i>num</i>{@code :}<i>den</i>" {@code => new Rational(num, den);},
+     * where <i>num</i> and <i>den</i> are string integers potentially
+     * containing a sign, such as "-10", "+7" or "5".
+     *
+     * Rational::Parse("3:+6").equals(new Rational(1, 2)) == true
+     * Rational::Parse("-3/-6").equals(new Rational(1, 2)) == true
+     * Rational::Parse("4.56") => return std::nullopt
+     *
+     * @param str the string representation of a rational value.
+     * @return the rational value wrapped by std::optional represented by str.
+     */
+    static std::optional<Rational> Parse(std::string str);
+};
+
+static const Rational NaN = Rational(0, 0);
+static const Rational POSITIVE_INFINITY = Rational(1, 0);
+static const Rational NEGATIVE_INFINITY = Rational(-1, 0);
+static const Rational ZERO = Rational(0, 1);
 
 }  // namespace android
 
diff --git a/media/libmedia/include/media/EncoderCapabilities.h b/media/libmedia/include/media/EncoderCapabilities.h
new file mode 100644
index 0000000..a9654bb
--- /dev/null
+++ b/media/libmedia/include/media/EncoderCapabilities.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ENCODER_CAPABILITIES_H_
+
+#define ENCODER_CAPABILITIES_H_
+
+#include <media/CodecCapabilitiesUtils.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+/**
+ * A class that supports querying the encoding capabilities of a codec.
+ */
+struct EncoderCapabilities {
+    /**
+    * Returns the supported range of quality values.
+    *
+    * Quality is implementation-specific. As a general rule, a higher quality
+    * setting results in a better image quality and a lower compression ratio.
+    */
+    const Range<int>& getQualityRange();
+
+    /**
+     * Returns the supported range of encoder complexity values.
+     * <p>
+     * Some codecs may support multiple complexity levels, where higher
+     * complexity values use more encoder tools (e.g. perform more
+     * intensive calculations) to improve the quality or the compression
+     * ratio.  Use a lower value to save power and/or time.
+     */
+    const Range<int>& getComplexityRange();
+
+    /** Constant quality mode */
+    inline static constexpr int BITRATE_MODE_CQ = 0;
+    /** Variable bitrate mode */
+    inline static constexpr int BITRATE_MODE_VBR = 1;
+    /** Constant bitrate mode */
+    inline static constexpr int BITRATE_MODE_CBR = 2;
+    /** Constant bitrate mode with frame drops */
+    inline static constexpr int BITRATE_MODE_CBR_FD =  3;
+
+    /**
+     * Query whether a bitrate mode is supported.
+     */
+    bool isBitrateModeSupported(int mode);
+
+    /** @hide */
+    static std::shared_ptr<EncoderCapabilities> Create(std::string mediaType,
+            std::vector<ProfileLevel> profLevs, const sp<AMessage> &format);
+
+    /** @hide */
+    void getDefaultFormat(sp<AMessage> &format);
+
+    /** @hide */
+    bool supportsFormat(const sp<AMessage> &format);
+
+private:
+    inline static const Feature sBitrateModes[] = {
+        Feature("VBR", BITRATE_MODE_VBR, true),
+        Feature("CBR", BITRATE_MODE_CBR, false),
+        Feature("CQ",  BITRATE_MODE_CQ,  false),
+        Feature("CBR-FD", BITRATE_MODE_CBR_FD, false)
+    };
+    static int ParseBitrateMode(std::string mode);
+
+    std::string mMediaType;
+    std::vector<ProfileLevel> mProfileLevels;
+
+    Range<int> mQualityRange;
+    Range<int> mComplexityRange;
+    int mBitControl;
+    int mDefaultComplexity;
+    int mDefaultQuality;
+    std::string mQualityScale;
+
+    /* no public constructor */
+    EncoderCapabilities() {}
+    void init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+            const sp<AMessage> &format);
+    void applyLevelLimits();
+    void parseFromInfo(const sp<AMessage> &format);
+    bool supports(std::optional<int> complexity, std::optional<int> quality,
+            std::optional<int> profile);
+};
+
+}  // namespace android
+
+#endif // ENCODER_CAPABILITIES_H_
\ No newline at end of file
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/libmedia/include/media/VideoCapabilities.h b/media/libmedia/include/media/VideoCapabilities.h
new file mode 100644
index 0000000..5671375
--- /dev/null
+++ b/media/libmedia/include/media/VideoCapabilities.h
@@ -0,0 +1,457 @@
+/*
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIDEO_CAPABILITIES_H_
+
+#define VIDEO_CAPABILITIES_H_
+
+#include <media/CodecCapabilitiesUtils.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct VideoCapabilities {
+    struct PerformancePoint {
+        /**
+         * Maximum number of macroblocks in the frame.
+         *
+         * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks.
+         * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance
+         * is characterized using such blocks.
+         *
+         * Test API
+         */
+        int32_t getMaxMacroBlocks() const;
+
+        /**
+         * Return the width.
+         *
+         * For internal use only.
+         */
+        int32_t getWidth() const;
+
+        /**
+         * Return the height.
+         *
+         * For internal use only.
+         */
+        int32_t getHeight() const;
+
+        /**
+         * Maximum frame rate in frames per second.
+         *
+         * Test API
+         */
+        int32_t getMaxFrameRate() const;
+
+        /**
+         * Maximum number of macroblocks processed per second.
+         *
+         * Test API
+         */
+        int64_t getMaxMacroBlockRate() const;
+
+        /**
+         * Return the block size.
+         *
+         * For internal use only.
+         */
+        VideoSize getBlockSize() const;
+
+        /**
+         * convert to a debug string
+         *
+         * Be careful about the serializable compatibility across API revisions.
+         */
+        std::string toString() const;
+
+        /**
+         * Create a detailed performance point with custom max frame rate and macroblock size.
+         *
+         * @param width  frame width in pixels
+         * @param height frame height in pixels
+         * @param frameRate frames per second for frame width and height
+         * @param maxFrameRate maximum frames per second for any frame size
+         * @param blockSize block size for codec implementation. Must be powers of two in both
+         *        width and height.
+         *
+         * Test API
+         */
+        PerformancePoint(int32_t width, int32_t height, int32_t frameRate, int32_t maxFrameRate,
+                VideoSize blockSize);
+
+        /**
+         * Create a detailed performance point with custom max frame rate and macroblock size.
+         *
+         * @param width  frame width in pixels
+         * @param height frame height in pixels
+         * @param maxFrameRate maximum frames per second for any frame size
+         * @param maxMacroBlockRate maximum number of macroblocks processed per second.
+         * @param blockSize block size for codec implementation. Must be powers of two in both
+         *        width and height.
+         *
+         * Test API
+         */
+        PerformancePoint(VideoSize blockSize, int32_t width, int32_t height, int maxFrameRate,
+                int64_t maxMacroBlockRate);
+
+        /**
+         * Convert a performance point to a larger blocksize.
+         *
+         * @param pp performance point. NonNull
+         * @param blockSize block size for codec implementation. NonNull.
+         *
+         * Test API
+         */
+        PerformancePoint(const PerformancePoint &pp, VideoSize newBlockSize);
+
+        /**
+         * Create a performance point for a given frame size and frame rate.
+         *
+         * @param width width of the frame in pixels
+         * @param height height of the frame in pixels
+         * @param frameRate frame rate in frames per second
+         */
+        PerformancePoint(int32_t width, int32_t height, int32_t frameRate);
+
+        /**
+         * Checks whether the performance point covers a media format.
+         *
+         * @param format Stream format considered
+         *
+         * @return {@code true} if the performance point covers the format.
+         */
+        bool covers(const sp<AMessage> &format) const;
+
+        /**
+         * Checks whether the performance point covers another performance point. Use this
+         * method to determine if a performance point advertised by a codec covers the
+         * performance point required. This method can also be used for loose ordering as this
+         * method is transitive.
+         *
+         * @param other other performance point considered
+         *
+         * @return {@code true} if the performance point covers the other.
+         */
+        bool covers(const PerformancePoint &other) const;
+
+        /**
+         * Check if two PerformancePoint instances are equal.
+         *
+         * @param other other PerformancePoint instance for comparison.
+         *
+         * @return true if two PerformancePoint are equal.
+         */
+        bool equals(const PerformancePoint &other) const;
+
+    private:
+        VideoSize mBlockSize; // codec block size in macroblocks
+        int32_t mWidth; // width in macroblocks
+        int32_t mHeight; // height in macroblocks
+        int32_t mMaxFrameRate; // max frames per second
+        int64_t mMaxMacroBlockRate; // max macro block rate
+
+        void init(int32_t width, int32_t height, int32_t frameRate, int32_t maxFrameRate,
+                VideoSize blockSize);
+
+        /** Saturates a 64 bit integer value to a 32 bit integer */
+        int32_t saturateInt64ToInt32(int64_t value) const;
+
+        /** This method may overflow */
+        int32_t align(int32_t value, int32_t alignment) const;
+
+        /** @return NonNull */
+        VideoSize getCommonBlockSize(const PerformancePoint &other) const;
+    };
+
+    /**
+     * Find the equivalent VP9 profile level.
+     *
+     * Not a public API to developers.
+     */
+    static int32_t EquivalentVP9Level(const sp<AMessage> &format);
+
+    /**
+     * Returns the range of supported bitrates in bits/second.
+     */
+    const Range<int32_t>& getBitrateRange() const;
+
+    /**
+     * Returns the range of supported video widths.
+     * 32-bit processes will not support resolutions larger than 4096x4096 due to
+     * the limited address space.
+     */
+    const Range<int32_t>& getSupportedWidths() const;
+
+    /**
+     * Returns the range of supported video heights.
+     * 32-bit processes will not support resolutions larger than 4096x4096 due to
+     * the limited address space.
+     */
+    const Range<int32_t>& getSupportedHeights() const;
+
+    /**
+     * Returns the alignment requirement for video width (in pixels).
+     *
+     * This is a power-of-2 value that video width must be a
+     * multiple of.
+     */
+    int32_t getWidthAlignment() const;
+
+    /**
+     * Returns the alignment requirement for video height (in pixels).
+     *
+     * This is a power-of-2 value that video height must be a
+     * multiple of.
+     */
+    int32_t getHeightAlignment() const;
+
+    /**
+     * Return the upper limit on the smaller dimension of width or height.
+     *
+     * Some codecs have a limit on the smaller dimension, whether it be
+     * the width or the height.  E.g. a codec may only be able to handle
+     * up to 1920x1080 both in landscape and portrait mode (1080x1920).
+     * In this case the maximum width and height are both 1920, but the
+     * smaller dimension limit will be 1080. For other codecs, this is
+     * {@code Math.min(getSupportedWidths().getUpper(),
+     * getSupportedHeights().getUpper())}.
+     */
+    int32_t getSmallerDimensionUpperLimit() const;
+
+    /**
+     * Returns the range of supported frame rates.
+     *
+     * This is not a performance indicator.  Rather, it expresses the
+     * limits specified in the coding standard, based on the complexities
+     * of encoding material for later playback at a certain frame rate,
+     * or the decoding of such material in non-realtime.
+     */
+    const Range<int32_t>& getSupportedFrameRates() const;
+
+    /**
+     * Returns the range of supported video widths for a video height.
+     * @param height the height of the video
+     */
+    std::optional<Range<int32_t>> getSupportedWidthsFor(int32_t height) const;
+
+    /**
+     * Returns the range of supported video heights for a video width
+     * @param width the width of the video
+     */
+    std::optional<Range<int32_t>> getSupportedHeightsFor(int32_t width) const;
+
+    /**
+     * Returns the range of supported video frame rates for a video size.
+     *
+     * This is not a performance indicator.  Rather, it expresses the limits specified in
+     * the coding standard, based on the complexities of encoding material of a given
+     * size for later playback at a certain frame rate, or the decoding of such material
+     * in non-realtime.
+
+     * @param width the width of the video
+     * @param height the height of the video
+     */
+    std::optional<Range<double>> getSupportedFrameRatesFor(int32_t width, int32_t height) const;
+
+    /**
+     * Returns the range of achievable video frame rates for a video size.
+     * May return {@code null}, if the codec did not publish any measurement
+     * data.
+     * <p>
+     * This is a performance estimate provided by the device manufacturer based on statistical
+     * sampling of full-speed decoding and encoding measurements in various configurations
+     * of common video sizes supported by the codec. As such it should only be used to
+     * compare individual codecs on the device. The value is not suitable for comparing
+     * different devices or even different android releases for the same device.
+     * <p>
+     * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range
+     * corresponds to the fastest frame rates achieved in the tested configurations. As
+     * such, it should not be used to gauge guaranteed or even average codec performance
+     * on the device.
+     * <p>
+     * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range
+     * corresponds closer to sustained performance <em>in tested configurations</em>.
+     * One can expect to achieve sustained performance higher than the lower limit more than
+     * 50% of the time, and higher than half of the lower limit at least 90% of the time
+     * <em>in tested configurations</em>.
+     * Conversely, one can expect performance lower than twice the upper limit at least
+     * 90% of the time.
+     * <p class=note>
+     * Tested configurations use a single active codec. For use cases where multiple
+     * codecs are active, applications can expect lower and in most cases significantly lower
+     * performance.
+     * <p class=note>
+     * The returned range value is interpolated from the nearest frame size(s) tested.
+     * Codec performance is severely impacted by other activity on the device as well
+     * as environmental factors (such as battery level, temperature or power source), and can
+     * vary significantly even in a steady environment.
+     * <p class=note>
+     * Use this method in cases where only codec performance matters, e.g. to evaluate if
+     * a codec has any chance of meeting a performance target. Codecs are listed
+     * in {@link MediaCodecList} in the preferred order as defined by the device
+     * manufacturer. As such, applications should use the first suitable codec in the
+     * list to achieve the best balance between power use and performance.
+     *
+     * @param width the width of the video
+     * @param height the height of the video
+     */
+    std::optional<Range<double>> getAchievableFrameRatesFor(int32_t width, int32_t height) const;
+
+    /**
+     * Returns the supported performance points. May return {@code null} if the codec did not
+     * publish any performance point information (e.g. the vendor codecs have not been updated
+     * to the latest android release). May return an empty list if the codec published that
+     * if does not guarantee any performance points.
+     * <p>
+     * This is a performance guarantee provided by the device manufacturer for hardware codecs
+     * based on hardware capabilities of the device.
+     * <p>
+     * The returned list is sorted first by decreasing number of pixels, then by decreasing
+     * width, and finally by decreasing frame rate.
+     * Performance points assume a single active codec. For use cases where multiple
+     * codecs are active, should use that highest pixel count, and add the frame rates of
+     * each individual codec.
+     * <p class=note>
+     * 32-bit processes will not support resolutions larger than 4096x4096 due to
+     * the limited address space, but performance points will be presented as is.
+     * In other words, even though a component publishes a performance point for
+     * a resolution higher than 4096x4096, it does not mean that the resolution is supported
+     * for 32-bit processes.
+     */
+    const std::vector<PerformancePoint>& getSupportedPerformancePoints() const;
+
+    /**
+     * Returns whether a given video size ({@code width} and
+     * {@code height}) and {@code frameRate} combination is supported.
+     */
+    bool areSizeAndRateSupported(int32_t width, int32_t height, double frameRate) const;
+
+    /**
+     * Returns whether a given video size ({@code width} and
+     * {@code height}) is supported.
+     */
+    bool isSizeSupported(int32_t width, int32_t height) const;
+
+    /**
+     * Returns if a media format is supported.
+     *
+     * Not exposed to public
+     */
+    bool supportsFormat(const sp<AMessage> &format) const;
+
+    /**
+     * Create VideoCapabilities.
+     */
+    static std::shared_ptr<VideoCapabilities> Create(std::string mediaType,
+            std::vector<ProfileLevel> profLevs, const sp<AMessage> &format);
+
+    /**
+     * Get the block size.
+     *
+     * Not a public API to developers
+     */
+    VideoSize getBlockSize() const;
+
+    /**
+     * Get the block count range.
+     *
+     * Not a public API to developers
+     */
+    const Range<int32_t>& getBlockCountRange() const;
+
+    /**
+     * Get the blocks per second range.
+     *
+     * Not a public API to developers
+     */
+    const Range<int64_t>& getBlocksPerSecondRange() const;
+
+    /**
+     * Get the aspect ratio range.
+     *
+     * Not a public API to developers
+     */
+    Range<Rational> getAspectRatioRange(bool blocks) const;
+
+private:
+    std::string mMediaType;
+    std::vector<ProfileLevel> mProfileLevels;
+    int mError;
+
+    Range<int32_t> mBitrateRange;
+    Range<int32_t> mHeightRange;
+    Range<int32_t> mWidthRange;
+    Range<int32_t> mBlockCountRange;
+    Range<int32_t> mHorizontalBlockRange;
+    Range<int32_t> mVerticalBlockRange;
+    Range<Rational> mAspectRatioRange;
+    Range<Rational> mBlockAspectRatioRange;
+    Range<int64_t> mBlocksPerSecondRange;
+    std::map<VideoSize, Range<int64_t>, VideoSizeCompare> mMeasuredFrameRates;
+    std::vector<PerformancePoint> mPerformancePoints;
+    Range<int32_t> mFrameRateRange;
+
+    int32_t mBlockWidth;
+    int32_t mBlockHeight;
+    int32_t mWidthAlignment;
+    int32_t mHeightAlignment;
+    int mSmallerDimensionUpperLimit;
+
+    bool mAllowMbOverride; // allow XML to override calculated limits
+
+    int32_t getBlockCount(int32_t width, int32_t height) const;
+    std::optional<VideoSize> findClosestSize(int32_t width, int32_t height) const;
+    std::optional<Range<double>> estimateFrameRatesFor(int32_t width, int32_t height) const;
+    bool supports(std::optional<int32_t> width, std::optional<int32_t> height,
+                std::optional<double> rate) const;
+    /* no public constructor */
+    VideoCapabilities() {}
+    void init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+            const sp<AMessage> &format);
+    void initWithPlatformLimits();
+    std::vector<PerformancePoint> getPerformancePoints(const sp<AMessage> &format) const;
+    std::map<VideoSize, Range<int64_t>, VideoSizeCompare>
+            getMeasuredFrameRates(const sp<AMessage> &format) const;
+
+    static std::optional<std::pair<Range<int32_t>, Range<int32_t>>> ParseWidthHeightRanges(
+            const std::string &str);
+    void parseFromInfo(const sp<AMessage> &format);
+    void applyBlockLimits(int32_t blockWidth, int32_t blockHeight,
+            Range<int32_t> counts, Range<int64_t> rates, Range<Rational> ratios);
+    void applyAlignment(int32_t widthAlignment, int32_t heightAlignment);
+    void updateLimits();
+    void applyMacroBlockLimits(
+            int32_t maxHorizontalBlocks, int32_t maxVerticalBlocks,
+            int32_t maxBlocks, int64_t maxBlocksPerSecond,
+            int32_t blockWidth, int32_t blockHeight,
+            int32_t widthAlignment, int32_t heightAlignment);
+    void applyMacroBlockLimits(
+            int32_t minHorizontalBlocks, int32_t minVerticalBlocks,
+            int32_t maxHorizontalBlocks, int32_t maxVerticalBlocks,
+            int32_t maxBlocks, int64_t maxBlocksPerSecond,
+            int32_t blockWidth, int32_t blockHeight,
+            int32_t widthAlignment, int32_t heightAlignment);
+    void applyLevelLimits();
+
+    friend struct CodecCapabilities;
+};
+
+}  // namespace android
+
+#endif // VIDEO_CAPABILITIES_H_
\ No newline at end of file
diff --git a/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
index 02e43a4..e59d4d6 100644
--- a/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
+++ b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
@@ -72,15 +72,15 @@
 }
 
 TEST_F(AudioCapsAacTest, AudioCaps_Aac_InputChannelCount) {
-    int maxInputChannelCount = audioCaps->getMaxInputChannelCount();
+    int32_t maxInputChannelCount = audioCaps->getMaxInputChannelCount();
     EXPECT_EQ(maxInputChannelCount, 8);
-    int minInputChannelCount = audioCaps->getMinInputChannelCount();
+    int32_t minInputChannelCount = audioCaps->getMinInputChannelCount();
     EXPECT_EQ(minInputChannelCount, 1);
 }
 
 TEST_F(AudioCapsAacTest, AudioCaps_Aac_SupportedSampleRates) {
-    const std::vector<int>& sampleRates = audioCaps->getSupportedSampleRates();
-    EXPECT_EQ(sampleRates, std::vector<int>({7350, 8000, 11025, 12000, 16000, 22050,
+    const std::vector<int32_t>& sampleRates = audioCaps->getSupportedSampleRates();
+    EXPECT_EQ(sampleRates, std::vector<int32_t>({7350, 8000, 11025, 12000, 16000, 22050,
             24000, 32000, 44100, 48000}));
 
     EXPECT_FALSE(audioCaps->isSampleRateSupported(6000))
@@ -120,16 +120,16 @@
 }
 
 TEST_F(AudioCapsRawTest, AudioCaps_Raw_InputChannelCount) {
-    int maxInputChannelCount = audioCaps->getMaxInputChannelCount();
+    int32_t maxInputChannelCount = audioCaps->getMaxInputChannelCount();
     EXPECT_EQ(maxInputChannelCount, 12);
-    int minInputChannelCount = audioCaps->getMinInputChannelCount();
+    int32_t minInputChannelCount = audioCaps->getMinInputChannelCount();
     EXPECT_EQ(minInputChannelCount, 1);
 }
 
 TEST_F(AudioCapsRawTest, AudioCaps_Raw_InputChannelCountRanges) {
-    const std::vector<Range<int>>& inputChannelCountRanges
+    const std::vector<Range<int32_t>>& inputChannelCountRanges
             = audioCaps->getInputChannelCountRanges();
-    std::vector<Range<int>> expectedOutput({{1,1}, {2,2}, {3,3}, {4,4}, {5,5},
+    std::vector<Range<int32_t>> expectedOutput({{1,1}, {2,2}, {3,3}, {4,4}, {5,5},
             {6,6}, {7,7}, {8,8}, {9,9}, {10,10}, {11,11}, {12,12}});
     ASSERT_EQ(inputChannelCountRanges.size(), expectedOutput.size());
     for (int i = 0; i < inputChannelCountRanges.size(); i++) {
@@ -139,7 +139,7 @@
 }
 
 TEST_F(AudioCapsRawTest, AudioCaps_Raw_SupportedSampleRates) {
-    const std::vector<Range<int>>& sampleRateRanges = audioCaps->getSupportedSampleRateRanges();
+    const std::vector<Range<int32_t>>& sampleRateRanges = audioCaps->getSupportedSampleRateRanges();
     EXPECT_EQ(sampleRateRanges.size(), 1);
     EXPECT_EQ(sampleRateRanges.at(0).lower(), 8000);
     EXPECT_EQ(sampleRateRanges.at(0).upper(), 192000);
@@ -148,3 +148,226 @@
     EXPECT_EQ(audioCaps->isSampleRateSupported(10000), true);
     EXPECT_EQ(audioCaps->isSampleRateSupported(193000), false);
 }
+
+class VideoCapsHevcTest : public testing::Test {
+protected:
+    VideoCapsHevcTest() {
+        std::string mediaType = MIMETYPE_VIDEO_HEVC;
+
+        sp<AMessage> details = new AMessage;
+        details->setString("alignment", "2x2");
+        details->setString("bitrate-range", "1-120000000");
+        details->setString("block-count-range", "1-32640");
+        details->setString("block-size", "16x16");
+        details->setString("blocks-per-second-range", "1-3916800");
+        details->setInt32("feature-adaptive-playback", 0);
+        details->setInt32("feature-can-swap-width-height", 1);
+        details->setString("max-concurrent-instances", "16");
+        details->setString("measured-frame-rate-1280x720-range", "547-553");
+        details->setString("measured-frame-rate-1920x1080-range", "569-572");
+        details->setString("measured-frame-rate-352x288-range", "1150-1250");
+        details->setString("measured-frame-rate-3840x2160-range", "159-159");
+        details->setString("measured-frame-rate-640x360-range", "528-529");
+        details->setString("measured-frame-rate-720x480-range", "546-548");
+        details->setString("performance-point-1280x720-range", "240");
+        details->setString("performance-point-3840x2160-range", "120");
+        details->setString("size-range", "64x64-3840x2176");
+
+        std::vector<ProfileLevel> profileLevel{
+            ProfileLevel(1, 8388608),
+            ProfileLevel(2, 8388608),
+            ProfileLevel(4096, 8388608),
+            ProfileLevel(8192, 8388608),
+        };
+
+        videoCaps = VideoCapabilities::Create(mediaType, profileLevel, details);
+    }
+
+    std::shared_ptr<VideoCapabilities> videoCaps;
+};
+
+TEST_F(VideoCapsHevcTest, VideoCaps_HEVC_Alignment) {
+    int32_t widthAlignment = videoCaps->getWidthAlignment();
+    EXPECT_EQ(widthAlignment, 2);
+    int32_t heightAlignment = videoCaps->getHeightAlignment();
+    EXPECT_EQ(heightAlignment, 2);
+}
+
+TEST_F(VideoCapsHevcTest, VideoCaps_HEVC_BitrateRange) {
+    const Range<int32_t>& bitrateRange = videoCaps->getBitrateRange();
+    EXPECT_EQ(bitrateRange.lower(), 1);
+    EXPECT_EQ(bitrateRange.upper(), 120000000);
+}
+
+TEST_F(VideoCapsHevcTest, VideoCaps_HEVC_SupportedWidthsAndHeights) {
+    const Range<int32_t>& supportedWidths = videoCaps->getSupportedWidths();
+    EXPECT_EQ(supportedWidths.upper(), 3840);
+    const Range<int32_t>& supportedHeights = videoCaps->getSupportedHeights();
+    EXPECT_EQ(supportedHeights.upper(), 3840);
+}
+
+TEST_F(VideoCapsHevcTest, VideoCaps_HEVC_SupportedFrameRates) {
+    const Range<int32_t>& supportedFrameRates = videoCaps->getSupportedFrameRates();
+    EXPECT_EQ(supportedFrameRates.lower(), 0);
+    EXPECT_EQ(supportedFrameRates.upper(), 960);
+
+    std::optional<Range<double>> supportedFR720p = videoCaps->getSupportedFrameRatesFor(1280, 720);
+    EXPECT_EQ(supportedFR720p.value().upper(), 960.0);
+    std::optional<Range<double>> supportedFR1080p
+            = videoCaps->getSupportedFrameRatesFor(1920, 1080);
+    EXPECT_EQ(supportedFR1080p.value().upper(), 480.0);
+    std::optional<Range<double>> supportedFR4k = videoCaps->getSupportedFrameRatesFor(3840, 2160);
+    EXPECT_EQ(std::round(supportedFR4k.value().upper()), 121);
+}
+
+TEST_F(VideoCapsHevcTest, VideoCaps_HEVC_AchievableFrameRates) {
+    std::optional<Range<double>> achievableFR1080p
+            = videoCaps->getAchievableFrameRatesFor(1920, 1080);
+    ASSERT_NE(achievableFR1080p, std::nullopt) << "resolution not supported";
+    EXPECT_EQ(achievableFR1080p.value().lower(), 569);
+    EXPECT_EQ(achievableFR1080p.value().upper(), 572);
+}
+
+class EncoderCapsAacTest : public testing::Test {
+protected:
+    EncoderCapsAacTest() {
+        std::string mediaType = MIMETYPE_AUDIO_AAC;
+
+        sp<AMessage> details = new AMessage;
+        details->setString("bitrate-range", "8000-960000");
+        details->setString("max-channel-count", "6");
+        details->setString("sample-rate-ranges",
+                "8000,11025,12000,16000,22050,24000,32000,44100,48000");
+
+        std::vector<ProfileLevel> profileLevel{
+            ProfileLevel(2, 0),
+            ProfileLevel(5, 0),
+            ProfileLevel(29, 0),
+            ProfileLevel(23, 0),
+            ProfileLevel(39, 0),
+        };
+
+        encoderCaps = EncoderCapabilities::Create(mediaType, profileLevel, details);
+    }
+
+    std::shared_ptr<EncoderCapabilities> encoderCaps;
+};
+
+
+TEST_F(EncoderCapsAacTest, EncoderCaps_AAC_ComplexityRange) {
+    const Range<int>& complexityRange = encoderCaps->getComplexityRange();
+    EXPECT_EQ(complexityRange.lower(), 0);
+    EXPECT_EQ(complexityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsAacTest, EncoderCaps_AAC_QualityRange) {
+    const Range<int>& qualityRange = encoderCaps->getQualityRange();
+    EXPECT_EQ(qualityRange.lower(), 0);
+    EXPECT_EQ(qualityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsAacTest, EncoderCaps_AAC_SupportedBitrateMode) {
+    EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR));
+    EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_VBR));
+    EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CQ));
+    EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR_FD));
+}
+
+class EncoderCapsFlacTest : public testing::Test {
+protected:
+    EncoderCapsFlacTest() {
+        std::string mediaType = MIMETYPE_AUDIO_FLAC;
+
+        sp<AMessage> details = new AMessage;
+        details->setString("bitrate-range", "1-21000000");
+        details->setString("complexity-default", "5");
+        details->setString("complexity-range", "0-8");
+        details->setString("feature-bitrate-modes", "CQ");
+        details->setString("max-channel-count", "2");
+        details->setString("sample-rate-ranges", "1-655350");
+
+        std::vector<ProfileLevel> profileLevel;
+
+        encoderCaps = EncoderCapabilities::Create(mediaType, profileLevel, details);
+    }
+
+    std::shared_ptr<EncoderCapabilities> encoderCaps;
+};
+
+TEST_F(EncoderCapsFlacTest, EncoderCaps_FLAC_ComplexityRange) {
+    const Range<int>& complexityRange = encoderCaps->getComplexityRange();
+    EXPECT_EQ(complexityRange.lower(), 0);
+    EXPECT_EQ(complexityRange.upper(), 8);
+}
+
+TEST_F(EncoderCapsFlacTest, EncoderCaps_FLAC_QualityRange) {
+    const Range<int>& qualityRange = encoderCaps->getQualityRange();
+    EXPECT_EQ(qualityRange.lower(), 0);
+    EXPECT_EQ(qualityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsFlacTest, EncoderCaps_FLAC_SupportedBitrateMode) {
+    EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR));
+    EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_VBR));
+    EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CQ));
+    EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR_FD));
+}
+
+class EncoderCapsHevcTest : public testing::Test {
+protected:
+    EncoderCapsHevcTest() {
+        std::string mediaType = MIMETYPE_VIDEO_HEVC;
+
+        sp<AMessage> details = new AMessage;
+        details->setString("alignment", "2x2");
+        details->setString("bitrate-range", "1-120000000");
+        details->setString("block-count-range", "1-8160");
+        details->setString("block-size", "32x32");
+        details->setString("blocks-per-second-range", "1-979200");
+        details->setString("feature-bitrate-modes", "VBR,CBR,CQ,CBR-FD");
+        details->setInt32("feature-can-swap-width-height", 1);
+        details->setInt32("feature-qp-bounds", 0);
+        details->setInt32("feature-vq-minimum-quality", 0);
+        details->setString("max-concurrent-instances", "16");
+        details->setString("measured-frame-rate-1280x720-range", "154-198");
+        details->setString("measured-frame-rate-1920x1080-range", "46-97");
+        details->setString("measured-frame-rate-320x240-range", "371-553");
+        details->setString("measured-frame-rate-720x480-range", "214-305");
+        details->setString("performance-point-1280x720-range", "240");
+        details->setString("performance-point-3840x2160-range", "120");
+        details->setString("quality-default", "57");
+        details->setString("quality-range", "0-100");
+        details->setString("quality-scale", "linear");
+        details->setString("size-range", "64x64-3840x2176");
+
+        std::vector<ProfileLevel> profileLevel{
+            ProfileLevel(1, 2097152),
+            ProfileLevel(2, 2097152),
+            ProfileLevel(4096, 2097152),
+            ProfileLevel(8192, 2097152),
+        };
+
+        encoderCaps = EncoderCapabilities::Create(mediaType, profileLevel, details);
+    }
+
+    std::shared_ptr<EncoderCapabilities> encoderCaps;
+};
+
+TEST_F(EncoderCapsHevcTest, EncoderCaps_HEVC_ComplexityRange) {
+    const Range<int>& complexityRange = encoderCaps->getComplexityRange();
+    EXPECT_EQ(complexityRange.lower(), 0);
+    EXPECT_EQ(complexityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsHevcTest, EncoderCaps_HEVC_QualityRange) {
+    const Range<int>& qualityRange = encoderCaps->getQualityRange();
+    EXPECT_EQ(qualityRange.lower(), 0);
+    EXPECT_EQ(qualityRange.upper(), 100);
+}
+
+TEST_F(EncoderCapsHevcTest, EncoderCaps_HEVC_SupportedBitrateMode) {
+    EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR));
+    EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_VBR));
+    EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CQ));
+    EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR_FD));
+}
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index b466f18..92ac451 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -99,6 +99,7 @@
 
     static_libs: [
         "libstagefright_esds",
+        "android.media.extractor.flags-aconfig-cc",
     ],
 
     export_include_dirs: [
@@ -325,6 +326,7 @@
 
     static_libs: [
         "android.media.codec-aconfig-cc",
+        "android.media.extractor.flags-aconfig-cc",
         "com.android.media.flags.editing-aconfig-cc",
         "framework-permission-aidl-cpp",
         "libmedia_ndkformatpriv",
diff --git a/media/libstagefright/FrameCaptureLayer.cpp b/media/libstagefright/FrameCaptureLayer.cpp
index 4e71943..53e4d7d 100644
--- a/media/libstagefright/FrameCaptureLayer.cpp
+++ b/media/libstagefright/FrameCaptureLayer.cpp
@@ -242,8 +242,7 @@
     ALOGV("releaseBuffer");
     Mutex::Autolock _lock(mLock);
 
-    return mConsumer->releaseBuffer(bi.mSlot, bi.mFrameNumber,
-            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
+    return mConsumer->releaseBuffer(bi.mSlot, bi.mFrameNumber, bi.mFence);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index efbd682..f917aa2 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -755,8 +755,7 @@
                 // consume buffer
                 sp<IGraphicBufferConsumer> consumer = mConsumer.promote();
                 if (consumer != nullptr && consumer->acquireBuffer(&buffer, 0) == NO_ERROR) {
-                    consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber,
-                                            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, buffer.mFence);
+                    consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber, buffer.mFence);
                 }
             }
 
@@ -6093,9 +6092,9 @@
         }
         if (csd->size() == 0) {
             ALOGW("csd-%zu size is 0", i);
+        } else {
+            mCSD.push_back(csd);
         }
-
-        mCSD.push_back(csd);
         ++i;
     }
 
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index a3f55da..b640040 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -752,8 +752,7 @@
     status_t status = mInput->attachBuffer(&consumerSlot, oldBuffer);
     ALOGE_IF(status != NO_ERROR, "attaching buffer to input failed (%d)", status);
     if (status == NO_ERROR) {
-        status = mInput->releaseBuffer(consumerSlot, 0 /* frameNumber */,
-                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
+        status = mInput->releaseBuffer(consumerSlot, 0 /* frameNumber */, fence);
         ALOGE_IF(status != NO_ERROR, "releasing buffer to input failed (%d)", status);
     }
 
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/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 86741a6..50eeb62 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -44,6 +44,8 @@
 #include <media/AudioParameter.h>
 #include <system/audio.h>
 
+#include <com_android_media_extractor_flags.h>
+
 // TODO : Remove the defines once mainline media is built against NDK >= 31.
 // The mp4 extractor is part of mainline and builds against NDK 29 as of
 // writing. These keys are available only from NDK 31:
@@ -1443,6 +1445,17 @@
         buffer->meta()->setInt64("timeUs", 0);
         msg->setBuffer("csd-0", buffer);
         parseAV1ProfileLevelFromCsd(buffer, msg);
+    } else if (com::android::media::extractor::flags::extractor_mp4_enable_apv() &&
+               meta->findData(kKeyAPVC, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        if (buffer.get() == NULL || buffer->base() == NULL) {
+            return NO_MEMORY;
+        }
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
         if (esds.InitCheck() != (status_t)OK) {
@@ -2091,6 +2104,9 @@
         } else if (mime == MEDIA_MIMETYPE_VIDEO_AV1 ||
                    mime == MEDIA_MIMETYPE_IMAGE_AVIF) {
             meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+        } else if (com::android::media::extractor::flags::extractor_mp4_enable_apv() &&
+                   mime == MEDIA_MIMETYPE_VIDEO_APV) {
+            meta->setData(kKeyAPVC, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
             int32_t profile = -1;
             uint8_t blCompatibilityId = -1;
diff --git a/media/libstagefright/data/media_codecs_google_c2_video.xml b/media/libstagefright/data/media_codecs_google_c2_video.xml
index 72a2551..2fb2d59 100644
--- a/media/libstagefright/data/media_codecs_google_c2_video.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_video.xml
@@ -101,6 +101,7 @@
             <Limit name="bitrate" range="1-240000000"/>
             <Limit name="block-size" value="16x16" />
             <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
+            <Feature name="dynamic-color-aspects" />
             <Attribute name="software-codec"/>
          </MediaCodec>
     </Decoders>
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 20c97dc..c79ac5c 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -262,6 +262,7 @@
             <Limit name="block-size" value="16x16" />
             <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
             <Feature name="adaptive-playback" />
+            <Feature name="dynamic-color-aspects" />
             <Attribute name="software-codec"/>
         </MediaCodec>
     </Decoders>
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 8f2f162..b0f671d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -854,12 +854,17 @@
 }
 
 inline constexpr char FEATURE_AdaptivePlayback[]       = "adaptive-playback";
+inline constexpr char FEATURE_DynamicTimestamp[]       = "dynamic-timestamp";
 inline constexpr char FEATURE_EncodingStatistics[]     = "encoding-statistics";
+inline constexpr char FEATURE_FrameParsing[]           = "frame-parsing";
+inline constexpr char FEATURE_HdrEditing[]             = "hdr-editing";
 inline constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
+inline constexpr char FEATURE_LowLatency[]             = "low-latency";
 inline constexpr char FEATURE_MultipleFrames[] = "multiple-frames";
 inline constexpr char FEATURE_PartialFrame[] = "partial-frame";
 inline constexpr char FEATURE_QpBounds[] = "qp-bounds";
 inline constexpr char FEATURE_SecurePlayback[]         = "secure-playback";
+inline constexpr char FEATURE_SpecialCodec[]           = "special-codec";
 inline constexpr char FEATURE_TunneledPlayback[]       = "tunneled-playback";
 
 // from MediaFormat.java
diff --git a/media/module/bqhelper/GraphicBufferSource.cpp b/media/module/bqhelper/GraphicBufferSource.cpp
index 82ddbc0..c9082f2 100644
--- a/media/module/bqhelper/GraphicBufferSource.cpp
+++ b/media/module/bqhelper/GraphicBufferSource.cpp
@@ -996,9 +996,8 @@
                     // somehow need to propagate frame number to that queue
                     if (buffer->isCached()) {
                         --mNumOutstandingAcquires;
-                        mConsumer->releaseBuffer(
-                                buffer->getSlot(), frameNum, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
-                                buffer->getReleaseFence());
+                        mConsumer->releaseBuffer(buffer->getSlot(), frameNum,
+                                                 buffer->getReleaseFence());
                     }
                 },
                 bi.mFence);
diff --git a/media/module/foundation/include/media/stagefright/foundation/AUtils.h b/media/module/foundation/include/media/stagefright/foundation/AUtils.h
index 3b646dc..eb605a7 100644
--- a/media/module/foundation/include/media/stagefright/foundation/AUtils.h
+++ b/media/module/foundation/include/media/stagefright/foundation/AUtils.h
@@ -92,4 +92,13 @@
     return (err < (period / 2)) ? err : (period - err);
 }
 
+inline static bool IsPowerOfTwo(int32_t value) {
+    return (value & (value - 1)) == 0;
+}
+
+/** Checks if the value is a power of two and not zero. */
+inline static bool IsPowerOfTwoStrict(int32_t value) {
+    return value != 0 && (value & (value - 1)) == 0;
+}
+
 #endif  // A_UTILS_H_
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/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 995c674..889ddad 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -678,6 +678,28 @@
     }
 }
 
+media_status_t
+AImageReader::setUsage(uint64_t usage) {
+    Mutex::Autolock _l(mLock);
+    if (!mIsOpen || mBufferItemConsumer == nullptr) {
+        ALOGE("not ready to perform setUsage()");
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    if (mUsage == usage) {
+        return AMEDIA_OK;
+    }
+
+    uint64_t halUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
+    status_t ret = mBufferItemConsumer->setConsumerUsageBits(halUsage);
+    if (ret != OK) {
+        ALOGE("setConsumerUsageBits() failed %d", ret);
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+    mUsage = usage;
+    mHalUsage = halUsage;
+    return AMEDIA_OK;
+}
+
 static
 media_status_t validateParameters(int32_t width, int32_t height, int32_t format,
                                   uint64_t usage, int32_t maxImages,
@@ -935,3 +957,14 @@
     reader->setBufferRemovedListener(listener);
     return AMEDIA_OK;
 }
+
+EXPORT
+media_status_t AImageReader_setUsage(
+    AImageReader *reader, uint64_t usage) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr) {
+        ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return reader->setUsage(usage);
+}
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 985f42b..89a33f8 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -20,6 +20,7 @@
 #include <inttypes.h>
 
 #include <media/NdkImageReader.h>
+#include <media-vndk/VndkImageReader.h>
 
 #include <utils/List.h>
 #include <utils/Mutex.h>
@@ -68,6 +69,7 @@
 
     media_status_t setImageListener(AImageReader_ImageListener* listener);
     media_status_t setBufferRemovedListener(AImageReader_BufferRemovedListener* listener);
+    media_status_t setUsage(uint64_t usage);
 
     media_status_t acquireNextImage(/*out*/AImage** image, /*out*/int* fenceFd);
     media_status_t acquireLatestImage(/*out*/AImage** image, /*out*/int* fenceFd);
@@ -121,7 +123,7 @@
     const int32_t mWidth;
     const int32_t mHeight;
     int32_t mFormat;
-    const uint64_t mUsage;  // AHARDWAREBUFFER_USAGE_* flags.
+    uint64_t mUsage;  // AHARDWAREBUFFER_USAGE_* flags.
     const int32_t mMaxImages;
 
     // TODO(jwcai) Seems completely unused in AImageReader class.
diff --git a/media/ndk/include/media-vndk/VndkImageReader.h b/media/ndk/include/media-vndk/VndkImageReader.h
new file mode 100644
index 0000000..c67a38c
--- /dev/null
+++ b/media/ndk/include/media-vndk/VndkImageReader.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _VNDK_IMAGE_READER_H
+#define _VNDK_IMAGE_READER_H
+
+// vndk is a superset of the NDK
+#include <media/NdkImageReader.h>
+
+__BEGIN_DECLS
+
+/**
+ * Set the usage of this image reader.
+ *
+ * <p>Note that calling this method will replace the previously set usage.</p>
+ *
+ * <p>Note: This will trigger re-allocation, could cause producer failures mid-stream
+ * if the new usage combination isn't supported, and thus should be avoided as much as
+ * possible regardless.</p>
+ *
+ * Available since API level 36.
+ *
+ * @param reader The image reader of interest.
+ * @param usage specifies how the consumer will access the AImage.
+ *              See {@link AImageReader_newWithUsage} parameter description for more details.
+ * @return <ul>
+ *         <li>{@link AMEDIA_OK} if the method call succeeds.</li>
+ *         <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL.</li>
+ *         <li>{@link AMEDIA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
+ *
+ * @see AImage_getHardwareBuffer
+ */
+media_status_t AImageReader_setUsage(
+        AImageReader* _Nonnull reader, uint64_t usage) __INTRODUCED_IN(36);
+
+__END_DECLS
+
+#endif //_VNDK_IMAGE_READER_H
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 262c169..8fb203f 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -16,6 +16,7 @@
     AImageReader_newWithDataSpace; # introduced=UpsideDownCake
     AImageReader_setBufferRemovedListener; # introduced=26
     AImageReader_setImageListener; # introduced=24
+    AImageReader_setUsage; # introduced=36 llndk
     AImage_delete; # introduced=24
     AImage_deleteAsync; # introduced=26
     AImage_getCropRect; # introduced=24
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index ddb93fe..39a172f 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -77,15 +77,24 @@
     return packages[0];
 }
 
+// NOTE/TODO(b/379754682):
+// AUDIO_SOURCE_VOICE_DOWNLINK and AUDIO_SOURCE_VOICE_CALL are handled specially:
+// DOWNLINK is an output source, but we still require RecordOp in addition to
+// OP_RECORD_INCOMING_PHONE_AUDIO
+// CALL includes both uplink and downlink, but we attribute RECORD_OP (only), since
+// there is not support for noting multiple ops.
 int32_t getOpForSource(audio_source_t source) {
   switch (source) {
+    // BEGIN output sources
     case AUDIO_SOURCE_FM_TUNER:
         return AppOpsManager::OP_NONE;
     case AUDIO_SOURCE_ECHO_REFERENCE: // fallthrough
     case AUDIO_SOURCE_REMOTE_SUBMIX:
+        // TODO -- valid in all cases?
       return AppOpsManager::OP_RECORD_AUDIO_OUTPUT;
     case AUDIO_SOURCE_VOICE_DOWNLINK:
       return AppOpsManager::OP_RECORD_INCOMING_PHONE_AUDIO;
+    // END output sources
     case AUDIO_SOURCE_HOTWORD:
       return AppOpsManager::OP_RECORD_AUDIO_HOTWORD;
     case AUDIO_SOURCE_DEFAULT:
@@ -99,6 +108,7 @@
     case AUDIO_SOURCE_FM_TUNER:
     case AUDIO_SOURCE_ECHO_REFERENCE: // fallthrough
     case AUDIO_SOURCE_REMOTE_SUBMIX:
+    // case AUDIO_SOURCE_VOICE_DOWNLINK:
         return false;
     default:
       return true;
@@ -291,6 +301,21 @@
     return ok;
 }
 
+bool bypassConcurrentPolicyAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
+    if (isAudioServerOrRootUid(uid)) return true;
+    static const String16 sBypassConcurrentPolicy(
+            "android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION ");
+    // Use PermissionChecker, which includes some logic for allowing the isolated
+    // HotwordDetectionService to hold certain permissions.
+    bool ok = PermissionCache::checkPermission(sBypassConcurrentPolicy, pid, uid);
+    if (!ok) {
+        ALOGV("Request requires android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION");
+    }
+    return ok;
+}
+
 bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource) {
     uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
     uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 9abdbf1..573cc14 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -102,6 +102,7 @@
 bool captureMediaOutputAllowed(const AttributionSourceState& attributionSource);
 bool captureTunerAudioInputAllowed(const AttributionSourceState& attributionSource);
 bool captureVoiceCommunicationOutputAllowed(const AttributionSourceState& attributionSource);
+bool bypassConcurrentPolicyAllowed(const AttributionSourceState& attributionSource) ;
 bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource);
 bool captureHotwordAllowed(const AttributionSourceState& attributionSource);
 bool settingsAllowed();
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/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b2edaf7..c67fa13 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -110,10 +110,6 @@
 
 static constexpr char kAudioServiceName[] = "audio";
 
-// In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
-// we define a minimum time during which a global effect is considered enabled.
-static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
-
 // Keep a strong reference to media.log service around forever.
 // The service is within our parent process so it can never die in a way that we could observe.
 // These two variables are const after initialization.
@@ -5019,11 +5015,6 @@
 
 bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l() const
 {
-    if (mGlobalEffectEnableTime != 0 &&
-            ((systemTime() - mGlobalEffectEnableTime) < kMinGlobalEffectEnabletimeNs)) {
-        return true;
-    }
-
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         const auto thread = mPlaybackThreads.valueAt(i);
         audio_utils::lock_guard l(thread->mutex());
@@ -5039,8 +5030,6 @@
 {
     audio_utils::lock_guard _l(mutex());
 
-    mGlobalEffectEnableTime = systemTime();
-
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         const sp<IAfPlaybackThread> t = mPlaybackThreads.valueAt(i);
         if (t->type() == IAfThreadBase::OFFLOAD) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 133410e..e99c3ed 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -775,9 +775,6 @@
     std::atomic<size_t> mClientSharedHeapSize = kMinimumClientSharedHeapSizeBytes;
     static constexpr size_t kMinimumClientSharedHeapSizeBytes = 1024 * 1024; // 1MB
 
-    // when a global effect was last enabled
-    nsecs_t mGlobalEffectEnableTime GUARDED_BY(mutex()) = 0;
-
     /* const */ sp<IAfPatchPanel> mPatchPanel;
 
     const sp<EffectsFactoryHalInterface> mEffectsFactoryHal =
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 3163d4c..8fef263 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -163,6 +163,7 @@
     virtual audio_channel_mask_t mixerChannelMask() const = 0;
     virtual audio_format_t format() const = 0;
     virtual uint32_t channelCount() const = 0;
+    virtual std::string flagsAsString() const = 0;
 
     // Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects,
     // and returns the [normal mix] buffer's frame count.
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index d27d52a..c9c766f 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -205,6 +205,7 @@
 
     virtual const char* getTrackStateAsString() const = 0;
 
+    virtual const std::string& getTraceSuffix() const = 0;
     // Called by the PlaybackThread to indicate that the track is becoming active
     // and a new interval should start with a given device list.
     virtual void logBeginInterval(const std::string& devices) = 0;
@@ -212,6 +213,9 @@
     // Called by the PlaybackThread to indicate the track is no longer active.
     virtual void logEndInterval() = 0;
 
+    // Called by the PlaybackThread when ATRACE is enabled.
+    virtual void logRefreshInterval(const std::string& devices) = 0;
+
     // Called to tally underrun frames in playback.
     virtual void tallyUnderrunFrames(size_t frames) = 0;
 
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index 0210bc2..259136b 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -78,6 +78,7 @@
     float getPortVolume() const override { return mVolume; }
     bool getPortMute() const override { return mMutedFromPort; }
 
+    std::string trackFlagsAsString() const final { return {}; }
 private:
     DISALLOW_COPY_AND_ASSIGN(MmapTrack);
 
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 2c3212c..c335c70 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -231,6 +231,8 @@
     float getPortVolume() const override { return mVolume; }
     bool getPortMute() const override { return mMutedFromPort; }
 
+    std::string trackFlagsAsString() const final { return toString(mFlags); }
+
 protected:
 
     DISALLOW_COPY_AND_ASSIGN(Track);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 83cd024..000244e 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -98,6 +98,8 @@
         return mResamplerBufferProvider;
     }
 
+    std::string trackFlagsAsString() const final { return toString(mFlags); }
+
 private:
     DISALLOW_COPY_AND_ASSIGN(RecordTrack);
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 200175b..32690ff 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -33,6 +33,7 @@
 #include <afutils/Vibrator.h>
 #include <audio_utils/MelProcessor.h>
 #include <audio_utils/Metadata.h>
+#include <audio_utils/Trace.h>
 #include <com_android_media_audioserver.h>
 #ifdef DEBUG_CPU_USAGE
 #include <audio_utils/Statistics.h>
@@ -612,7 +613,7 @@
 // ----------------------------------------------------------------------------
 
 // static
-const char* ThreadBase::threadTypeToString(ThreadBase::type_t type)
+const char* IAfThreadBase::threadTypeToString(ThreadBase::type_t type)
 {
     switch (type) {
     case MIXER:
@@ -2184,6 +2185,7 @@
         mIsTimestampAdvancing(kMinimumTimeBetweenTimestampChecksNs)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
+    mFlagsAsString = toString(output->flags);
     mNBLogWriter = afThreadCallback->newWriter_l(kLogSize, mThreadName);
 
     // Assumes constructor is called by AudioFlinger with its mutex() held, but
@@ -4271,6 +4273,17 @@
                 track->updateTeePatches_l();
             }
 
+            // check if traces have been enabled.
+            bool atraceEnabled = ATRACE_ENABLED();
+            if (atraceEnabled != mAtraceEnabled) [[unlikely]] {
+                mAtraceEnabled = atraceEnabled;
+                if (atraceEnabled) {
+                    const auto devices = patchSinksToString(&mPatch);
+                    for (const auto& track : activeTracks) {
+                        track->logRefreshInterval(devices);
+                    }
+                }
+            }
             // signal actual start of output stream when the render position reported by
             // the kernel starts moving.
             if (!mHalStarted && ((isSuspended() && (mBytesWritten != 0)) || (!mStandby
@@ -5261,6 +5274,8 @@
         fastTrack->mHapticScale = os::HapticScale::none();
         fastTrack->mHapticMaxAmplitude = NAN;
         fastTrack->mGeneration++;
+        snprintf(fastTrack->mTraceName, sizeof(fastTrack->mTraceName),
+                 "%s.0.0.%d", AUDIO_TRACE_PREFIX_AUDIO_TRACK_FRDY, mId);
         state->mFastTracksGen++;
         state->mTrackMask = 1;
         // fast mixer will use the HAL output sink
@@ -5838,6 +5853,9 @@
                     fastTrack->mHapticScale = track->getHapticScale();
                     fastTrack->mHapticMaxAmplitude = track->getHapticMaxAmplitude();
                     fastTrack->mGeneration++;
+                    snprintf(fastTrack->mTraceName, sizeof(fastTrack->mTraceName),
+                             "%s%s", AUDIO_TRACE_PREFIX_AUDIO_TRACK_FRDY,
+                             track->getTraceSuffix().c_str());
                     state->mTrackMask |= 1 << j;
                     didModify = true;
                     // no acknowledgement required for newly active tracks
@@ -5980,11 +5998,9 @@
         }
 
         size_t framesReady = track->framesReady();
-        if (ATRACE_ENABLED()) {
-            // I wish we had formatted trace names
-            std::string traceName("nRdy");
-            traceName += std::to_string(trackId);
-            ATRACE_INT(traceName.c_str(), framesReady);
+        if (ATRACE_ENABLED()) [[unlikely]] {
+            ATRACE_INT(std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_NRDY)
+                    .append(track->getTraceSuffix()).c_str(), framesReady);
         }
         if ((framesReady >= minFrames) && track->isReady() &&
                 !track->isPaused() && !track->isTerminated())
@@ -7011,10 +7027,9 @@
 
         const size_t framesReady = track->framesReady();
         const int trackId = track->id();
-        if (ATRACE_ENABLED()) {
-            std::string traceName("nRdy");
-            traceName += std::to_string(trackId);
-            ATRACE_INT(traceName.c_str(), framesReady);
+        if (ATRACE_ENABLED()) [[unlikely]] {
+            ATRACE_INT(std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_NRDY)
+                    .append(track->getTraceSuffix()).c_str(), framesReady);
         }
         if ((framesReady >= minFrames) && track->isReady() && !track->isPaused() &&
                 !track->isStopping_2() && !track->isStopped())
@@ -7534,6 +7549,11 @@
             continue;
         }
 
+        const size_t framesReady = track->framesReady();
+        if (ATRACE_ENABLED()) [[unlikely]] {
+            ATRACE_INT(std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_NRDY)
+                    .append(track->getTraceSuffix()).c_str(), framesReady);
+        }
         if (track->isPausePending()) {
             track->pauseAck();
             // It is possible a track might have been flushed or stopped.
@@ -7592,7 +7612,7 @@
                 // Do not handle new data in this iteration even if track->framesReady()
                 mixerStatus = MIXER_TRACKS_ENABLED;
             }
-        }  else if (track->framesReady() && track->isReady() &&
+        } else if (framesReady && track->isReady() &&
                 !track->isPaused() && !track->isTerminated() && !track->isStopping_2()) {
             ALOGVV("OffloadThread: track(%d) s=%08x [OK]", track->id(), cblk->mServer);
             if (track->fillingStatus() == IAfTrack::FS_FILLED) {
@@ -8237,6 +8257,7 @@
     , mBtNrecSuspended(false)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
+    mFlagsAsString = toString(input->flags);
     mNBLogWriter = afThreadCallback->newWriter_l(kLogSize, mThreadName);
 
     if (mInput->audioHwDev != nullptr) {
@@ -8574,7 +8595,6 @@
                     }
                     if (invalidate) {
                         activeTrack->invalidate();
-                        ALOG_ASSERT(fastTrackToRemove == 0);
                         fastTrackToRemove = activeTrack;
                         removeTrack_l(activeTrack);
                         mActiveTracks.remove(activeTrack);
@@ -8591,6 +8611,18 @@
 
             mActiveTracks.updatePowerState_l(this);
 
+            // check if traces have been enabled.
+            bool atraceEnabled = ATRACE_ENABLED();
+            if (atraceEnabled != mAtraceEnabled) [[unlikely]] {
+                mAtraceEnabled = atraceEnabled;
+                if (atraceEnabled) {
+                    const auto devices = patchSourcesToString(&mPatch);
+                    for (const auto& track : activeTracks) {
+                        track->logRefreshInterval(devices);
+                    }
+                }
+            }
+
             updateMetadata_l();
 
             if (allStopped) {
@@ -11172,6 +11204,7 @@
       mOutput(output)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioMmapOut_%X", id);
+    mFlagsAsString = toString(output->flags);
     mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
     mMasterVolume = afThreadCallback->masterVolume_l();
     mMasterMute = afThreadCallback->masterMute_l();
@@ -11515,6 +11548,7 @@
       mInput(input)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
+    mFlagsAsString = toString(input->flags);
     mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
 }
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1d6e244..6784341 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -43,7 +43,6 @@
 
 class ThreadBase : public virtual IAfThreadBase, public Thread {
 public:
-    static const char *threadTypeToString(type_t type);
 
     // ThreadBase_ThreadLoop is a virtual mutex (always nullptr) that
     // guards methods and variables that ONLY run and are accessed
@@ -400,6 +399,8 @@
         }
     }
 
+    std::string flagsAsString() const final {  return mFlagsAsString; }
+
     sp<IAfEffectHandle> createEffect_l(
                                     const sp<Client>& client,
                                     const sp<media::IEffectClient>& effectClient,
@@ -681,6 +682,9 @@
                 ThreadMetrics           mThreadMetrics;
                 const bool              mIsOut;
 
+    std::string mFlagsAsString;                                     // set in constructor.
+    bool mAtraceEnabled GUARDED_BY(ThreadBase_ThreadLoop) = false;  // checked in threadLoop.
+
     // mThreadBusy is checked under the ThreadBase_Mutex to ensure that
     // TrackHandle operations do not proceed while the ThreadBase is busy
     // with the track.  mThreadBusy is only true if the track is active.
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index cde7fc2..2b3d772 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -22,6 +22,7 @@
 
 #include <afutils/NBAIO_Tee.h>
 #include <android-base/macros.h>  // DISALLOW_COPY_AND_ASSIGN
+#include <audio_utils/Trace.h>
 #include <datapath/TrackMetrics.h>
 #include <mediautils/BatteryNotifier.h>
 #include <psh_utils/AudioPowerManager.h>
@@ -210,16 +211,16 @@
         }
     }
 
+    const std::string& getTraceSuffix() const final { return mTraceSuffix; }
     // Called by the PlaybackThread to indicate that the track is becoming active
     // and a new interval should start with a given device list.
-    void logBeginInterval(const std::string& devices) final {
-        mTrackMetrics.logBeginInterval(devices);
-    }
+    void logBeginInterval(const std::string& devices) final;
 
     // Called by the PlaybackThread to indicate the track is no longer active.
-    void logEndInterval() final {
-        mTrackMetrics.logEndInterval();
-    }
+    void logEndInterval() final;
+
+    // Called by the PlaybackThread when ATRACE is enabled.
+    void logRefreshInterval(const std::string& devices) final;
 
     // Called to tally underrun frames in playback.
     void tallyUnderrunFrames(size_t /* frames */) override {}
@@ -333,6 +334,10 @@
     void deferRestartIfDisabled();
     virtual void restartIfDisabled() {}
 
+    virtual std::string trackFlagsAsString() const = 0;
+
+    audio_utils::trace::Object createDeviceIntervalTrace(const std::string& devices);
+
     const wp<IAfThreadBase> mThread;
     const alloc_type     mAllocType;
     /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
@@ -384,6 +389,7 @@
 
     bool                mLogForceVolumeUpdate = true; // force volume update to TrackMetrics.
 
+    audio_utils::trace::Object mLastTrace;  // accessed by PlaybackThread or RecordThread
     TrackMetrics        mTrackMetrics;
 
     bool                mServerLatencySupported = false;
@@ -393,6 +399,10 @@
     const pid_t         mCreatorPid;  // can be different from mclient->pid() for instance
                                       // when created by NuPlayer on behalf of a client
 
+    const std::string mTraceSuffix;
+    const std::string mTraceActionId;
+    const std::string mTraceIntervalId;
+
     // If the last track change was notified to the client with readAndClearHasChanged
     std::atomic_flag    mChangeNotified = ATOMIC_FLAG_INIT;
     // RAII object for battery stats book-keeping
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5fbe48c..78ba24d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -28,6 +28,7 @@
 #include "IAfThread.h"
 #include "ResamplerBufferProvider.h"
 
+#include <audio_utils/StringUtils.h>
 #include <audio_utils/minifloat.h>
 #include <media/AudioValidator.h>
 #include <media/RecordBufferConverter.h>
@@ -124,7 +125,12 @@
         mPortId(portId),
         mIsInvalid(false),
         mTrackMetrics(std::move(metricsId), isOut, clientUid),
-        mCreatorPid(creatorPid)
+        mCreatorPid(creatorPid),
+        mTraceSuffix{std::to_string(mPortId).append(".").append(std::to_string(mId))
+                .append(".").append(std::to_string(mThreadIoHandle))},
+        mTraceActionId{std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_ACTION).append(mTraceSuffix)},
+        mTraceIntervalId{std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_INTERVAL)
+                .append(mTraceSuffix)}
 {
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     if (!isAudioServerOrMediaServerUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
@@ -337,6 +343,90 @@
     mTrackToken.reset();
 }
 
+audio_utils::trace::Object TrackBase::createDeviceIntervalTrace(const std::string& devices) {
+    audio_utils::trace::Object trace;
+
+    // Please do not modify any items without approval (look at git blame).
+    // Sanitize the device string to remove addresses.
+    std::string plainDevices;
+    if (devices.find(")") != std::string::npos) {
+        auto deviceAddrVector = audio_utils::stringutils::getDeviceAddressPairs(devices);
+        for (const auto& deviceAddr : deviceAddrVector) {
+            // "|" not compatible with ATRACE filtering so we use "+".
+            if (!plainDevices.empty()) plainDevices.append("+");
+            plainDevices.append(deviceAddr.first);
+        }
+    } else {
+        plainDevices = devices;
+    }
+
+    trace // the following key, value pairs should be alphabetical
+            .set(AUDIO_TRACE_OBJECT_KEY_CHANNEL_MASK, static_cast<int32_t>(mChannelMask))
+            .set(AUDIO_TRACE_OBJECT_KEY_CONTENT_TYPE, toString(mAttr.content_type))
+            .set(AUDIO_TRACE_OBJECT_KEY_DEVICES, plainDevices)
+            .set(AUDIO_TRACE_OBJECT_KEY_FLAGS, trackFlagsAsString())
+            .set(AUDIO_TRACE_OBJECT_KEY_FORMAT, IAfThreadBase::formatToString(mFormat))
+            .set(AUDIO_TRACE_OBJECT_KEY_FRAMECOUNT, static_cast<int64_t>(mFrameCount))
+            .set(AUDIO_TRACE_OBJECT_KEY_PID, static_cast<int32_t>(mClient->pid()))
+            .set(AUDIO_TRACE_OBJECT_KEY_SAMPLE_RATE, static_cast<int32_t>(sampleRate()));
+    if (const auto thread = mThread.promote()) {
+        trace // continue in alphabetical order
+                .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_CHANNEL_MASK,
+                        static_cast<int32_t>(thread->channelMask()))
+                .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_FLAGS,
+                        thread->flagsAsString())
+                .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_FORMAT,
+                        IAfThreadBase::formatToString(thread->format()))
+                .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_FRAMECOUNT,
+                        static_cast<int64_t>(thread->frameCount()))
+                .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_ID,
+                        static_cast<int32_t>(mThreadIoHandle))
+                .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_SAMPLE_RATE,
+                        static_cast<int32_t>(thread->sampleRate()))
+                .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_TYPE,
+                        IAfThreadBase::threadTypeToString(thread->type()));
+    }
+    trace // continue in alphabetical order
+            .set(AUDIO_TRACE_OBJECT_KEY_UID, static_cast<int32_t>(uid()))
+            .set(AUDIO_TRACE_OBJECT_KEY_USAGE, toString(mAttr.usage));
+    return trace;
+}
+
+void TrackBase::logBeginInterval(const std::string& devices) {
+    mTrackMetrics.logBeginInterval(devices);
+
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        auto trace = createDeviceIntervalTrace(devices);
+        mLastTrace = trace;
+        ATRACE_INSTANT_FOR_TRACK(mTraceIntervalId.c_str(),
+                trace.set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_BEGIN_INTERVAL)
+                        .toTrace().c_str());
+    }
+}
+
+void TrackBase::logEndInterval() {
+    if (!mLastTrace.empty()) {
+        if (ATRACE_ENABLED()) [[unlikely]] {
+            ATRACE_INSTANT_FOR_TRACK(mTraceIntervalId.c_str(),
+                    mLastTrace.set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_END_INTERVAL)
+                            .toTrace().c_str());
+        }
+        mLastTrace.clear();
+    }
+    mTrackMetrics.logEndInterval();
+}
+
+void TrackBase::logRefreshInterval(const std::string& devices) {
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        if (mLastTrace.empty()) mLastTrace = createDeviceIntervalTrace(devices);
+        auto trace = mLastTrace;
+        ATRACE_INSTANT_FOR_TRACK(mTraceIntervalId.c_str(),
+                trace.set(AUDIO_TRACE_OBJECT_KEY_EVENT,
+                               AUDIO_TRACE_EVENT_REFRESH_INTERVAL)
+                        .toTrace().c_str());
+    }
+}
+
 PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
         IAfThreadBase* thread, const Timeout& timeout)
     : mProxy(proxy)
@@ -1159,6 +1249,12 @@
         ALOGV("%s(%d): underrun,  framesReady(%zu) < framesDesired(%zd), state: %d",
                 __func__, mId, buf.mFrameCount, desiredFrames, (int)mState);
         mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+        if (ATRACE_ENABLED()) [[unlikely]] {
+            ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                    .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_UNDERRUN)
+                    .set(AUDIO_TRACE_OBJECT_KEY_FRAMECOUNT, desiredFrames)
+                    .toTrace().c_str());
+        }
     } else {
         mAudioTrackServerProxy->tallyUnderrunFrames(0);
     }
@@ -1271,6 +1367,11 @@
 status_t Track::start(AudioSystem::sync_event_t event __unused,
                                                     audio_session_t triggerSession __unused)
 {
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_START)
+                .toTrace().c_str());
+    }
     status_t status = NO_ERROR;
     ALOGV("%s(%d): calling pid %d session %d",
             __func__, mId, IPCThreadState::self()->getCallingPid(), mSessionId);
@@ -1415,6 +1516,11 @@
 void Track::stop()
 {
     ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_STOP)
+                .toTrace().c_str());
+    }
     const sp<IAfThreadBase> thread = mThread.promote();
     if (thread != 0) {
         audio_utils::unique_lock ul(thread->mutex());
@@ -1452,6 +1558,11 @@
 void Track::pause()
 {
     ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_PAUSE)
+                .toTrace().c_str());
+    }
     const sp<IAfThreadBase> thread = mThread.promote();
     if (thread != 0) {
         audio_utils::unique_lock ul(thread->mutex());
@@ -1491,6 +1602,11 @@
 void Track::flush()
 {
     ALOGV("%s(%d)", __func__, mId);
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_FLUSH)
+                .toTrace().c_str());
+    }
     const sp<IAfThreadBase> thread = mThread.promote();
     if (thread != 0) {
         audio_utils::unique_lock ul(thread->mutex());
@@ -2936,6 +3052,11 @@
 status_t RecordTrack::start(AudioSystem::sync_event_t event,
                                                         audio_session_t triggerSession)
 {
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_START)
+                .toTrace().c_str());
+    }
     const sp<IAfThreadBase> thread = mThread.promote();
     if (thread != 0) {
         auto* const recordThread = thread->asIAfRecordThread().get();
@@ -2948,6 +3069,11 @@
 
 void RecordTrack::stop()
 {
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_STOP)
+                .toTrace().c_str());
+    }
     const sp<IAfThreadBase> thread = mThread.promote();
     if (thread != 0) {
         auto* const recordThread = thread->asIAfRecordThread().get();
@@ -3619,11 +3745,21 @@
 status_t MmapTrack::start(AudioSystem::sync_event_t event __unused,
                                                     audio_session_t triggerSession __unused)
 {
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_START)
+                .toTrace().c_str());
+    }
     return NO_ERROR;
 }
 
 void MmapTrack::stop()
 {
+    if (ATRACE_ENABLED()) [[unlikely]] {
+        ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+                .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_STOP)
+                .toTrace().c_str());
+    }
 }
 
 // AudioBufferProvider interface
diff --git a/services/audioflinger/fastpath/FastMixer.cpp b/services/audioflinger/fastpath/FastMixer.cpp
index 1d41b3f..760ce1d 100644
--- a/services/audioflinger/fastpath/FastMixer.cpp
+++ b/services/audioflinger/fastpath/FastMixer.cpp
@@ -36,6 +36,7 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
+#include <audio_utils/Trace.h>
 #include <audio_utils/channels.h>
 #include <audio_utils/format.h>
 #include <audio_utils/mono_blend.h>
@@ -397,12 +398,7 @@
             // in the overall fast mix cycle being delayed.  Should use a non-blocking FIFO.
             const size_t framesReady = fastTrack->mBufferProvider->framesReady();
             if (ATRACE_ENABLED()) {
-                // I wish we had formatted trace names
-                char traceName[16];
-                strcpy(traceName, "fRdy");
-                traceName[4] = i + (i < 10 ? '0' : 'A' - 10);
-                traceName[5] = '\0';
-                ATRACE_INT(traceName, framesReady);
+                ATRACE_INT(fastTrack->mTraceName, framesReady);
             }
             FastTrackDump *ftDump = &dumpState->mTracks[i];
             FastTrackUnderruns underruns = ftDump->mUnderruns;
diff --git a/services/audioflinger/fastpath/FastMixerState.h b/services/audioflinger/fastpath/FastMixerState.h
index 0a56f92..f01dd4b 100644
--- a/services/audioflinger/fastpath/FastMixerState.h
+++ b/services/audioflinger/fastpath/FastMixerState.h
@@ -56,6 +56,7 @@
     bool                    mHapticPlaybackEnabled = false; // haptic playback is enabled or not
     os::HapticScale mHapticScale = os::HapticScale::mute(); // scale of haptic data
     float                   mHapticMaxAmplitude = NAN; // max amplitude allowed for haptic data
+    char mTraceName[32]{};
 };
 
 // No virtuals.
diff --git a/services/audioparameterparser/Android.bp b/services/audioparameterparser/Android.bp
index 1c1c1e1..0b2c1ba 100644
--- a/services/audioparameterparser/Android.bp
+++ b/services/audioparameterparser/Android.bp
@@ -35,10 +35,10 @@
     name: "android.hardware.audio.parameter_parser.example_defaults",
     defaults: [
         "latest_android_hardware_audio_core_ndk_shared",
-        "latest_av_audio_types_aidl_ndk_shared",
     ],
 
     shared_libs: [
+        "av-audio-types-aidl-ndk",
         "libbase",
         "libbinder_ndk",
     ],
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 8dd247a..e5bd121 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -19,15 +19,18 @@
 
 #include <android/media/DeviceConnectedState.h>
 #include <android/media/TrackInternalMuteInfo.h>
+#include <android/media/audio/common/AudioConfigBase.h>
 #include <android/media/audio/common/AudioMMapPolicyInfo.h>
 #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>
-#include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
+#include <media/AudioSystem.h>
 #include <media/DeviceDescriptorBase.h>
-#include <android/content/AttributionSourceState.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -161,18 +164,26 @@
     // releases the output, return true if the output descriptor is reopened.
     virtual bool releaseOutput(audio_port_handle_t portId) = 0;
 
-    // request an input appropriate for record from the supplied device with supplied parameters.
-    virtual status_t getInputForAttr(const audio_attributes_t *attr,
-                                     audio_io_handle_t *input,
+    // Request an input appropriate for record from the supplied device with supplied parameters.
+    // attr -- attributes for the requested record
+    // requestedInput -- input only for MMAP mode where an input is re-used, otherwise output param
+    // requestedDeviceId, config, flags -- additional params for matching
+    // riid, session, attributionSource -- params which encapsulate client info to associate with
+    // this input
+    //
+    // On most errors, return a Status describing the error in the error object.
+    // However, in cases where an appropriate device cannot be found for a config, the error side of
+    // the unexpected will contain a suggested config.
+    virtual base::expected<media::GetInputForAttrResponse,
+            std::variant<binder::Status, media::audio::common::AudioConfigBase>>
+                     getInputForAttr(audio_attributes_t attributes,
+                                     audio_io_handle_t requestedInput,
+                                     audio_port_handle_t requestedDeviceId,
+                                     audio_config_base_t config,
+                                     audio_input_flags_t flags,
                                      audio_unique_id_t riid,
                                      audio_session_t session,
-                                     const AttributionSourceState& attributionSource,
-                                     audio_config_base_t *config,
-                                     audio_input_flags_t flags,
-                                     audio_port_handle_t *selectedDeviceId,
-                                     input_type_t *inputType,
-                                     audio_port_handle_t *portId,
-                                     uint32_t *virtualDeviceId) = 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.
@@ -625,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/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index e519766..918e247 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -64,6 +64,21 @@
             if (activeClients.size() == activeClientsWithRoute.size()) {
                 return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
             }
+            if (activeClientsWithRoute.size() == 0) {
+                return nullptr;
+            }
+            uid_t uniqueUid = activeClients[0]->uid();
+            for (const auto &client : activeClients) {
+                if (uniqueUid != client->uid()) {
+                   return nullptr;
+                }
+            }
+            for (const auto &client : activeClientsWithRoute) {
+                if (uniqueUid != client->uid()) {
+                   return nullptr;
+                }
+            }
+            return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
         }
     }
     return nullptr;
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 1c6248a..b17a248 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -286,7 +286,7 @@
 bool AudioPolicyManagerFuzzer::getInputForAttr(
     const audio_attributes_t &attr, audio_unique_id_t riid, audio_port_handle_t *selectedDeviceId,
     audio_format_t format, audio_channel_mask_t channelMask, int sampleRate,
-    audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t *virtualDeviceId) {
+    audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t*) {
     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
     audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
     config.sample_rate = sampleRate;
@@ -295,16 +295,15 @@
     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();
-    if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, attributionSource,
-            &config, flags, selectedDeviceId, &inputType, portId, virtualDeviceId) != OK) {
-        return false;
-    }
-    if (*portId == AUDIO_PORT_HANDLE_NONE || input == AUDIO_IO_HANDLE_NONE) {
+    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) {
         return false;
     }
     return true;
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index e6f6374..94be786 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -41,6 +41,7 @@
         // a dependency on it in the device makefile. There will be no build time
         // conflict with libaudiopolicyenginedefault.
         "audioclient-types-aidl-cpp",
+        "audiopolicy-aidl-cpp",
         // Flag support
         "android.media.audiopolicy-aconfig-cc",
         "com.android.media.audioserver-aconfig-cc",
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0ebf8d1..303f313 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "utils/Errors.h"
 #define LOG_TAG "APM_AudioPolicyManager"
 
 // Need to keep the log statements even in production builds
@@ -46,6 +45,7 @@
 #include <android_media_audiopolicy.h>
 #include <com_android_media_audioserver.h>
 #include <cutils/bitops.h>
+#include <error/expected_utils.h>
 #include <media/AudioParameter.h>
 #include <policy.h>
 #include <private/android_filesystem_config.h>
@@ -71,6 +71,8 @@
 using android::media::audio::common::AudioMMapPolicyType;
 using android::media::audio::common::AudioPortDeviceExt;
 using android::media::audio::common::AudioPortExt;
+using android::media::audio::common::AudioConfigBase;
+using binder::Status;
 using com::android::media::audioserver::fix_call_audio_patch;
 using content::AttributionSourceState;
 
@@ -1557,7 +1559,8 @@
         for (auto &secondaryMix : secondaryMixes) {
             sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
             if (outputDesc != nullptr &&
-                outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+                outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE &&
+                outputDesc->mIoHandle != *output) {
                 secondaryOutputs->push_back(outputDesc->mIoHandle);
                 weakSecondaryOutputDescs.push_back(outputDesc);
             }
@@ -2925,63 +2928,67 @@
     return false;
 }
 
-status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
-                                             audio_io_handle_t *input,
-                                             audio_unique_id_t riid,
-                                             audio_session_t session,
-                                             const AttributionSourceState& attributionSource,
-                                             audio_config_base_t *config,
-                                             audio_input_flags_t flags,
-                                             audio_port_handle_t *selectedDeviceId,
-                                             input_type_t *inputType,
-                                             audio_port_handle_t *portId,
-                                             uint32_t *virtualDeviceId)
+base::expected<media::GetInputForAttrResponse, std::variant<binder::Status, AudioConfigBase>>
+AudioPolicyManager::getInputForAttr(audio_attributes_t attributes,
+                                     audio_io_handle_t requestedInput,
+                                     audio_port_handle_t requestedDeviceId,
+                                     audio_config_base_t config,
+                                     audio_input_flags_t flags,
+                                     audio_unique_id_t riid,
+                                     audio_session_t session,
+                                     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",
-          __func__, attr->source, config->sample_rate, config->format, config->channel_mask,
-          session, flags, toString(*attr).c_str(), *selectedDeviceId);
+          __func__, attributes.source, config.sample_rate, config.format, config.channel_mask,
+          session, flags, toString(attributes).c_str(), requestedDeviceId);
 
-    status_t status = NO_ERROR;
-    audio_attributes_t attributes = *attr;
     sp<AudioPolicyMix> policyMix;
     sp<DeviceDescriptor> device;
     sp<AudioInputDescriptor> inputDesc;
     sp<AudioInputDescriptor> previousInputDesc;
     sp<RecordClientDescriptor> clientDesc;
-    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
-    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    uid_t uid = static_cast<uid_t>(attributionSource.uid);
     bool isSoundTrigger;
+    int vdi = 0 /* default device id */;
+    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
 
-    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
-    if (*portId != AUDIO_PORT_HANDLE_NONE) {
-        return INVALID_OPERATION;
-    }
-
-    if (attr->source == AUDIO_SOURCE_DEFAULT) {
+    if (attributes.source == AUDIO_SOURCE_DEFAULT) {
         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(*selectedDeviceId);
+            mAvailableInputDevices.getDeviceFromId(requestedDeviceId);
 
     // special case for mmap capture: if an input IO handle is specified, we reuse this input if
     // possible
     if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
-            *input != AUDIO_IO_HANDLE_NONE) {
-        ssize_t index = mInputs.indexOfKey(*input);
+            requestedInput != AUDIO_IO_HANDLE_NONE) {
+        input = requestedInput;
+        ssize_t index = mInputs.indexOfKey(requestedInput);
         if (index < 0) {
-            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
-            status = BAD_VALUE;
-            goto error;
+            return base::unexpected{Status::fromExceptionCode(
+                    EX_ILLEGAL_ARGUMENT,
+                    String8::format("%s unknown MMAP input %d", __func__, requestedInput))};
         }
         sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
         RecordClientVector clients = inputDesc->getClientsForSession(session);
         if (clients.size() == 0) {
-            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
-            status = BAD_VALUE;
-            goto error;
+            return base::unexpected{Status::fromExceptionCode(
+                    EX_ILLEGAL_ARGUMENT, String8::format("%s unknown session %d on input %d",
+                                                         __func__, session, requestedInput))};
         }
         // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
         // The second call is for the first active client and sets the UID. Any further call
@@ -2997,146 +3004,146 @@
                     continue;
                 }
                 if (uid != client->uid() && !client->isSilenced()) {
-                    ALOGW("getInputForAttr() bad uid %d for client %d uid %d",
-                          uid, client->portId(), client->uid());
-                    status = INVALID_OPERATION;
-                    goto error;
+                    return base::unexpected{Status::fromExceptionCode(
+                            EX_ILLEGAL_STATE,
+                            String8::format("%s bad uid %d for client %d uid %d", __func__, uid,
+                                            client->portId(), client->uid()))};
                 }
             }
         }
-        *inputType = API_INPUT_LEGACY;
         device = inputDesc->getDevice();
-
-        ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
-        goto exit;
-    }
-
-    *input = AUDIO_IO_HANDLE_NONE;
-    *inputType = API_INPUT_INVALID;
-
-    if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
-            extractAddressFromAudioAttributes(attributes).has_value()) {
-        status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
-        if (status != NO_ERROR) {
-            ALOGW("%s could not find input mix for attr %s",
-                    __func__, toString(attributes).c_str());
-            goto error;
-        }
-        device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
-                                                  String8(attr->tags + strlen("addr=")),
-                                                  AUDIO_FORMAT_DEFAULT);
-        if (device == nullptr) {
-            ALOGW("%s could not find in Remote Submix device for source %d, tags %s",
-                    __func__, attributes.source, attributes.tags);
-            status = BAD_VALUE;
-            goto error;
-        }
-
-        if (is_mix_loopback_render(policyMix->mRouteFlags)) {
-            *inputType = API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK;
-        } else {
-            *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
-        }
-        if (virtualDeviceId) {
-            *virtualDeviceId = policyMix->mVirtualDeviceId;
-        }
+        ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, requestedInput, session);
     } else {
-        if (explicitRoutingDevice != nullptr) {
-            device = explicitRoutingDevice;
+        if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+                extractAddressFromAudioAttributes(attributes).has_value()) {
+            status_t status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
+            if (status != NO_ERROR) {
+                ALOGW("%s could not find input mix for attr %s",
+                        __func__, toString(attributes).c_str());
+                return base::unexpected {aidl_utils::binderStatusFromStatusT(status)};
+            }
+            device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                                                      String8(attributes.tags + strlen("addr=")),
+                                                      AUDIO_FORMAT_DEFAULT);
+            if (device == nullptr) {
+                return base::unexpected{Status::fromExceptionCode(
+                        EX_ILLEGAL_ARGUMENT,
+                        String8::format(
+                                "%s could not find in Remote Submix device for source %d, tags %s",
+                                __func__, attributes.source, attributes.tags))};
+            }
+
+            if (is_mix_loopback_render(policyMix->mRouteFlags)) {
+                permReq.mixType = MixType::PUBLIC_CAPTURE_PLAYBACK;
+            } else {
+                permReq.mixType = MixType::EXT_POLICY_REROUTE;
+            }
+            // TODO is this correct?
+            permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
         } else {
-            // Prevent from storing invalid requested device id in clients
-            requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
-            device = mEngine->getInputDeviceForAttributes(attributes, uid, session, &policyMix);
-            ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
-                __FUNCTION__, device->type());
-        }
-        if (device == nullptr) {
-            ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
-            status = BAD_VALUE;
-            goto error;
-        }
-        if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
-            *inputType = API_INPUT_MIX_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;
-
-            if (virtualDeviceId) {
-                *virtualDeviceId = policyMix->mVirtualDeviceId;
+            if (explicitRoutingDevice != nullptr) {
+                device = explicitRoutingDevice;
+            } else {
+                // Prevent from storing invalid requested device id in clients
+                requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
+                device = mEngine->getInputDeviceForAttributes(attributes, uid, session, &policyMix);
+                ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
+                    __FUNCTION__, device->type());
             }
-        } else if (audio_is_remote_submix_device(device->type())) {
-            *inputType = API_INPUT_MIX_CAPTURE;
-        } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
-            *inputType = API_INPUT_TELEPHONY_RX;
-        } else {
-            *inputType = API_INPUT_LEGACY;
+            if (device == nullptr) {
+                return base::unexpected{Status::fromExceptionCode(
+                        EX_ILLEGAL_ARGUMENT,
+                        String8::format("%s could not find device for source %d", __func__,
+                                        attributes.source))};
+            }
+            if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
+                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"
+                permReq.mixType = MixType::NONE;
+                permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
+            } else if (audio_is_remote_submix_device(device->type())) {
+                permReq.mixType = MixType::CAPTURE;
+            } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+                permReq.mixType = MixType::TELEPHONY_RX_CAPTURE;
+            } else {
+                permReq.mixType = MixType::NONE;
+            }
         }
 
+        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) {
+            AudioProfileVector profiles;
+            status_t ret = getProfilesForDevices(
+                    DeviceVector(device), profiles, flags, true /*isInput*/);
+            if (ret == NO_ERROR && !profiles.empty()) {
+                const auto channels = profiles[0]->getChannels();
+                if (!channels.empty() && (channels.find(config.channel_mask) == channels.end())) {
+                    config.channel_mask = *channels.begin();
+                }
+                const auto sampleRates = profiles[0]->getSampleRates();
+                if (!sampleRates.empty() &&
+                        (sampleRates.find(config.sample_rate) == sampleRates.end())) {
+                    config.sample_rate = *sampleRates.begin();
+                }
+                config.format = profiles[0]->getFormat();
+            }
+            const auto suggestedConfig = VALUE_OR_FATAL(
+                legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
+            return base::unexpected {suggestedConfig};
+        }
     }
 
-    *input = getInputForDevice(device, session, attributes, config, flags, policyMix);
-    if (*input == AUDIO_IO_HANDLE_NONE) {
-        status = INVALID_OPERATION;
-        AudioProfileVector profiles;
-        status_t ret = getProfilesForDevices(
-                DeviceVector(device), profiles, flags, true /*isInput*/);
-        if (ret == NO_ERROR && !profiles.empty()) {
-            const auto channels = profiles[0]->getChannels();
-            if (!channels.empty() && (channels.find(config->channel_mask) == channels.end())) {
-                config->channel_mask = *channels.begin();
-            }
-            const auto sampleRates = profiles[0]->getSampleRates();
-            if (!sampleRates.empty() &&
-                    (sampleRates.find(config->sample_rate) == sampleRates.end())) {
-                config->sample_rate = *sampleRates.begin();
-            }
-            config->format = profiles[0]->getFormat();
-        }
-        goto error;
-    }
-
-
-    if (policyMix != nullptr && virtualDeviceId != nullptr) {
-        *virtualDeviceId = policyMix->mVirtualDeviceId;
-    }
-
-exit:
-
-    *selectedDeviceId = mAvailableInputDevices.contains(device) ?
+    auto selectedDeviceId = mAvailableInputDevices.contains(device) ?
                 device->getId() : AUDIO_PORT_HANDLE_NONE;
 
     isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
         mSoundTriggerSessions.indexOfKey(session) >= 0;
-    *portId = PolicyAudioPort::getNextUniqueId();
 
-    clientDesc = new RecordClientDescriptor(*portId, riid, uid, session, attributes, *config,
+    const auto allocatedPortId = PolicyAudioPort::getNextUniqueId();
+
+    clientDesc = new RecordClientDescriptor(allocatedPortId, riid, uid, session, attributes, config,
                                             requestedDeviceId, attributes.source, flags,
                                             isSoundTrigger);
-    inputDesc = mInputs.valueFor(*input);
+    inputDesc = mInputs.valueFor(input);
     // Move (if found) effect for the client session to its input
-    mEffects.moveEffectsForIo(session, *input, &mInputs, mpClientInterface);
+    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, *portId);
+    ALOGV("getInputForAttr() returns input %d selectedDeviceId %d vdi %d for port ID %d",
+            input, selectedDeviceId, permReq.virtualDeviceId, allocatedPortId);
 
-    return NO_ERROR;
-
-error:
-    return status;
+    auto ret = media::GetInputForAttrResponse {};
+    ret.input = input;
+    ret.selectedDeviceId = selectedDeviceId;
+    ret.portId = allocatedPortId;
+    ret.virtualDeviceId = permReq.virtualDeviceId;
+    ret.config = legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/).value();
+    return ret;
 }
 
-
-audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor> &device,
+audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor>& device,
                                                         audio_session_t session,
-                                                        const audio_attributes_t &attributes,
-                                                        audio_config_base_t *config,
+                                                        const audio_attributes_t& attributes,
+                                                        const audio_config_base_t& config,
                                                         audio_input_flags_t flags,
-                                                        const sp<AudioPolicyMix> &policyMix)
-{
+                                                        const sp<AudioPolicyMix>& policyMix) {
     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
     audio_source_t halInputSource = attributes.source;
     bool isSoundTrigger = false;
@@ -3152,7 +3159,7 @@
             halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
         }
     } else if (attributes.source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
-               audio_is_linear_pcm(config->format)) {
+               audio_is_linear_pcm(config.format)) {
         flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
     }
 
@@ -3161,10 +3168,10 @@
     }
 
     // sampling rate and flags may be updated by getInputProfile
-    uint32_t profileSamplingRate = (config->sample_rate == 0) ?
-            SAMPLE_RATE_HZ_DEFAULT : config->sample_rate;
-    audio_format_t profileFormat = config->format;
-    audio_channel_mask_t profileChannelMask = config->channel_mask;
+    uint32_t profileSamplingRate = (config.sample_rate == 0) ?
+            SAMPLE_RATE_HZ_DEFAULT : config.sample_rate;
+    audio_format_t profileFormat = config.format;
+    audio_channel_mask_t profileChannelMask = config.channel_mask;
     audio_input_flags_t profileFlags = flags;
     // find a compatible input profile (not necessarily identical in parameters)
     sp<IOProfile> profile = getInputProfile(
@@ -3174,7 +3181,7 @@
     }
 
     // Pick input sampling rate if not specified by client
-    uint32_t samplingRate = config->sample_rate;
+    uint32_t samplingRate = config.sample_rate;
     if (samplingRate == 0) {
         samplingRate = profileSamplingRate;
     }
@@ -3573,19 +3580,43 @@
     ALOGI("%s: deviceType 0x%X, enabled %d, streamToDriveAbs %d", __func__, deviceType, enabled,
           streamToDriveAbs);
 
-    if (!enabled) {
-        mAbsoluteVolumeDrivingStreams.erase(deviceType);
-        return NO_ERROR;
-    }
-
+    bool changed = false;
     audio_attributes_t attributesToDriveAbs = mEngine->getAttributesForStreamType(streamToDriveAbs);
-    if (attributesToDriveAbs == AUDIO_ATTRIBUTES_INITIALIZER) {
-        ALOGW("%s: no attributes for stream %s, bailing out", __func__,
-              toString(streamToDriveAbs).c_str());
-        return BAD_VALUE;
+    if (enabled) {
+        if (attributesToDriveAbs == AUDIO_ATTRIBUTES_INITIALIZER) {
+            ALOGW("%s: no attributes for stream %s, bailing out", __func__,
+                  toString(streamToDriveAbs).c_str());
+            return BAD_VALUE;
+        }
+
+        const auto attrIt = mAbsoluteVolumeDrivingStreams.find(deviceType);
+        if (attrIt == mAbsoluteVolumeDrivingStreams.end() ||
+            (attrIt->second.usage != attributesToDriveAbs.usage ||
+             attrIt->second.content_type != attributesToDriveAbs.content_type ||
+             attrIt->second.flags != attributesToDriveAbs.flags)) {
+            mAbsoluteVolumeDrivingStreams[deviceType] = attributesToDriveAbs;
+            changed = true;
+        }
+    } else {
+        if (mAbsoluteVolumeDrivingStreams.erase(deviceType) != 0) {
+            changed = true;
+        }
     }
 
-    mAbsoluteVolumeDrivingStreams[deviceType] = attributesToDriveAbs;
+    const DeviceVector devices = mEngine->getOutputDevicesForAttributes(
+            attributesToDriveAbs, nullptr /* preferredDevice */, true /* fromCache */);
+    changed &= devices.types().contains(deviceType);
+    // if something changed on the output device for the changed attributes, apply the stream
+    // volumes regarding the new absolute mode to all the outputs without any delay
+    if (changed) {
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+            ALOGI("%s: apply stream volumes for portId %d and device type %d", __func__,
+                  desc->getId(), deviceType);
+            applyStreamVolumes(desc, {deviceType});
+        }
+    }
+
     return NO_ERROR;
 }
 
@@ -3774,19 +3805,21 @@
         }
     }
 
-    // update voice volume if the an active call route exists
-    if (mCallRxSourceClient != nullptr && mCallRxSourceClient->isConnected()
-            && (curSrcDevices.find(
-                Volume::getDeviceForVolume({mCallRxSourceClient->sinkDevice()->type()}))
-                != curSrcDevices.end())) {
-        bool isVoiceVolSrc;
-        bool isBtScoVolSrc;
-        if (isVolumeConsistentForCalls(vs, {mCallRxSourceClient->sinkDevice()->type()},
-                isVoiceVolSrc, isBtScoVolSrc, __func__)
-                && (isVoiceVolSrc || isBtScoVolSrc)) {
-            bool voiceVolumeManagedByHost = !isBtScoVolSrc &&
-                    !audio_is_ble_out_device(mCallRxSourceClient->sinkDevice()->type());
-            setVoiceVolume(index, curves, voiceVolumeManagedByHost, 0);
+    // update voice volume if the an active call route exists and target device is same as current
+    if (mCallRxSourceClient != nullptr && mCallRxSourceClient->isConnected()) {
+        audio_devices_t rxSinkDevice = mCallRxSourceClient->sinkDevice()->type();
+        audio_devices_t curVoiceDevice = Volume::getDeviceForVolume({rxSinkDevice});
+        if (curVoiceDevice == device
+                && curSrcDevices.find(curVoiceDevice) != curSrcDevices.end()) {
+            bool isVoiceVolSrc;
+            bool isBtScoVolSrc;
+            if (isVolumeConsistentForCalls(vs, {rxSinkDevice},
+                    isVoiceVolSrc, isBtScoVolSrc, __func__)
+                    && (isVoiceVolSrc || isBtScoVolSrc)) {
+                bool voiceVolumeManagedByHost = !isBtScoVolSrc &&
+                        !audio_is_ble_out_device(rxSinkDevice);
+                setVoiceVolume(index, curves, voiceVolumeManagedByHost, 0);
+            }
         }
     }
 
@@ -7623,7 +7656,8 @@
             for (auto &secondaryMix : secondaryMixes) {
                 sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
                 if (outputDesc != nullptr &&
-                    outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+                    outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE &&
+                    outputDesc != outputDescriptor) {
                     secondaryDescs.push_back(outputDesc);
                 }
             }
@@ -7822,7 +7856,8 @@
     }
 
     // Honor explicit routing requests only if no client using default routing is active on this
-    // input: a specific app can not force routing for other apps by setting a preferred device.
+    // input or if all active clients are from the same app: a specific app can not force routing
+    // for other apps by setting a preferred device.
     bool active;
     device = findPreferredDevice(inputDesc, AUDIO_SOURCE_DEFAULT, active, mAvailableInputDevices);
     if (device != nullptr) {
@@ -8632,7 +8667,6 @@
     const bool isHAUsed = isHearingAidUsedForComm();
 
     if (com_android_media_audio_replace_stream_bt_sco()) {
-        ALOGV("%s stream bt sco is replaced, no volume consistency check for calls", __func__);
         isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource) &&
                         (isScoRequested || isHAUsed);
         return true;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index e0cafd4..44863ee 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -134,17 +134,17 @@
         virtual status_t startOutput(audio_port_handle_t portId);
         virtual status_t stopOutput(audio_port_handle_t portId);
         virtual bool releaseOutput(audio_port_handle_t portId);
-        virtual status_t getInputForAttr(const audio_attributes_t *attr,
-                                         audio_io_handle_t *input,
+
+        base::expected<media::GetInputForAttrResponse, std::variant<binder::Status,
+            media::audio::common::AudioConfigBase>>
+                         getInputForAttr(audio_attributes_t attributes,
+                                         audio_io_handle_t requestedInput,
+                                         audio_port_handle_t requestedDeviceId,
+                                         audio_config_base_t config,
+                                         audio_input_flags_t flags,
                                          audio_unique_id_t riid,
                                          audio_session_t session,
-                                         const AttributionSourceState& attributionSource,
-                                         audio_config_base_t *config,
-                                         audio_input_flags_t flags,
-                                         audio_port_handle_t *selectedDeviceId,
-                                         input_type_t *inputType,
-                                         audio_port_handle_t *portId,
-                                         uint32_t *virtualDeviceId);
+                                         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);
@@ -1226,7 +1226,7 @@
         audio_io_handle_t getInputForDevice(const sp<DeviceDescriptor> &device,
                 audio_session_t session,
                 const audio_attributes_t &attributes,
-                audio_config_base_t *config,
+                const audio_config_base_t &config,
                 audio_input_flags_t flags,
                 const sp<AudioPolicyMix> &policyMix);
 
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index e157808..f415a41 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -11,16 +11,20 @@
 cc_defaults {
     name: "libaudiopolicyservice_dependencies",
 
+    defaults: [
+        "latest_android_media_audio_common_types_cpp_shared",
+    ],
+
     include_dirs: [
         "frameworks/av/services/audiopolicy", // include path outside of libaudiopolicyservice
     ],
 
     shared_libs: [
+        "android.media.audio-aconfig-cc",
         "android.media.audiopolicy-aconfig-cc",
         "audio-permission-aidl-cpp",
         "audioclient-types-aidl-cpp",
         "audioflinger-aidl-cpp",
-        "audiopermissioncontroller",
         "audiopolicy-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
@@ -32,6 +36,7 @@
         "libaudioclient_aidl_conversion",
         "libaudiofoundation",
         "libaudiohal",
+        "libaudiopermission",
         "libaudiopolicy",
         "libaudiopolicycomponents",
         "libaudiopolicymanagerdefault",
@@ -63,7 +68,6 @@
     name: "libaudiopolicyservice",
 
     defaults: [
-        "latest_android_media_audio_common_types_cpp_shared",
         "libaudiopolicyservice_dependencies",
     ],
 
@@ -114,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 3589de1..12320b7 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -23,6 +23,8 @@
 
 #include <android/content/AttributionSourceState.h>
 #include <android_media_audiopolicy.h>
+#include <android_media_audio.h>
+#include <binder/Enums.h>
 #include <com_android_media_audio.h>
 #include <cutils/properties.h>
 #include <error/expected_utils.h>
@@ -50,14 +52,18 @@
 #define CHECK_PERM(expr1, expr2) \
     VALUE_OR_RETURN_STATUS(getPermissionProvider().checkPermission((expr1), (expr2)))
 
+#define PROPAGATE_FALSEY(val) do { if (!val.has_value() || !val.value()) return val; } while (0)
+
 #define MAX_ITEMS_PER_LIST 1024
 
 namespace android {
 namespace audiopolicy_flags = android::media::audiopolicy;
 using binder::Status;
 using aidl_utils::binderStatusFromStatusT;
+using android::media::audio::concurrent_audio_record_bypass_permission;
 using com::android::media::audio::audioserver_permissions;
 using com::android::media::permission::NativePermissionController;
+using com::android::media::permission::PermissionEnum;
 using com::android::media::permission::PermissionEnum::ACCESS_ULTRASOUND;
 using com::android::media::permission::PermissionEnum::CALL_AUDIO_INTERCEPTION;
 using com::android::media::permission::PermissionEnum::CAPTURE_AUDIO_HOTWORD;
@@ -71,6 +77,7 @@
 using com::android::media::permission::PermissionEnum::MODIFY_PHONE_STATE;
 using com::android::media::permission::PermissionEnum::RECORD_AUDIO;
 using com::android::media::permission::PermissionEnum::WRITE_SECURE_SETTINGS;
+using com::android::media::permission::PermissionEnum::BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION;
 using content::AttributionSourceState;
 using media::audio::common::AudioConfig;
 using media::audio::common::AudioConfigBase;
@@ -80,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;
@@ -291,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));
@@ -323,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));
 
@@ -658,6 +663,137 @@
     mAudioPolicyManager->releaseOutput(portId);
 }
 
+// These are sources for which CAPTURE_AUDIO_OUTPUT granted access
+// for legacy reasons, before more specific permissions were deployed.
+// TODO: remove this access
+static bool isLegacyOutputSource(AudioSource source) {
+    switch (source) {
+        case AudioSource::VOICE_CALL:
+        case AudioSource::VOICE_DOWNLINK:
+        case AudioSource::VOICE_UPLINK:
+        case AudioSource::FM_TUNER:
+            return true;
+        default:
+            return false;
+    }
+}
+
+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 mAudioPolicyService->getPermissionProvider().checkPermission(perm, uid);
+    };
+    switch (req.source) {
+        case AudioSource::VOICE_UPLINK:
+        case AudioSource::VOICE_DOWNLINK:
+        case AudioSource::VOICE_CALL:
+            permRes = audioserver_permissions()
+                              ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
+                              : callAudioInterceptionAllowed(attrSource);
+            break;
+        case AudioSource::ECHO_REFERENCE:
+            permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
+                                                : captureAudioOutputAllowed(attrSource);
+            break;
+        case AudioSource::FM_TUNER:
+            permRes = audioserver_permissions()
+                              ? check_perm(CAPTURE_TUNER_AUDIO_INPUT, attrSource.uid)
+                              : captureTunerAudioInputAllowed(attrSource);
+            break;
+        case AudioSource::HOTWORD:
+            permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_HOTWORD, attrSource.uid)
+                                                : captureHotwordAllowed(attrSource);
+            break;
+        case AudioSource::ULTRASOUND:
+            permRes = audioserver_permissions() ? check_perm(ACCESS_ULTRASOUND, attrSource.uid)
+                                                : accessUltrasoundAllowed(attrSource);
+            break;
+        case AudioSource::SYS_RESERVED_INVALID:
+        case AudioSource::DEFAULT:
+        case AudioSource::MIC:
+        case AudioSource::CAMCORDER:
+        case AudioSource::VOICE_RECOGNITION:
+        case AudioSource::VOICE_COMMUNICATION:
+        case AudioSource::UNPROCESSED:
+        case AudioSource::VOICE_PERFORMANCE:
+            // No additional check intended
+        case AudioSource::REMOTE_SUBMIX:
+            // special-case checked based on mix type below
+            break;
+    }
+
+    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);
+        } else {
+            return false;
+        }
+    }
+
+    if (req.isHotword) {
+        permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_HOTWORD, attrSource.uid)
+                                            : captureHotwordAllowed(attrSource);
+        PROPAGATE_FALSEY(permRes);
+    }
+
+    // TODO evaluate whether we should be checking call redirection like this
+    bool isAllowedDueToCallPerm = false;
+    if (req.isCallRedir) {
+        const auto checkCall = audioserver_permissions()
+                                         ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
+                                         : callAudioInterceptionAllowed(attrSource);
+        isAllowedDueToCallPerm = VALUE_OR_RETURN(checkCall);
+    }
+
+    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
+            // TODO (b/378778313)
+            break;
+        case MixType::TELEPHONY_RX_CAPTURE:
+            if (isAllowedDueToCallPerm) break;
+            // FIXME: use the same permission as for remote submix for now.
+            FALLTHROUGH_INTENDED;
+        case MixType::CAPTURE:
+            permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
+                                                : captureAudioOutputAllowed(attrSource);
+            break;
+        case MixType::EXT_POLICY_REROUTE:
+            // TODO intended?
+            if (isAllowedDueToCallPerm) break;
+            permRes = audioserver_permissions() ? check_perm(MODIFY_AUDIO_ROUTING, attrSource.uid)
+                                                : modifyAudioRoutingAllowed(attrSource);
+            break;
+    }
+
+    PROPAGATE_FALSEY(permRes);
+
+    // 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;
+}
+
 Status AudioPolicyService::getInputForAttr(const media::audio::common::AudioAttributes& attrAidl,
                                            int32_t inputAidl,
                                            int32_t riidAidl,
@@ -667,23 +803,22 @@
                                            int32_t flagsAidl,
                                            int32_t selectedDeviceIdAidl,
                                            media::GetInputForAttrResponse* _aidl_return) {
-    audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+    auto inputSource = attrAidl.source;
+    const audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioAttributes_audio_attributes_t(attrAidl));
-    audio_io_handle_t input = VALUE_OR_RETURN_BINDER_STATUS(
+    const audio_io_handle_t requestedInput = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_int32_t_audio_io_handle_t(inputAidl));
-    audio_unique_id_t riid = VALUE_OR_RETURN_BINDER_STATUS(
+    const audio_unique_id_t riid = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_int32_t_audio_unique_id_t(riidAidl));
-    audio_session_t session = VALUE_OR_RETURN_BINDER_STATUS(
+    const audio_session_t session = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_int32_t_audio_session_t(sessionAidl));
-    audio_config_base_t config = VALUE_OR_RETURN_BINDER_STATUS(
+    const audio_config_base_t config = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioConfigBase_audio_config_base_t(configAidl, true /*isInput*/));
-    audio_input_flags_t flags = VALUE_OR_RETURN_BINDER_STATUS(
+    const audio_input_flags_t flags = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_int32_t_audio_input_flags_t_mask(flagsAidl));
-    audio_port_handle_t selectedDeviceId = VALUE_OR_RETURN_BINDER_STATUS(
+    const audio_port_handle_t requestedDeviceId = VALUE_OR_RETURN_BINDER_STATUS(
                 aidl2legacy_int32_t_audio_port_handle_t(selectedDeviceIdAidl));
 
-    audio_port_handle_t portId;
-
     if (mAudioPolicyManager == NULL) {
         return binderStatusFromStatusT(NO_INIT);
     }
@@ -691,208 +826,69 @@
     RETURN_IF_BINDER_ERROR(
             binderStatusFromStatusT(AudioValidator::validateAudioAttributes(attr, "68953950")));
 
-    audio_source_t inputSource = attr.source;
-    if (inputSource == AUDIO_SOURCE_DEFAULT) {
-        inputSource = AUDIO_SOURCE_MIC;
-    }
-
-    // already checked by client, but double-check in case the client wrapper is bypassed
-    if ((inputSource < AUDIO_SOURCE_DEFAULT)
-            || (inputSource >= AUDIO_SOURCE_CNT
-                && inputSource != AUDIO_SOURCE_HOTWORD
-                && inputSource != AUDIO_SOURCE_FM_TUNER
-                && inputSource != AUDIO_SOURCE_ECHO_REFERENCE
-                && inputSource != AUDIO_SOURCE_ULTRASOUND)) {
+    if (inputSource == AudioSource::SYS_RESERVED_INVALID ||
+            std::find(enum_range<AudioSource>().begin(), enum_range<AudioSource>().end(),
+                inputSource) == enum_range<AudioSource>().end()) {
         return binderStatusFromStatusT(BAD_VALUE);
     }
 
-    RETURN_IF_BINDER_ERROR(validateUsage(attr, attributionSource));
-
-    uint32_t virtualDeviceId = kDefaultVirtualDeviceId;
-
-    // check calling permissions.
-    // Capturing from the following sources does not require permission RECORD_AUDIO
-    // as the captured audio does not come from a microphone:
-    // - FM_TUNER source is controlled by captureTunerAudioInputAllowed() or
-    // captureAudioOutputAllowed() (deprecated).
-    // - REMOTE_SUBMIX source is controlled by captureAudioOutputAllowed() if the input
-    // type is API_INPUT_MIX_EXT_POLICY_REROUTE and by AudioService if a media projection
-    // is used and input type is API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK
-    // - ECHO_REFERENCE source is controlled by captureAudioOutputAllowed()
-    const auto isRecordingAllowed = audioserver_permissions() ?
-            CHECK_PERM(RECORD_AUDIO, attributionSource.uid) :
-            recordingAllowed(attributionSource, inputSource);
-    if (!(isRecordingAllowed
-            || inputSource == AUDIO_SOURCE_FM_TUNER
-            || inputSource == AUDIO_SOURCE_REMOTE_SUBMIX
-            || inputSource == AUDIO_SOURCE_ECHO_REFERENCE)) {
-        ALOGE("%s permission denied: recording not allowed for %s",
-                __func__, attributionSource.toString().c_str());
-        return binderStatusFromStatusT(PERMISSION_DENIED);
+    if (inputSource == AudioSource::DEFAULT) {
+        inputSource = AudioSource::MIC;
     }
 
-    bool canCaptureOutput = audioserver_permissions() ?
-                        CHECK_PERM(CAPTURE_AUDIO_OUTPUT, attributionSource.uid)
-                        : captureAudioOutputAllowed(attributionSource);
-    bool canInterceptCallAudio = audioserver_permissions() ?
-                        CHECK_PERM(CALL_AUDIO_INTERCEPTION, attributionSource.uid)
-                        : callAudioInterceptionAllowed(attributionSource);
-    bool isCallAudioSource = inputSource == AUDIO_SOURCE_VOICE_UPLINK
-             || inputSource == AUDIO_SOURCE_VOICE_DOWNLINK
-             || inputSource == AUDIO_SOURCE_VOICE_CALL;
+    const bool isCallRedir = (attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0;
 
-    if (isCallAudioSource && !canInterceptCallAudio && !canCaptureOutput) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-    if (inputSource == AUDIO_SOURCE_ECHO_REFERENCE
-            && !canCaptureOutput) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-    if (inputSource == AUDIO_SOURCE_FM_TUNER
-        && !canCaptureOutput
-        && !(audioserver_permissions() ?
-                        CHECK_PERM(CAPTURE_TUNER_AUDIO_INPUT, attributionSource.uid)
-            : captureTunerAudioInputAllowed(attributionSource))) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
+    //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 = 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,
+                                       attributionSource.uid)
+                            : bypassConcurrentPolicyAllowed(attributionSource);
     }
 
-    bool canCaptureHotword = audioserver_permissions() ?
-                        CHECK_PERM(CAPTURE_AUDIO_HOTWORD, attributionSource.uid)
-                        : captureHotwordAllowed(attributionSource);
-    if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-
-    if (((flags & (AUDIO_INPUT_FLAG_HW_HOTWORD |
-                        AUDIO_INPUT_FLAG_HOTWORD_TAP |
-                        AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0)
-            && !canCaptureHotword) {
-        ALOGE("%s: permission denied: hotword mode not allowed"
-              " for uid %d pid %d", __func__, attributionSource.uid, attributionSource.pid);
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-
-    if (attr.source == AUDIO_SOURCE_ULTRASOUND) {
-        if (!(audioserver_permissions() ?
-                CHECK_PERM(ACCESS_ULTRASOUND, attributionSource.uid)
-                : accessUltrasoundAllowed(attributionSource))) {
-            ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
-                    __func__, attributionSource.uid, attributionSource.pid);
-            return binderStatusFromStatusT(PERMISSION_DENIED);
-        }
-    }
-
-    sp<AudioPolicyEffects>audioPolicyEffects;
+    sp<AudioPolicyEffects> audioPolicyEffects;
+    base::expected<media::GetInputForAttrResponse, std::variant<binder::Status, AudioConfigBase>>
+            res;
     {
-        status_t status;
-        AudioPolicyInterface::input_type_t inputType;
-
         audio_utils::lock_guard _l(mMutex);
-        {
-            AutoCallerClear acc;
-            // the audio_in_acoustics_t parameter is ignored by get_input()
-            status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
-                                                          attributionSource, &config,
-                                                          flags, &selectedDeviceId,
-                                                          &inputType, &portId,
-                                                          &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());
+                return Status::fromExceptionCode(EX_ILLEGAL_STATE);
+            } else {
+                return std::get<0>(res.error());
+            }
         }
+
         audioPolicyEffects = mAudioPolicyEffects;
 
-        if (status == NO_ERROR) {
-            // enforce permission (if any) required for each type of input
-            switch (inputType) {
-            case AudioPolicyInterface::API_INPUT_MIX_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:
-                break;
-            case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
-                if ((attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0
-                        && canInterceptCallAudio) {
-                    break;
-                }
-                // FIXME: use the same permission as for remote submix for now.
-                FALLTHROUGH_INTENDED;
-            case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
-                if (!canCaptureOutput) {
-                    ALOGE("%s permission denied: capture not allowed", __func__);
-                    status = PERMISSION_DENIED;
-                }
-                break;
-            case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: {
-                bool modAudioRoutingAllowed;
-                if (audioserver_permissions()) {
-                        auto result = getPermissionProvider().checkPermission(
-                                MODIFY_AUDIO_ROUTING, attributionSource.uid);
-                        if (!result.ok()) {
-                            ALOGE("%s permission provider error: %s", __func__,
-                                    result.error().toString8().c_str());
-                            status = aidl_utils::statusTFromBinderStatus(result.error());
-                            break;
-                        }
-                        modAudioRoutingAllowed = result.value();
-                } else {
-                    modAudioRoutingAllowed = modifyAudioRoutingAllowed(attributionSource);
-                }
-                if (!(modAudioRoutingAllowed
-                        || ((attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0
-                            && canInterceptCallAudio))) {
-                    ALOGE("%s permission denied for remote submix capture", __func__);
-                    status = PERMISSION_DENIED;
-                }
-                break;
-            }
-            case AudioPolicyInterface::API_INPUT_INVALID:
-            default:
-                LOG_ALWAYS_FATAL("%s encountered an invalid input type %d",
-                        __func__, (int)inputType);
-            }
-
-            if (audiopolicy_flags::record_audio_device_aware_permission()) {
-                // enforce device-aware RECORD_AUDIO permission
-                if (virtualDeviceId != kDefaultVirtualDeviceId &&
-                    !recordingAllowed(attributionSource, virtualDeviceId, inputSource)) {
-                    status = PERMISSION_DENIED;
-                }
-            }
-        }
-
-        if (status != NO_ERROR) {
-            if (status == PERMISSION_DENIED) {
-                AutoCallerClear acc;
-                mAudioPolicyManager->releaseInput(portId);
-            } else {
-                _aidl_return->config = VALUE_OR_RETURN_BINDER_STATUS(
-                        legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
-            }
-            return binderStatusFromStatusT(status);
-        }
-
-        DeviceIdVector selectedDeviceIds = { selectedDeviceId };
-        sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
-                                                             selectedDeviceIds, attributionSource,
-                                                             virtualDeviceId,
-                                                             canCaptureOutput, canCaptureHotword,
-                                                             mOutputCommandThread);
-        mAudioRecordClients.add(portId, client);
+        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(input, inputSource, session);
+        status_t status = audioPolicyEffects->addInputEffects(res->input,
+                aidl2legacy_AudioSource_audio_source_t(inputSource).value(), session);
         if (status != NO_ERROR && status != ALREADY_EXISTS) {
-            ALOGW("Failed to add effects on input %d", input);
+            ALOGW("Failed to add effects on input %d", res->input);
         }
     }
 
-    _aidl_return->input = VALUE_OR_RETURN_BINDER_STATUS(
-            legacy2aidl_audio_io_handle_t_int32_t(input));
-    _aidl_return->selectedDeviceId = VALUE_OR_RETURN_BINDER_STATUS(
-            legacy2aidl_audio_port_handle_t_int32_t(selectedDeviceId));
-    _aidl_return->portId = VALUE_OR_RETURN_BINDER_STATUS(
-            legacy2aidl_audio_port_handle_t_int32_t(portId));
+    *_aidl_return = res.value();
+
     return Status::ok();
 }
 
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 80ee34e..4c506e8 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -853,13 +853,13 @@
 //               AND an accessibility service is TOP
 //                  AND source is either VOICE_RECOGNITION OR HOTWORD
 //               OR there is no active privacy sensitive capture or call
-//                          OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+//                          OR client can capture calls
 //                  AND source is VOICE_RECOGNITION OR HOTWORD
 //    The client is an assistant AND active assistant is not being used
 //        AND an accessibility service is on TOP or a RTT call is active
 //                AND the source is VOICE_RECOGNITION or HOTWORD
 //        OR there is no active privacy sensitive capture or call
-//                OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+//                OR client can capture calls
 //            AND is TOP most recent assistant and uses VOICE_RECOGNITION or HOTWORD
 //                OR there is no top recent assistant and source is HOTWORD
 //    OR The client is an accessibility service
@@ -867,7 +867,7 @@
 //                AND the source is VOICE_RECOGNITION or HOTWORD
 //            OR The assistant is not on TOP
 //                AND there is no active privacy sensitive capture or call
-//                    OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+//                    OR client can capture calls
 //        AND is on TOP
 //        AND the source is VOICE_RECOGNITION or HOTWORD
 //    OR the client source is virtual (remote submix, call audio TX or RX...)
@@ -875,7 +875,7 @@
 //        AND is on TOP
 //            OR all active clients are using HOTWORD source
 //        AND no call is active
-//            OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+//            OR client can capture calls
 //    OR the client is the current InputMethodService
 //        AND a RTT call is active AND the source is VOICE_RECOGNITION
 //    OR The client is an active communication owner
@@ -884,7 +884,11 @@
 //        AND The assistant is not on TOP
 //        AND is on TOP or latest started
 //        AND there is no active privacy sensitive capture or call
-//            OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+//            OR client can capture calls
+//    NOTE: a client can capture calls if it either:
+//       has CAPTURE_AUDIO_OUTPUT privileged permission (temporarily until
+//            all system apps are updated)
+//       or has CONCURRENT_AUDIO_RECORD_BYPASS privileged permission
 
 
     sp<AudioRecordClient> topActive;
@@ -1024,7 +1028,7 @@
     //  else
     //    favor the privacy sensitive case
     if (topActive != nullptr && topSensitiveActive != nullptr
-            && !topActive->canCaptureOutput) {
+            && !topActive->canBypassConcurrentPolicy) {
         topActive = nullptr;
     }
 
@@ -1055,8 +1059,8 @@
                                                                mMutex) {
             uid_t recordUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
                 recordClient->attributionSource.uid));
-            bool canCaptureCall = recordClient->canCaptureOutput;
-            bool canCaptureCommunication = recordClient->canCaptureOutput
+            bool canCaptureCall = recordClient->canBypassConcurrentPolicy;
+            bool canCaptureCommunication = recordClient->canBypassConcurrentPolicy
                 || !isPhoneStateOwnerActive
                 || recordUid == mPhoneStateOwnerUid;
             return !(isInCall && !canCaptureCall)
@@ -1072,7 +1076,7 @@
         //         AND is ongoing communication owner
         //         AND is on TOP or latest started
         const bool allowSensitiveCapture =
-            !isSensitiveActive || isTopOrLatestSensitive || current->canCaptureOutput;
+            !isSensitiveActive || isTopOrLatestSensitive || current->canBypassConcurrentPolicy;
         bool allowCapture = false;
         if (!isAssistantOnTop || isActiveAssistant) {
             allowCapture = (isTopOrLatestActive || isTopOrLatestSensitive) &&
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index eeac9a6..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,
@@ -960,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 76bc17a..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;
@@ -90,14 +90,13 @@
                       const DeviceIdVector deviceIds,
                       const AttributionSourceState& attributionSource,
                       const uint32_t virtualDeviceId,
-                      bool canCaptureOutput, bool canCaptureHotword,
+                      bool canBypassConcurrentPolicy,
                       wp<AudioPolicyService::AudioCommandThread> commandThread) :
                 AudioClient(attributes, io, attributionSource,
                     session, portId, deviceIds), attributionSource(attributionSource),
                     virtualDeviceId(virtualDeviceId),
-                    startTimeNs(0), canCaptureOutput(canCaptureOutput),
-                    canCaptureHotword(canCaptureHotword), silenced(false),
-                    mOpRecordAudioMonitor(
+                    startTimeNs(0), canBypassConcurrentPolicy(canBypassConcurrentPolicy),
+                    silenced(false), mOpRecordAudioMonitor(
                             OpRecordAudioMonitor::createIfNeeded(attributionSource,
                                                                  virtualDeviceId,
                                                                  attributes, commandThread)) {
@@ -112,8 +111,7 @@
     const AttributionSourceState attributionSource; // attribution source of client
     const uint32_t virtualDeviceId; // id of the virtual device associated with the audio device
     nsecs_t startTimeNs;
-    const bool canCaptureOutput;
-    const bool canCaptureHotword;
+    const bool canBypassConcurrentPolicy;
     bool silenced;
 
 private:
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 182dc61..a6e5c75 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -21,6 +21,7 @@
     ],
 
     shared_libs: [
+        "audiopolicy-aidl-cpp",
         "framework-permission-aidl-cpp",
         "libaudioclient",
         "libaudiofoundation",
@@ -32,6 +33,7 @@
         "libhidlbase",
         "liblog",
         "libmedia_helper",
+        "libstagefright_foundation",
         "libutils",
         "libxml2",
         "server_configurable_flags",
@@ -42,6 +44,7 @@
         "audioclient-types-aidl-cpp",
         "com.android.media.audio-aconfig-cc",
         "com.android.media.audioserver-aconfig-cc",
+        "libaudio_aidl_conversion_common_cpp",
         "libaudiopolicycomponents",
         "libflagtest",
         "libgmock",
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 f8f91fc..a8f79c3 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -97,13 +97,6 @@
     attributionSourceState.token = sp<BBinder>::make();
     return attributionSourceState;
 }
-
-bool equals(const audio_config_base_t& config1, const audio_config_base_t& config2) {
-    return config1.format == config2.format
-            && config1.sample_rate == config2.sample_rate
-            && config1.channel_mask == config2.channel_mask;
-}
-
 } // namespace
 
 TEST(AudioPolicyConfigTest, DefaultConfigForTestsIsEmpty) {
@@ -341,12 +334,15 @@
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
     if (!virtualDeviceId) virtualDeviceId = 0;
-    AudioPolicyInterface::input_type_t inputType;
     AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
-    ASSERT_EQ(OK, mManager->getInputForAttr(
-            &attr, input, riid, session, attributionSource, &config, flags,
-            selectedDeviceId, &inputType, portId, virtualDeviceId));
-    ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+    auto inputRes = mManager->getInputForAttr(attr, *input, *selectedDeviceId,
+        config, flags, riid, session, attributionSource);
+    ASSERT_TRUE(inputRes.has_value());
+    ASSERT_NE(inputRes->portId, AUDIO_PORT_HANDLE_NONE);
+    *input = inputRes->input;
+    if (selectedDeviceId != nullptr) *selectedDeviceId = inputRes->selectedDeviceId;
+    *portId = inputRes->portId;
+    if (virtualDeviceId != nullptr) *virtualDeviceId = inputRes->virtualDeviceId;
 }
 
 void AudioPolicyManagerTest::getAudioPorts(audio_port_type_t type, audio_port_role_t role,
@@ -1231,40 +1227,39 @@
                                                            AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                                            "", "", AUDIO_FORMAT_DEFAULT));
 
-    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    const audio_port_handle_t requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    const audio_io_handle_t requestedInput = AUDIO_PORT_HANDLE_NONE;
+    const AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
+    AudioPolicyInterface::input_type_t inputType;
+
     audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
                                AUDIO_SOURCE_VOICE_COMMUNICATION,AUDIO_FLAG_NONE, ""};
-    AudioPolicyInterface::input_type_t inputType;
-    audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
-    AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
     audio_config_base_t requestedConfig = {
             .sample_rate = k48000SamplingRate,
             .channel_mask = AUDIO_CHANNEL_IN_STEREO,
             .format = AUDIO_FORMAT_PCM_16_BIT,
     };
-    audio_config_base_t config = requestedConfig;
-    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
-    uint32_t *virtualDeviceId = 0;
-    ASSERT_EQ(OK, mManager->getInputForAttr(
-            &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
-            AUDIO_INPUT_FLAG_NONE,
-            &selectedDeviceId, &inputType, &portId, virtualDeviceId));
-    ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
-    ASSERT_TRUE(equals(requestedConfig, config));
+    auto inputRes = mManager->getInputForAttr(attr, requestedInput, requestedDeviceId,
+                                              requestedConfig, AUDIO_INPUT_FLAG_NONE, 1 /*riid*/,
+                                              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(
+                               requestedConfig, true /* isInput */)),
+                       inputRes->config);
 
     attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
             AUDIO_SOURCE_VOICE_COMMUNICATION, AUDIO_FLAG_NONE, ""};
     requestedConfig.channel_mask = deviceChannelMask;
-    config = requestedConfig;
-    selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
-    input = AUDIO_PORT_HANDLE_NONE;
-    portId = AUDIO_PORT_HANDLE_NONE;
-    ASSERT_EQ(OK, mManager->getInputForAttr(
-            &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
-            AUDIO_INPUT_FLAG_NONE,
-            &selectedDeviceId, &inputType, &portId, virtualDeviceId));
-    ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
-    ASSERT_TRUE(equals(requestedConfig, config));
+
+    inputRes = mManager->getInputForAttr(attr, requestedInput, requestedDeviceId, requestedConfig,
+                                         AUDIO_INPUT_FLAG_NONE, 1 /*riid*/, 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(requestedConfig,
+                                                                             true /* isInput */)),
+              inputRes->config);
 
     ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_IN_USB_DEVICE,
                                                            AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index b9c8206..b44f949 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -87,7 +87,9 @@
         "android.hardware.camera.device@3.6",
         "android.hardware.camera.device@3.7",
         "android.hardware.common-V2-ndk",
+        "android.hardware.common-V2-cpp",
         "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.common.fmq-V1-cpp",
         "camera_platform_flags_c_lib",
         "com.android.window.flags.window-aconfig_flags_c_lib",
         "media_permission-aidl-cpp",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index df94478..fdb5b7d 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1492,6 +1492,7 @@
         int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
         apiLevel effectiveApiLevel, bool overrideForPerfClass, int rotationOverride,
         bool forceSlowJpegMode, const std::string& originalCameraId, bool sharedMode,
+        bool isVendorClient,
         /*out*/sp<BasicClient>* client) {
     // For HIDL devices
     if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
@@ -1537,7 +1538,8 @@
                 cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
                 cameraService->mAttributionAndPermissionUtils, clientAttribution, callingPid,
                 systemNativeClient, cameraId, facing, sensorOrientation, servicePid,
-                overrideForPerfClass, rotationOverride, originalCameraId, sharedMode);
+                overrideForPerfClass, rotationOverride, originalCameraId, sharedMode,
+                isVendorClient);
         ALOGI("%s: Camera2 API, rotationOverride %d", __FUNCTION__, rotationOverride);
     }
     return Status::ok();
@@ -1638,7 +1640,7 @@
                   /*rotationOverride*/
                   hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
                   /*forceSlowJpegMode*/ false, cameraIdStr, /*isNonSystemNdk*/ false,
-                  /*sharedMode*/false, /*out*/ tmp))
+                  /*sharedMode*/false, /*isVendorClient*/false,/*out*/ tmp))
                  .isOk()) {
         ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().c_str());
     }
@@ -2202,7 +2204,8 @@
             cameraClient, cameraIdStr, api1CameraId, resolvedClientAttribution,
             /*systemNativeClient*/ false, API_1,
             /*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion, rotationOverride,
-            forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*sharedMode*/false, /*out*/ client);
+            forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*sharedMode*/false,
+            /*isVendorClient*/ false, /*out*/ client);
 
     if (!ret.isOk()) {
         logRejected(cameraIdStr, getCallingPid(),
@@ -2286,7 +2289,32 @@
         const std::string& unresolvedCameraId,
         int oomScoreOffset, int targetSdkVersion,
         int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
-        bool sharedMode, /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+        bool sharedMode,
+        /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+    return connectDeviceImpl(cameraCb, unresolvedCameraId, oomScoreOffset, targetSdkVersion,
+            rotationOverride, clientAttribution, devicePolicy, sharedMode,
+            /*isVendorClient*/false, device);
+}
+
+Status CameraService::connectDeviceVendor(
+        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+        const std::string& unresolvedCameraId,
+        int oomScoreOffset, int targetSdkVersion,
+        int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
+        bool sharedMode,
+        /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+            return connectDeviceImpl(cameraCb, unresolvedCameraId, oomScoreOffset, targetSdkVersion,
+                    rotationOverride, clientAttribution, devicePolicy, sharedMode,
+                    /*isVendorClient*/true, device);
+}
+
+Status CameraService::connectDeviceImpl(
+        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+        const std::string& unresolvedCameraId,
+        int oomScoreOffset, int targetSdkVersion,
+        int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
+        bool sharedMode, bool isVendorClient,
+        /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
     ATRACE_CALL();
     RunThreadWithRealtimePriority priorityBump;
     Status ret = Status::ok();
@@ -2367,7 +2395,7 @@
             cameraCb, cameraId, /*api1CameraId*/ -1, resolvedClientAttribution, systemNativeClient,
             API_2, /*shimUpdateOnly*/ false, oomScoreOffset, targetSdkVersion, rotationOverride,
             /*forceSlowJpegMode*/ false, unresolvedCameraId, isNonSystemNdk, sharedMode,
-            /*out*/ client);
+            isVendorClient, /*out*/ client);
 
     if (!ret.isOk()) {
         logRejected(cameraId, clientPid, clientPackageName, toStdString(ret.toString8()));
@@ -2447,7 +2475,8 @@
                                     bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
                                     int rotationOverride, bool forceSlowJpegMode,
                                     const std::string& originalCameraId, bool isNonSystemNdk,
-                                    bool sharedMode, /*out*/ sp<CLIENT>& device) {
+                                    bool sharedMode, bool isVendorClient,
+                                    /*out*/ sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
 
     nsecs_t openTimeNs = systemTime();
@@ -2546,7 +2575,7 @@
                                systemNativeClient, cameraId, api1CameraId, facing, orientation,
                                getpid(), deviceVersionAndTransport, effectiveApiLevel,
                                overrideForPerfClass, rotationOverride, forceSlowJpegMode,
-                               originalCameraId, sharedMode,
+                               originalCameraId, sharedMode, isVendorClient,
                                /*out*/ &tmp))
                      .isOk()) {
             return ret;
@@ -3811,14 +3840,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..c4d2d67 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -280,6 +280,14 @@
             std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false,
             bool isProcessLocalTest = false);
 
+    binder::Status  connectDeviceVendor(
+            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+            const std::string& cameraId, int scoreOffset, int targetSdkVersion,
+            int rotationOverride, const AttributionSourceState& clientAttribution,
+            int32_t devicePolicy, bool sharedMode,
+            /*out*/
+            sp<hardware::camera2::ICameraDeviceUser>* device);
+
     // Monitored UIDs availability notification
     void                notifyMonitoredUids();
     void                notifyMonitoredUids(const std::unordered_set<uid_t> &notifyUidSet);
@@ -631,6 +639,9 @@
         CameraClientManager();
         virtual ~CameraClientManager();
 
+        // Bring all remove() functions into scope
+        using ClientManager::remove;
+
         virtual void remove(const DescriptorPtr& value) override;
 
         /**
@@ -993,7 +1004,16 @@
                                  bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
                                  int rotationOverride, bool forceSlowJpegMode,
                                  const std::string& originalCameraId, bool isNonSystemNdk,
-                                 bool sharedMode, /*out*/ sp<CLIENT>& device);
+                                 bool sharedMode, bool isVendorClient,
+                                 /*out*/ sp<CLIENT>& device);
+
+    binder::Status connectDeviceImpl(
+            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+            const std::string& cameraId, int scoreOffset, int targetSdkVersion,
+            int rotationOverride, const AttributionSourceState& clientAttribution,
+            int32_t devicePolicy, bool sharedMode, bool isVendorClient,
+            /*out*/
+            sp<hardware::camera2::ICameraDeviceUser>* device);
 
     // Lock guarding camera service state
     Mutex               mServiceLock;
@@ -1490,6 +1510,7 @@
                                      apiLevel effectiveApiLevel, bool overrideForPerfClass,
                                      int rotationOverride, bool forceSlowJpegMode,
                                      const std::string& originalCameraId, bool sharedMode,
+                                     bool isVendorClient,
                                      /*out*/ sp<BasicClient>* client);
 
     static std::string toString(std::set<userid_t> intSet);
diff --git a/services/camera/libcameraservice/FwkOnlyMetadataTags.h b/services/camera/libcameraservice/FwkOnlyMetadataTags.h
new file mode 100644
index 0000000..768afeb
--- /dev/null
+++ b/services/camera/libcameraservice/FwkOnlyMetadataTags.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#pragma once
+
+/**
+ * ! Do not edit this file directly !
+ *
+ * Generated automatically from fwk_only_metadata_tags.mako. To be included in libcameraservice
+ * only by Camera3Device.cpp.
+ */
+
+namespace android {
+
+/**
+ * Framework only CaptureRequest keys. To be used for filtering out keys in CaptureRequest
+ * before sending to the HAL.
+ */
+constexpr std::array kFwkOnlyMetadataKeys = {
+        ANDROID_CONTROL_AF_REGIONS_SET,
+        ANDROID_CONTROL_AE_REGIONS_SET,
+        ANDROID_CONTROL_AWB_REGIONS_SET,
+        ANDROID_CONTROL_ZOOM_METHOD,
+        ANDROID_SCALER_CROP_REGION_SET,
+        ANDROID_EXTENSION_STRENGTH,
+};
+
+} //namespace android
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
index 70647b4..950ea05 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
@@ -174,11 +174,19 @@
 }
 
 binder::Status AidlCameraDeviceCallbacks::onResultReceived(
-    const CameraMetadataNative& result,
+    const CameraMetadataInfo &resultInfo,
     const UCaptureResultExtras& resultExtras,
     const ::std::vector<UPhysicalCaptureResultInfo>& physicalCaptureResultInfos) {
     // Wrap CameraMetadata, resultExtras and physicalCaptureResultInfos in on
     // sp<RefBase>-able structure and post it.
+    // We modify metadata - since we want to filter out tags based on the vndk
+    // version, and also this communication is an in process function call.
+    // So we don't use FMQ for the shim layer. FMQ is still used for VNDK IPC.
+    if (resultInfo.getTag() != CameraMetadataInfo::metadata) {
+        ALOGE("Vendor callbacks got metadata in fmq ? ");
+        return binder::Status::ok();
+    }
+    const CameraMetadataNative &result = resultInfo.get<CameraMetadataInfo::metadata>();
     sp<ResultWrapper> resultWrapper = new ResultWrapper(const_cast<CameraMetadataNative &>(result),
                                                         resultExtras, physicalCaptureResultInfos);
     sp<AMessage> msg = new AMessage(kWhatResultReceived, mHandler);
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
index 07bf7d8..6504cdc 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
@@ -46,6 +46,7 @@
 using ::android::frameworks::cameraservice::utils::DeathPipe;
 using ::android::hardware::camera2::impl::CameraMetadataNative;
 
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 using CaptureResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
 
 class AidlCameraDeviceCallbacks : public UBnCameraDeviceCallbacks {
@@ -65,7 +66,8 @@
                                     int64_t timestamp) override;
 
     binder::Status onResultReceived(
-            const CameraMetadataNative& result, const CaptureResultExtras& resultExtras,
+            const CameraMetadataInfo &resultInfo,
+            const CaptureResultExtras& resultExtras,
             const std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
 
     binder::Status onPrepared(int32_t streamId) override;
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.cpp b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
index a2c431e..46e2280 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraService.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
@@ -177,7 +177,7 @@
                     kDefaultDeviceId);
     clientAttribution.packageName = "";
     clientAttribution.attributionTag = std::nullopt;
-    binder::Status serviceRet = mCameraService->connectDevice(
+    binder::Status serviceRet = mCameraService->connectDeviceVendor(
             callbacks,
             in_cameraId,
             /* scoreOffset= */ 0,
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.cpp b/services/camera/libcameraservice/aidl/AidlUtils.cpp
index 1ec5072..7f927f1 100644
--- a/services/camera/libcameraservice/aidl/AidlUtils.cpp
+++ b/services/camera/libcameraservice/aidl/AidlUtils.cpp
@@ -24,6 +24,7 @@
 #include <aidlcommonsupport/NativeHandle.h>
 #include <camera/StringUtils.h>
 #include <device3/Camera3StreamInterface.h>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <mediautils/AImageReaderUtils.h>
 #include "utils/Utils.h"
@@ -32,6 +33,7 @@
 
 using aimg::AImageReader_getHGBPFromHandle;
 using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 
 // Note: existing data in dst will be gone. Caller still owns the memory of src
 void cloneToAidl(const camera_metadata_t* src, SCameraMetadata* dst) {
@@ -76,20 +78,25 @@
 }
 
 UOutputConfiguration convertFromAidl(const SOutputConfiguration &src) {
-    std::vector<sp<IGraphicBufferProducer>> iGBPs;
+    std::vector<ParcelableSurfaceType> pSurfaces;
     if (!src.surfaces.empty()) {
         auto& surfaces = src.surfaces;
-        iGBPs.reserve(surfaces.size());
+        pSurfaces.reserve(surfaces.size());
 
         for (auto& sSurface : surfaces) {
-            sp<IGraphicBufferProducer> igbp =
-                    Surface::getIGraphicBufferProducer(sSurface.get());
-            if (igbp == nullptr) {
-                ALOGE("%s: ANativeWindow (%p) not backed by a Surface.",
-                      __FUNCTION__, sSurface.get());
+            ParcelableSurfaceType pSurface;
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+            pSurface.graphicBufferProducer = Surface::getIGraphicBufferProducer(sSurface.get());
+            if (pSurface.isEmpty()) {
+#else
+            pSurface = Surface::getIGraphicBufferProducer(sSurface.get());
+            if (pSurface == nullptr) {
+#endif
+                ALOGE("%s: ANativeWindow (%p) not backed by a Surface.", __FUNCTION__,
+                      sSurface.get());
                 continue;
             }
-            iGBPs.push_back(igbp);
+            pSurfaces.push_back(pSurface);
         }
     } else {
 #pragma clang diagnostic push
@@ -100,7 +107,7 @@
         auto &windowHandles = src.windowHandles;
 #pragma clang diagnostic pop
 
-        iGBPs.reserve(windowHandles.size());
+        pSurfaces.reserve(windowHandles.size());
 
         for (auto &handle : windowHandles) {
             native_handle_t* nh = makeFromAidl(handle);
@@ -111,15 +118,20 @@
                 continue;
             }
 
-            iGBPs.push_back(new H2BGraphicBufferProducer(igbp));
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+            view::Surface viewSurface;
+            viewSurface.graphicBufferProducer = new H2BGraphicBufferProducer(igbp);
+            pSurfaces.push_back(viewSurface);
+#else
+            pSurfaces.push_back(new H2BGraphicBufferProducer(igbp));
+#endif
             native_handle_delete(nh);
         }
     }
 
     UOutputConfiguration outputConfiguration(
-        iGBPs, convertFromAidl(src.rotation), src.physicalCameraId,
-        src.windowGroupId, OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0,
-        (iGBPs.size() > 1));
+            pSurfaces, convertFromAidl(src.rotation), src.physicalCameraId, src.windowGroupId,
+            OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0, (pSurfaces.size() > 1));
     return outputConfiguration;
 }
 
@@ -254,7 +266,8 @@
     SPhysicalCaptureResultInfo dst;
     dst.physicalCameraId = src.mPhysicalCameraId;
 
-    const camera_metadata_t *rawMetadata = src.mPhysicalCameraMetadata.getAndLock();
+    const camera_metadata_t *rawMetadata =
+            src.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().getAndLock();
     // Try using fmq at first.
     size_t metadata_size = get_camera_metadata_size(rawMetadata);
     if ((metadata_size > 0) && (fmq->availableToWrite() > 0)) {
@@ -267,7 +280,7 @@
             dst.physicalCameraMetadata.set<SCaptureMetadataInfo::metadata>(std::move(metadata));
         }
     }
-    src.mPhysicalCameraMetadata.unlock(rawMetadata);
+    src.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().unlock(rawMetadata);
     return dst;
 }
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 1d29462..9b916bf 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -73,6 +73,7 @@
                         overrideForPerfClass, rotationOverride, sharedMode,
                         /*legacyClient*/ true),
       mParameters(api1CameraId, cameraFacing),
+      mInitialized(false),
       mLatestRequestIds(kMaxRequestIds),
       mLatestFailedRequestIds(kMaxRequestIds) {
     ATRACE_CALL();
@@ -194,6 +195,7 @@
         ALOGD("%s", l.mParameters.paramsFlattened.c_str());
     }
 
+    mInitialized = true;
     return OK;
 }
 
@@ -1040,6 +1042,12 @@
 
 void Camera2Client::stopPreviewL() {
     ATRACE_CALL();
+
+    if (!mInitialized) {
+        // If we haven't initialized yet, there's no stream to stop (b/379558387)
+        return;
+    }
+
     status_t res;
     const nsecs_t kStopCaptureTimeout = 3000000000LL; // 3 seconds
     Parameters::State state;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 51d8d54..a90e8cc 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
 #define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
 
+#include <atomic>
+
 #include <gui/Flags.h>
 #include <gui/view/Surface.h>
 #include <media/RingBuffer.h>
@@ -236,6 +238,8 @@
     sp<camera2::JpegProcessor> mJpegProcessor;
     sp<camera2::ZslProcessor> mZslProcessor;
 
+    std::atomic<bool> mInitialized;
+
     /** Utility members */
     bool mLegacyMode;
 
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 8c30d54..5bcb8e8 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -16,17 +16,22 @@
 
 #define LOG_TAG "CameraDeviceClient"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
 //#define LOG_NDEBUG 0
 
+#include <camera/CameraUtils.h>
+#include <camera/StringUtils.h>
+#include <camera/camera2/CaptureRequest.h>
 #include <com_android_internal_camera_flags.h>
 #include <cutils/properties.h>
+#include <gui/Surface.h>
 #include <utils/Log.h>
 #include <utils/SessionConfigurationUtils.h>
 #include <utils/Trace.h>
-#include <gui/Surface.h>
-#include <camera/camera2/CaptureRequest.h>
-#include <camera/CameraUtils.h>
-#include <camera/StringUtils.h>
 
 #include "common/CameraDeviceBase.h"
 #include "device3/Camera3Device.h"
@@ -40,6 +45,7 @@
 #include "JpegRCompositeStream.h"
 
 // Convenience methods for constructing binder::Status objects for error returns
+constexpr int32_t METADATA_QUEUE_SIZE = 1 << 20;
 
 #define STATUS_ERROR(errorCode, errorString) \
     binder::Status::fromServiceSpecificError(errorCode, \
@@ -80,7 +86,7 @@
         const AttributionSourceState& clientAttribution, int callingPid, bool systemNativeClient,
         const std::string& cameraId, int cameraFacing, int sensorOrientation, int servicePid,
         bool overrideForPerfClass, int rotationOverride, const std::string& originalCameraId,
-        bool sharedMode)
+        bool sharedMode, bool isVendorClient)
     : Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper,
                         attributionAndPermissionUtils, clientAttribution, callingPid,
                         systemNativeClient, cameraId, /*API1 camera ID*/ -1, cameraFacing,
@@ -90,7 +96,8 @@
       mStreamingRequestId(REQUEST_ID_NONE),
       mRequestIdCounter(0),
       mOverrideForPerfClass(overrideForPerfClass),
-      mOriginalCameraId(originalCameraId) {
+      mOriginalCameraId(originalCameraId),
+      mIsVendorClient(isVendorClient) {
     ATRACE_CALL();
     ALOGI("CameraDeviceClient %s: Opened", cameraId.c_str());
 }
@@ -180,6 +187,14 @@
             mHighResolutionSensors.insert(physicalId);
         }
     }
+    int32_t resultMQSize =
+            property_get_int32("ro.vendor.camera.res.fmq.size", /*default*/METADATA_QUEUE_SIZE);
+    res = CreateMetadataQueue(&mResultMetadataQueue, resultMQSize);
+    if (res != OK) {
+        ALOGE("%s: Creating result metadata queue failed: %s(%d)", __FUNCTION__,
+            strerror(-res), res);
+        return res;
+    }
     return OK;
 }
 
@@ -195,10 +210,44 @@
     return submitRequestList(requestList, streaming, submitInfo);
 }
 
-binder::Status CameraDeviceClient::insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
+status_t CameraDeviceClient::getSurfaceKey(ParcelableSurfaceType surface, SurfaceKey* out) const {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+    auto ret = surface.getUniqueId(out);
+    if (ret != OK) {
+        ALOGE("%s: Camera %s: Could not getUniqueId.", __FUNCTION__, mCameraIdStr.c_str());
+        return ret;
+    }
+    return OK;
+#else
+    *out = IInterface::asBinder(surface);
+    return OK;
+#endif
+}
+
+status_t CameraDeviceClient::getSurfaceKey(sp<Surface> surface, SurfaceKey* out) const {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+    auto ret = surface->getUniqueId(out);
+    if (ret != OK) {
+        ALOGE("%s: Camera %s: Could not getUniqueId.", __FUNCTION__, mCameraIdStr.c_str());
+        return ret;
+    }
+    return OK;
+#else
+    *out = IInterface::asBinder(surface->getIGraphicBufferProducer());
+    return OK;
+#endif
+}
+
+binder::Status CameraDeviceClient::insertSurfaceLocked(const ParcelableSurfaceType& surface,
         SurfaceMap* outSurfaceMap, Vector<int32_t>* outputStreamIds, int32_t *currentStreamId) {
     int compositeIdx;
-    int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));
+    SurfaceKey surfaceKey;
+    status_t ret = getSurfaceKey(surface, &surfaceKey);
+    if(ret != OK) {
+        ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__, mCameraIdStr.c_str());
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, "Could not get the SurfaceKey");
+    }
+    int idx = mStreamMap.indexOfKey(surfaceKey);
 
     Mutex::Autolock l(mCompositeLock);
     // Trying to submit request with surface that wasn't created
@@ -208,7 +257,7 @@
                 __FUNCTION__, mCameraIdStr.c_str());
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                 "Request targets Surface that is not part of current capture session");
-    } else if ((compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp)))
+    } else if ((compositeIdx = mCompositeStreamMap.indexOfKey(surfaceKey))
             != NAME_NOT_FOUND) {
         mCompositeStreamMap.valueAt(compositeIdx)->insertGbp(outSurfaceMap, outputStreamIds,
                 currentStreamId);
@@ -332,8 +381,12 @@
                 if (surface == 0) continue;
 
                 int32_t streamId;
-                sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
-                res = insertGbpLocked(gbp, &surfaceMap, &outputStreamIds, &streamId);
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                ParcelableSurfaceType surface_type = view::Surface::fromSurface(surface);
+#else
+                ParcelableSurfaceType surface_type = surface->getIGraphicBufferProducer();
+#endif
+                res = insertSurfaceLocked(surface_type, &surfaceMap, &outputStreamIds, &streamId);
                 if (!res.isOk()) {
                     return res;
                 }
@@ -363,8 +416,8 @@
                             "Request targets Surface that is not part of current capture session");
                 }
 
-                const auto& gbps = mConfiguredOutputs.valueAt(index).getGraphicBufferProducers();
-                if ((size_t)surfaceIdx >= gbps.size()) {
+                const auto& surfaces = mConfiguredOutputs.valueAt(index).getSurfaces();
+                if ((size_t)surfaceIdx >= surfaces.size()) {
                     ALOGE("%s: Camera %s: Tried to submit a request with a surface that"
                             " we have not called createStream on: stream %d, surfaceIdx %d",
                             __FUNCTION__, mCameraIdStr.c_str(), streamId, surfaceIdx);
@@ -372,7 +425,9 @@
                             "Request targets Surface has invalid surface index");
                 }
 
-                res = insertGbpLocked(gbps[surfaceIdx], &surfaceMap, &outputStreamIds, nullptr);
+                res = insertSurfaceLocked(surfaces[surfaceIdx], &surfaceMap, &outputStreamIds,
+                                          nullptr);
+
                 if (!res.isOk()) {
                     return res;
                 }
@@ -787,7 +842,7 @@
     }
 
     bool isInput = false;
-    std::vector<sp<IBinder>> surfaces;
+    std::vector<SurfaceKey> surfaces;
     std::vector<size_t> removedSurfaceIds;
     ssize_t dIndex = NAME_NOT_FOUND;
     ssize_t compositeIndex  = NAME_NOT_FOUND;
@@ -899,13 +954,12 @@
                 "OutputConfiguration isn't valid!");
     }
 
-    const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
-            outputConfiguration.getGraphicBufferProducers();
-    size_t numBufferProducers = bufferProducers.size();
+    const std::vector<ParcelableSurfaceType>& surfaces = outputConfiguration.getSurfaces();
+    size_t numSurfaces = surfaces.size();
     bool deferredConsumer = outputConfiguration.isDeferred();
     bool isShared = outputConfiguration.isShared();
     const std::string &physicalCameraId = outputConfiguration.getPhysicalCameraId();
-    bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
+    bool deferredConsumerOnly = deferredConsumer && numSurfaces == 0;
     bool isMultiResolution = outputConfiguration.isMultiResolution();
     int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
     int64_t streamUseCase = outputConfiguration.getStreamUseCase();
@@ -913,7 +967,7 @@
     int32_t colorSpace = outputConfiguration.getColorSpace();
     bool useReadoutTimestamp = outputConfiguration.useReadoutTimestamp();
 
-    res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
+    res = SessionConfigurationUtils::checkSurfaceType(numSurfaces, deferredConsumer,
             outputConfiguration.getSurfaceType(), /*isConfigurationComplete*/true);
     if (!res.isOk()) {
         return res;
@@ -928,8 +982,8 @@
         return res;
     }
 
-    std::vector<SurfaceHolder> surfaces;
-    std::vector<sp<IBinder>> binders;
+    std::vector<SurfaceHolder> surfaceHolders;
+    std::vector<SurfaceKey> surfaceKeys;
     std::vector<OutputStreamInfo> streamInfos;
     status_t err;
 
@@ -942,10 +996,19 @@
     bool isStreamInfoValid = false;
     const std::vector<int32_t> &sensorPixelModesUsed =
             outputConfiguration.getSensorPixelModesUsed();
-    for (auto& bufferProducer : bufferProducers) {
+
+    for (auto& surface : surfaces) {
         // Don't create multiple streams for the same target surface
-        sp<IBinder> binder = IInterface::asBinder(bufferProducer);
-        ssize_t index = mStreamMap.indexOfKey(binder);
+        SurfaceKey surfaceKey;
+        status_t ret = getSurfaceKey(surface, &surfaceKey);
+        if(ret != OK) {
+            ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+                mCameraIdStr.c_str());
+            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                "Could not get the SurfaceKey");
+        }
+
+        ssize_t index = mStreamMap.indexOfKey(surfaceKey);
         if (index != NAME_NOT_FOUND) {
             std::string msg = std::string("Camera ") + mCameraIdStr
                     + ": Surface already has a stream created for it (ID "
@@ -954,10 +1017,14 @@
             return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.c_str());
         }
 
-        int mirrorMode = outputConfiguration.getMirrorMode(bufferProducer);
-        sp<Surface> surface;
+        int mirrorMode = outputConfiguration.getMirrorMode(surface);
+        sp<Surface> outSurface;
         res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
-                isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
+                isStreamInfoValid, outSurface, surface
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                .graphicBufferProducer
+#endif
+                , mCameraIdStr,
                 mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
                 streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
 
@@ -968,8 +1035,8 @@
             isStreamInfoValid = true;
         }
 
-        binders.push_back(IInterface::asBinder(bufferProducer));
-        surfaces.push_back({surface, mirrorMode});
+        surfaceKeys.push_back(surfaceKey);
+        surfaceHolders.push_back({outSurface, mirrorMode});
         if (flags::camera_multi_client() && mSharedMode) {
             streamInfos.push_back(streamInfo);
         }
@@ -980,15 +1047,15 @@
     if (flags::camera_multi_client() && mSharedMode) {
         err = mDevice->getSharedStreamId(outputConfiguration, &streamId);
         if (err == OK) {
-            err = mDevice->addSharedSurfaces(streamId, streamInfos, surfaces, &surfaceIds);
+            err = mDevice->addSharedSurfaces(streamId, streamInfos, surfaceHolders, &surfaceIds);
         }
     } else {
         bool isDepthCompositeStream =
-                camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0].mSurface);
+                camera3::DepthCompositeStream::isDepthCompositeStream(surfaceHolders[0].mSurface);
         bool isHeicCompositeStream = camera3::HeicCompositeStream::isHeicCompositeStream(
-                surfaces[0].mSurface);
+                surfaceHolders[0].mSurface);
         bool isJpegRCompositeStream =
-            camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaces[0].mSurface) &&
+            camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaceHolders[0].mSurface) &&
             !mDevice->isCompositeJpegRDisabled();
         if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) {
             sp<CompositeStream> compositeStream;
@@ -999,7 +1066,7 @@
             } else {
                 compositeStream = new camera3::JpegRCompositeStream(mDevice, getRemoteCallback());
             }
-            err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width,
+            err = compositeStream->createStream(surfaceHolders, deferredConsumer, streamInfo.width,
                 streamInfo.height, streamInfo.format,
                 static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
                 &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
@@ -1008,12 +1075,18 @@
                 useReadoutTimestamp);
             if (err == OK) {
                 Mutex::Autolock l(mCompositeLock);
-                mCompositeStreamMap.add(
-                        IInterface::asBinder(surfaces[0].mSurface->getIGraphicBufferProducer()),
-                        compositeStream);
+                SurfaceKey surfaceKey;
+                status_t ret = getSurfaceKey(surfaceHolders[0].mSurface, &surfaceKey);
+                if(ret != OK) {
+                    ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+                        mCameraIdStr.c_str());
+                    return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                        "Could not get the SurfaceKey");
+                }
+                mCompositeStreamMap.add(surfaceKey, compositeStream);
             }
         } else {
-            err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
+            err = mDevice->createStream(surfaceHolders, deferredConsumer, streamInfo.width,
                     streamInfo.height, streamInfo.format, streamInfo.dataSpace,
                     static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
                     &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
@@ -1030,10 +1103,15 @@
                 static_cast<int>(streamInfo.dataSpace), strerror(-err), err);
     } else {
         int i = 0;
-        for (auto& binder : binders) {
-            ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d",
-                    __FUNCTION__, binder.get(), streamId, i);
-            mStreamMap.add(binder, StreamSurfaceId(streamId, surfaceIds[i]));
+        for (auto& surfaceKey : surfaceKeys) {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+            ALOGV("%s: mStreamMap add surfaceKey %lu streamId %d, surfaceId %d",
+                    __FUNCTION__, surfaceKey, streamId, i);
+#else
+            ALOGV("%s: mStreamMap add surfaceKey %p streamId %d, surfaceId %d",
+                    __FUNCTION__, surfaceKey.get(), streamId, i);
+#endif
+            mStreamMap.add(surfaceKey, StreamSurfaceId(streamId, surfaceIds[i]));
             i++;
         }
 
@@ -1257,40 +1335,52 @@
                 "OutputConfiguration isn't valid!");
     }
 
-    const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
-            outputConfiguration.getGraphicBufferProducers();
-    const std::string &physicalCameraId = outputConfiguration.getPhysicalCameraId();
+    const std::vector<ParcelableSurfaceType>& surfaces = outputConfiguration.getSurfaces();
+    const std::string& physicalCameraId = outputConfiguration.getPhysicalCameraId();
 
-    auto producerCount = bufferProducers.size();
+    auto producerCount = surfaces.size();
     if (producerCount == 0) {
-        ALOGE("%s: bufferProducers must not be empty", __FUNCTION__);
+        ALOGE("%s: surfaces must not be empty", __FUNCTION__);
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                "bufferProducers must not be empty");
+                            "surfaces must not be empty");
     }
 
     // The first output is the one associated with the output configuration.
     // It should always be present, valid and the corresponding stream id should match.
-    sp<IBinder> binder = IInterface::asBinder(bufferProducers[0]);
-    ssize_t index = mStreamMap.indexOfKey(binder);
+    SurfaceKey surfaceKey;
+    status_t ret = getSurfaceKey(surfaces[0], &surfaceKey);
+    if(ret != OK) {
+        ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__, mCameraIdStr.c_str());
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, "Could not get the SurfaceKey");
+    }
+    ssize_t index = mStreamMap.indexOfKey(surfaceKey);
     if (index == NAME_NOT_FOUND) {
         ALOGE("%s: Outputconfiguration is invalid", __FUNCTION__);
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                 "OutputConfiguration is invalid");
     }
-    if (mStreamMap.valueFor(binder).streamId() != streamId) {
+    if (mStreamMap.valueFor(surfaceKey).streamId() != streamId) {
         ALOGE("%s: Stream Id: %d provided doesn't match the id: %d in the stream map",
-                __FUNCTION__, streamId, mStreamMap.valueFor(binder).streamId());
+                __FUNCTION__, streamId, mStreamMap.valueFor(surfaceKey).streamId());
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                 "Stream id is invalid");
     }
 
     std::vector<size_t> removedSurfaceIds;
-    std::vector<sp<IBinder>> removedOutputs;
+    std::vector<SurfaceKey> removedOutputs;
     std::vector<SurfaceHolder> newOutputs;
     std::vector<OutputStreamInfo> streamInfos;
-    KeyedVector<sp<IBinder>, sp<IGraphicBufferProducer>> newOutputsMap;
-    for (auto &it : bufferProducers) {
-        newOutputsMap.add(IInterface::asBinder(it), it);
+    KeyedVector<SurfaceKey, ParcelableSurfaceType> newOutputsMap;
+    for (auto& surface : surfaces) {
+        SurfaceKey surfaceKey;
+        status_t ret = getSurfaceKey(surface, &surfaceKey);
+        if(ret != OK) {
+            ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+                 mCameraIdStr.c_str());
+            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                 "Could not get the SurfaceKey");
+        }
+        newOutputsMap.add(surfaceKey, surface);
     }
 
     for (size_t i = 0; i < mStreamMap.size(); i++) {
@@ -1318,17 +1408,24 @@
 
     for (size_t i = 0; i < newOutputsMap.size(); i++) {
         OutputStreamInfo outInfo;
-        sp<Surface> surface;
+        sp<Surface> outSurface;
         int mirrorMode = outputConfiguration.getMirrorMode(newOutputsMap.valueAt(i));
-        res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
-                /*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
-                mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
-                streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
-        if (!res.isOk())
-            return res;
+        res = SessionConfigurationUtils::createSurfaceFromGbp(
+                outInfo,
+                /*isStreamInfoValid*/ false, outSurface,
+                newOutputsMap
+                        .valueAt(i)
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                        .graphicBufferProducer
+#endif
+                ,
+                mCameraIdStr, mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed,
+                dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode, colorSpace,
+                /*respectSurfaceSize*/ false);
+        if (!res.isOk()) return res;
 
         streamInfos.push_back(outInfo);
-        newOutputs.push_back({surface, mirrorMode});
+        newOutputs.push_back({outSurface, mirrorMode});
     }
 
     //Trivial case no changes required
@@ -1337,8 +1434,7 @@
     }
 
     KeyedVector<sp<Surface>, size_t> outputMap;
-    auto ret = mDevice->updateStream(streamId, newOutputs, streamInfos, removedSurfaceIds,
-            &outputMap);
+    ret = mDevice->updateStream(streamId, newOutputs, streamInfos, removedSurfaceIds, &outputMap);
     if (ret != OK) {
         switch (ret) {
             case NAME_NOT_FOUND:
@@ -1360,8 +1456,15 @@
         }
 
         for (size_t i = 0; i < outputMap.size(); i++) {
-            mStreamMap.add(IInterface::asBinder(outputMap.keyAt(i)->getIGraphicBufferProducer()),
-                    StreamSurfaceId(streamId, outputMap.valueAt(i)));
+            SurfaceKey surfaceKey;
+            status_t ret = getSurfaceKey(outputMap.keyAt(i), &surfaceKey);
+            if(ret != OK) {
+                ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+                     mCameraIdStr.c_str());
+                return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                     "Could not get the SurfaceKey");
+            }
+            mStreamMap.add(surfaceKey, StreamSurfaceId(streamId, outputMap.valueAt(i)));
         }
 
         mConfiguredOutputs.replaceValueFor(streamId, outputConfiguration);
@@ -1641,12 +1744,11 @@
                 "OutputConfiguration isn't valid!");
     }
 
-    const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
-            outputConfiguration.getGraphicBufferProducers();
-    const std::string &physicalId = outputConfiguration.getPhysicalCameraId();
+    const std::vector<ParcelableSurfaceType>& surfaces = outputConfiguration.getSurfaces();
+    const std::string& physicalId = outputConfiguration.getPhysicalCameraId();
 
-    if (bufferProducers.size() == 0) {
-        ALOGE("%s: bufferProducers must not be empty", __FUNCTION__);
+    if (surfaces.size() == 0) {
+        ALOGE("%s: surfaces must not be empty", __FUNCTION__);
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
     }
 
@@ -1686,34 +1788,47 @@
     }
 
     std::vector<SurfaceHolder> consumerSurfaceHolders;
-    const std::vector<int32_t> &sensorPixelModesUsed =
+    const std::vector<int32_t>& sensorPixelModesUsed =
             outputConfiguration.getSensorPixelModesUsed();
     int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
     int32_t colorSpace = outputConfiguration.getColorSpace();
     int64_t streamUseCase = outputConfiguration.getStreamUseCase();
     int timestampBase = outputConfiguration.getTimestampBase();
-    for (auto& bufferProducer : bufferProducers) {
+
+    for (auto& surface : surfaces) {
         // Don't create multiple streams for the same target surface
-        ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
+        SurfaceKey surfaceKey;
+        status_t ret = getSurfaceKey(surface, &surfaceKey);
+        if(ret != OK) {
+            ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+                 mCameraIdStr.c_str());
+            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                 "Could not get the SurfaceKey");
+        }
+        ssize_t index = mStreamMap.indexOfKey(surfaceKey);
         if (index != NAME_NOT_FOUND) {
             ALOGV("Camera %s: Surface already has a stream created "
-                    " for it (ID %zd)", mCameraIdStr.c_str(), index);
+                  " for it (ID %zd)",
+                  mCameraIdStr.c_str(), index);
             continue;
         }
 
-        sp<Surface> surface;
-        int mirrorMode = outputConfiguration.getMirrorMode(bufferProducer);
-        res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
-                true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
-                mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile,
-                streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
+        sp<Surface> outSurface;
+        int mirrorMode = outputConfiguration.getMirrorMode(surface);
+        res = SessionConfigurationUtils::createSurfaceFromGbp(
+                mStreamInfoMap[streamId], true /*isStreamInfoValid*/, outSurface,
+                surface
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                .graphicBufferProducer
+#endif
+                , mCameraIdStr, mDevice->infoPhysical(physicalId),
+                sensorPixelModesUsed, dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode,
+                colorSpace, /*respectSurfaceSize*/ false);
 
-        if (!res.isOk())
-            return res;
+        if (!res.isOk()) return res;
 
-        consumerSurfaceHolders.push_back({surface, mirrorMode});
+        consumerSurfaceHolders.push_back({outSurface, mirrorMode});
     }
-
     // Gracefully handle case where finalizeOutputConfigurations is called
     // without any new surface.
     if (consumerSurfaceHolders.size() == 0) {
@@ -1727,11 +1842,22 @@
     err = mDevice->setConsumerSurfaces(streamId, consumerSurfaceHolders, &consumerSurfaceIds);
     if (err == OK) {
         for (size_t i = 0; i < consumerSurfaceHolders.size(); i++) {
-            sp<IBinder> binder = IInterface::asBinder(
-                    consumerSurfaceHolders[i].mSurface->getIGraphicBufferProducer());
-            ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d", __FUNCTION__,
-                    binder.get(), streamId, consumerSurfaceIds[i]);
-            mStreamMap.add(binder, StreamSurfaceId(streamId, consumerSurfaceIds[i]));
+            SurfaceKey surfaceKey;
+            status_t ret = getSurfaceKey(consumerSurfaceHolders[i].mSurface, &surfaceKey);
+            if(ret != OK) {
+                ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+                     mCameraIdStr.c_str());
+                return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                     "Could not get the SurfaceKey");
+            }
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+            ALOGV("%s: mStreamMap add surface_key %lu streamId %d, surfaceId %d", __FUNCTION__,
+                    surfaceKey, streamId, consumerSurfaceIds[i]);
+#else
+            ALOGV("%s: mStreamMap add surface_key %p streamId %d, surfaceId %d", __FUNCTION__,
+                    surfaceKey.get(), streamId, consumerSurfaceIds[i]);
+#endif
+            mStreamMap.add(surfaceKey, StreamSurfaceId(streamId, consumerSurfaceIds[i]));
         }
         if (deferredStreamIndex != NAME_NOT_FOUND) {
             mDeferredStreams.removeItemsAt(deferredStreamIndex);
@@ -1768,6 +1894,34 @@
     return binder::Status::ok();
 }
 
+status_t CameraDeviceClient::CreateMetadataQueue(
+        std::unique_ptr<MetadataQueue>* metadata_queue, uint32_t default_size_bytes) {
+        if (metadata_queue == nullptr) {
+            ALOGE("%s: metadata_queue is nullptr", __FUNCTION__);
+            return BAD_VALUE;
+        }
+
+        int32_t size = default_size_bytes;
+
+        *metadata_queue =
+                std::make_unique<MetadataQueue>(static_cast<size_t>(size),
+                        /*configureEventFlagWord*/ false);
+        if (!(*metadata_queue)->isValid()) {
+            ALOGE("%s: Creating metadata queue (size %d) failed.", __FUNCTION__, size);
+            return NO_INIT;
+        }
+
+        return OK;
+}
+
+binder::Status CameraDeviceClient::getCaptureResultMetadataQueue(
+          android::hardware::common::fmq::MQDescriptor<
+          int8_t, android::hardware::common::fmq::SynchronizedReadWrite>* aidl_return) {
+
+    *aidl_return = mResultMetadataQueue->dupeDesc();
+    return binder::Status::ok();
+}
+
 binder::Status CameraDeviceClient::getGlobalAudioRestriction(/*out*/ int32_t* outMode) {
     ATRACE_CALL();
     binder::Status res;
@@ -1866,7 +2020,7 @@
 
     std::vector<int32_t> offlineStreamIds;
     offlineStreamIds.reserve(offlineOutputIds.size());
-    KeyedVector<sp<IBinder>, sp<CompositeStream>> offlineCompositeStreamMap;
+    KeyedVector<SurfaceKey, sp<CompositeStream>> offlineCompositeStreamMap;
     for (const auto& streamId : offlineOutputIds) {
         ssize_t index = mConfiguredOutputs.indexOfKey(streamId);
         if (index == NAME_NOT_FOUND) {
@@ -1885,24 +2039,37 @@
 
         Mutex::Autolock l(mCompositeLock);
         bool isCompositeStream = false;
-        for (const auto& gbp : mConfiguredOutputs.valueAt(index).getGraphicBufferProducers()) {
-            sp<Surface> s = new Surface(gbp, false /*controlledByApp*/);
+
+        for (const auto& surface : mConfiguredOutputs.valueAt(index).getSurfaces()) {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+            sp<Surface> s = surface.toSurface();
+#else
+            sp<Surface> s = new Surface(surface, false /*controlledByApp*/);
+#endif
             isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) ||
-                camera3::HeicCompositeStream::isHeicCompositeStream(s) ||
-                (camera3::JpegRCompositeStream::isJpegRCompositeStream(s) &&
-                 !mDevice->isCompositeJpegRDisabled());
+                                camera3::HeicCompositeStream::isHeicCompositeStream(s) ||
+                                (camera3::JpegRCompositeStream::isJpegRCompositeStream(s) &&
+                                 !mDevice->isCompositeJpegRDisabled());
             if (isCompositeStream) {
-                auto compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp));
+                SurfaceKey surfaceKey;
+                status_t ret = getSurfaceKey(surface, &surfaceKey);
+                if(ret != OK) {
+                    ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+                        mCameraIdStr.c_str());
+                    return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                        "Could not get the SurfaceKey");
+                }
+                auto compositeIdx = mCompositeStreamMap.indexOfKey(surfaceKey);
                 if (compositeIdx == NAME_NOT_FOUND) {
                     ALOGE("%s: Unknown composite stream", __FUNCTION__);
                     return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                            "Unknown composite stream");
+                                        "Unknown composite stream");
                 }
 
-                mCompositeStreamMap.valueAt(compositeIdx)->insertCompositeStreamIds(
-                        &offlineStreamIds);
+                mCompositeStreamMap.valueAt(compositeIdx)
+                        ->insertCompositeStreamIds(&offlineStreamIds);
                 offlineCompositeStreamMap.add(mCompositeStreamMap.keyAt(compositeIdx),
-                        mCompositeStreamMap.valueAt(compositeIdx));
+                                              mCompositeStreamMap.valueAt(compositeIdx));
                 break;
             }
         }
@@ -2190,16 +2357,76 @@
     mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs, hasDeviceError);
 }
 
+size_t CameraDeviceClient::writeResultMetadataIntoResultQueue(
+        const CameraMetadata &resultMetadata) {
+    ATRACE_CALL();
+
+    const camera_metadata_t *resultMetadataP = resultMetadata.getAndLock();
+    size_t resultSize = get_camera_metadata_size(resultMetadataP);
+    if (mResultMetadataQueue != nullptr &&
+        mResultMetadataQueue->write(reinterpret_cast<const int8_t*>(resultMetadataP),
+                resultSize)) {
+        resultMetadata.unlock(resultMetadataP);
+        return resultSize;
+    }
+    resultMetadata.unlock(resultMetadataP);
+    ALOGE(" %s couldn't write metadata into result queue ", __FUNCTION__);
+    return 0;
+}
+
 /** Device-related methods */
+std::vector<PhysicalCaptureResultInfo> CameraDeviceClient::convertToFMQ(
+        const std::vector<PhysicalCaptureResultInfo> &physicalResults) {
+    std::vector<PhysicalCaptureResultInfo> retVal;
+    ALOGVV("%s E", __FUNCTION__);
+    for (const auto &srcPhysicalResult : physicalResults) {
+        size_t fmqSize = 0;
+        if (!mIsVendorClient && flags::fmq_metadata()) {
+            fmqSize = writeResultMetadataIntoResultQueue(
+                    srcPhysicalResult.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
+        }
+        ALOGVV("%s physical metadata write size is %d", __FUNCTION__, (int)fmqSize);
+        if (fmqSize != 0) {
+            retVal.emplace_back(srcPhysicalResult.mPhysicalCameraId, fmqSize);
+        } else {
+            // The flag was off / we're serving VNDK shim call or FMQ write failed.
+            retVal.emplace_back(srcPhysicalResult.mPhysicalCameraId,
+                    srcPhysicalResult.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
+        }
+    }
+    ALOGVV("%s X", __FUNCTION__);
+    return retVal;
+}
+
 void CameraDeviceClient::onResultAvailable(const CaptureResult& result) {
     ATRACE_CALL();
-    ALOGV("%s", __FUNCTION__);
+    ALOGVV("%s E", __FUNCTION__);
 
     // Thread-safe. No lock necessary.
     sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
     if (remoteCb != NULL) {
-        remoteCb->onResultReceived(result.mMetadata, result.mResultExtras,
-                result.mPhysicalMetadatas);
+        // Write  result metadata into metadataQueue
+        size_t fmqMetadataSize = 0;
+        // Vendor clients need to modify metadata and also this call is in process
+        // before going through FMQ to vendor clients. So don't use FMQ here.
+        if (!mIsVendorClient && flags::fmq_metadata()) {
+            fmqMetadataSize = writeResultMetadataIntoResultQueue(result.mMetadata);
+        }
+        hardware::camera2::impl::CameraMetadataNative resultMetadata;
+        CameraMetadataInfo resultInfo;
+        if (fmqMetadataSize == 0) {
+            // The flag was off / we're serving VNDK shim call or FMQ write failed.
+            resultMetadata = result.mMetadata;
+            resultInfo.set<CameraMetadataInfo::metadata>(resultMetadata);
+        } else {
+            resultInfo.set<CameraMetadataInfo::fmqSize>(fmqMetadataSize);
+        }
+
+        std::vector<PhysicalCaptureResultInfo> physicalMetadatas =
+                convertToFMQ(result.mPhysicalMetadatas);
+
+        remoteCb->onResultReceived(resultInfo, result.mResultExtras,
+                physicalMetadatas);
     }
 
     // Access to the composite stream map must be synchronized
@@ -2207,6 +2434,7 @@
     for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
         mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
     }
+    ALOGVV("%s X", __FUNCTION__);
 }
 
 binder::Status CameraDeviceClient::checkPidStatus(const char* checkLocation) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index a8cf451..4ad3c49 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -23,6 +23,9 @@
 #include <camera/camera2/SessionConfiguration.h>
 #include <camera/camera2/SubmitInfo.h>
 #include <unordered_map>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+
+#include <fmq/AidlMessageQueueCpp.h>
 
 #include "CameraOfflineSessionClient.h"
 #include "CameraService.h"
@@ -37,6 +40,12 @@
 
 namespace android {
 
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+typedef uint64_t SurfaceKey;
+#else
+typedef sp<IBinder> SurfaceKey;
+#endif
+
 struct CameraDeviceClientBase :
          public CameraService::BasicClient,
          public hardware::camera2::BnCameraDeviceUser
@@ -161,6 +170,11 @@
 
     virtual binder::Status setCameraAudioRestriction(int32_t mode) override;
 
+    virtual binder::Status getCaptureResultMetadataQueue(
+          android::hardware::common::fmq::MQDescriptor<
+          int8_t, android::hardware::common::fmq::SynchronizedReadWrite>*
+          aidl_return) override;
+
     virtual binder::Status getGlobalAudioRestriction(/*out*/int32_t* outMode) override;
 
     virtual binder::Status switchToOffline(
@@ -182,7 +196,8 @@
                        const AttributionSourceState& clientAttribution, int callingPid,
                        bool clientPackageOverride, const std::string& cameraId, int cameraFacing,
                        int sensorOrientation, int servicePid, bool overrideForPerfClass,
-                       int rotationOverride, const std::string& originalCameraId, bool sharedMode);
+                       int rotationOverride, const std::string& originalCameraId, bool sharedMode,
+                       bool isVendorClient);
     virtual ~CameraDeviceClient();
 
     virtual status_t      initialize(sp<CameraProviderManager> manager,
@@ -233,6 +248,10 @@
      */
 protected:
     /** FilteredListener implementation **/
+
+    size_t writeResultMetadataIntoResultQueue(const CameraMetadata &result);
+    std::vector<PhysicalCaptureResultInfo> convertToFMQ(
+            const std::vector<PhysicalCaptureResultInfo> &physicalResults);
     virtual void          onResultAvailable(const CaptureResult& result);
     virtual void          detachDevice();
 
@@ -244,6 +263,11 @@
     const CameraMetadata &getStaticInfo(const std::string &cameraId);
 
 private:
+    using MetadataQueue = AidlMessageQueueCpp<
+            int8_t, android::hardware::common::fmq::SynchronizedReadWrite>;
+    using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
+    status_t CreateMetadataQueue(
+            std::unique_ptr<MetadataQueue>* metadata_queue, uint32_t default_size);
     // StreamSurfaceId encapsulates streamId + surfaceId for a particular surface.
     // streamId specifies the index of the stream the surface belongs to, and the
     // surfaceId specifies the index of the surface within the stream. (one stream
@@ -293,12 +317,20 @@
             int* newStreamId = NULL);
 
     // Utility method to insert the surface into SurfaceMap
-    binder::Status insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
+    binder::Status insertSurfaceLocked(const ParcelableSurfaceType& surface,
             /*out*/SurfaceMap* surfaceMap, /*out*/Vector<int32_t>* streamIds,
             /*out*/int32_t*  currentStreamId);
 
+    // A ParcelableSurfaceType can be either a view::Surface or IGBP.
+    // We use this type of surface when we need to be able to have a parcelable data type.
+    // view::Surface has helper functions to make converting between a regular Surface and a
+    // view::Surface easy.
+    status_t getSurfaceKey(ParcelableSurfaceType surface, SurfaceKey* out) const;
+    // Surface only
+    status_t getSurfaceKey(sp<Surface> surface, SurfaceKey* out) const;
+
     // IGraphicsBufferProducer binder -> Stream ID + Surface ID for output streams
-    KeyedVector<sp<IBinder>, StreamSurfaceId> mStreamMap;
+    KeyedVector<SurfaceKey, StreamSurfaceId> mStreamMap;
 
     // Stream ID -> OutputConfiguration. Used for looking up Surface by stream/surface index
     KeyedVector<int32_t, hardware::camera2::params::OutputConfiguration> mConfiguredOutputs;
@@ -322,6 +354,9 @@
 
     int32_t mRequestIdCounter;
 
+    // Metadata queue to write the result metadata to.
+    std::unique_ptr<MetadataQueue> mResultMetadataQueue;
+
     std::vector<std::string> mPhysicalCameraIds;
 
     // The list of output streams whose surfaces are deferred. We have to track them separately
@@ -340,7 +375,7 @@
 
     // Synchronize access to 'mCompositeStreamMap'
     Mutex mCompositeLock;
-    KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
+    KeyedVector<SurfaceKey, sp<CompositeStream>> mCompositeStreamMap;
 
     sp<CameraProviderManager> mProviderManager;
 
@@ -361,6 +396,8 @@
 
     // This only exists in case of camera ID Remapping.
     const std::string mOriginalCameraId;
+
+    bool mIsVendorClient = false;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 71fd3ba..1e73d79 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -299,7 +299,10 @@
     ALOGV("%s", __FUNCTION__);
 
     if (mRemoteCallback.get() != NULL) {
-        mRemoteCallback->onResultReceived(result.mMetadata, result.mResultExtras,
+        using hardware::camera2::CameraMetadataInfo;
+        CameraMetadataInfo resultInfo;
+        resultInfo.set<CameraMetadataInfo::metadata>(result.mMetadata);
+        mRemoteCallback->onResultReceived(resultInfo, result.mResultExtras,
                 result.mPhysicalMetadatas);
     }
 
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 78a3055..3799ba3 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -30,6 +30,12 @@
 using android::hardware::camera2::ICameraDeviceCallbacks;
 using camera3::CompositeStream;
 
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+typedef uint64_t SurfaceKey;
+#else
+typedef sp<IBinder> SurfaceKey;
+#endif
+
 // Client for offline session. Note that offline session client does not affect camera service's
 // client arbitration logic. It is camera HAL's decision to decide whether a normal camera
 // client is conflicting with existing offline client(s).
@@ -45,7 +51,7 @@
 public:
     CameraOfflineSessionClient(
             const sp<CameraService>& cameraService, sp<CameraOfflineSessionBase> session,
-            const KeyedVector<sp<IBinder>, sp<CompositeStream>>& offlineCompositeStreamMap,
+            const KeyedVector<SurfaceKey, sp<CompositeStream>>& offlineCompositeStreamMap,
             const sp<ICameraDeviceCallbacks>& remoteCallback,
             std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
             const AttributionSourceState& clientAttribution, int callingPid,
@@ -135,7 +141,7 @@
     sp<camera2::FrameProcessorBase> mFrameProcessor;
 
     // Offline composite stream map, output surface -> composite stream
-    KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
+    KeyedVector<SurfaceKey, sp<CompositeStream>> mCompositeStreamMap;
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 2322def..31dcce2 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -29,6 +29,8 @@
 namespace android {
 namespace camera2 {
 
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
+
 FrameProcessorBase::FrameProcessorBase(wp<FrameProducer> device) :
     Thread(/*canCallJava*/false),
     mDevice(device),
@@ -99,7 +101,7 @@
 
         for (const auto& physicalFrame : mLastPhysicalFrames) {
             lastPhysicalFrames.emplace(physicalFrame.mPhysicalCameraId,
-                    physicalFrame.mPhysicalCameraMetadata);
+                    physicalFrame.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
         }
     }
     lastFrame.dump(fd, /*verbosity*/2, /*indentation*/6);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9e89a19..c050f1b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -61,6 +61,7 @@
 #include <com_android_window_flags.h>
 
 #include "CameraService.h"
+#include "FwkOnlyMetadataTags.h"
 #include "aidl/android/hardware/graphics/common/Dataspace.h"
 #include "aidl/AidlUtils.h"
 #include "device3/Camera3Device.h"
@@ -3797,18 +3798,12 @@
 }
 
 status_t Camera3Device::removeFwkOnlyKeys(CameraMetadata *request) {
-    static const std::array<uint32_t, 5> kFwkOnlyKeys = {
-            ANDROID_CONTROL_AF_REGIONS_SET,
-            ANDROID_CONTROL_AE_REGIONS_SET,
-            ANDROID_CONTROL_AWB_REGIONS_SET,
-            ANDROID_SCALER_CROP_REGION_SET,
-            ANDROID_CONTROL_ZOOM_METHOD};
     if (request == nullptr) {
         ALOGE("%s request metadata nullptr", __FUNCTION__);
         return BAD_VALUE;
     }
     status_t res = OK;
-    for (const auto &key : kFwkOnlyKeys) {
+    for (const auto &key : kFwkOnlyMetadataKeys) {
         if (request->exists(key)) {
             res = request->erase(key);
             if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 78f1698..66dcbc3 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -56,6 +56,7 @@
 using namespace android::camera3;
 using namespace android::camera3::SessionConfigurationUtils;
 using namespace android::hardware::camera;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 namespace flags = com::android::internal::camera::flags;
 
 namespace android {
@@ -231,11 +232,12 @@
 
     // Update vendor tag id for physical metadata
     for (auto& physicalMetadata : result->mPhysicalMetadatas) {
-        camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(
-                physicalMetadata.mPhysicalCameraMetadata.getAndLock());
+        auto &metadata =
+                physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>();
+        camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(metadata.getAndLock());
         set_camera_metadata_vendor_id(pmeta, states.vendorTagId);
         correctMeteringRegions(pmeta);
-        physicalMetadata.mPhysicalCameraMetadata.unlock(pmeta);
+        metadata.unlock(pmeta);
     }
 
     // Valid result, insert into queue
@@ -362,7 +364,8 @@
 
     for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
         camera_metadata_entry timestamp =
-                physicalMetadata.mPhysicalCameraMetadata.find(ANDROID_SENSOR_TIMESTAMP);
+                physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+                        find(ANDROID_SENSOR_TIMESTAMP);
         if (timestamp.count == 0) {
             SET_ERR("No timestamp provided by HAL for physical camera %s frame %d!",
                     physicalMetadata.mPhysicalCameraId.c_str(), frameNumber);
@@ -385,9 +388,8 @@
     // Fix up result metadata to account for zoom ratio availabilities between
     // HAL and app.
     bool zoomRatioIs1 = cameraIdsWithZoom.find(states.cameraId) == cameraIdsWithZoom.end();
-    bool appUsesZoomRatio = !zoomRatioIs1 || useZoomRatio;
     res = states.zoomRatioMappers[states.cameraId].updateCaptureResult(
-            &captureResult.mMetadata, appUsesZoomRatio);
+            &captureResult.mMetadata, useZoomRatio, zoomRatioIs1);
     if (res != OK) {
         SET_ERR("Failed to update capture result zoom ratio metadata for frame %d: %s (%d)",
                 frameNumber, strerror(-res), res);
@@ -416,7 +418,8 @@
         return;
     }
     for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
-        res = fixupManualFlashStrengthControlTags(physicalMetadata.mPhysicalCameraMetadata);
+        res = fixupManualFlashStrengthControlTags(physicalMetadata.mCameraMetadataInfo.
+                get<CameraMetadataInfo::metadata>());
         if (res != OK) {
             SET_ERR("Failed to set flash strength level defaults in physical result"
                     " metadata: %s (%d)", strerror(-res), res);
@@ -432,7 +435,8 @@
         return;
     }
     for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
-        res = fixupAutoframingTags(physicalMetadata.mPhysicalCameraMetadata);
+        res = fixupAutoframingTags(physicalMetadata.mCameraMetadataInfo.
+                get<CameraMetadataInfo::metadata>());
         if (res != OK) {
             SET_ERR("Failed to set autoframing defaults in physical result metadata: %s (%d)",
                     strerror(-res), res);
@@ -445,7 +449,7 @@
         auto mapper = states.distortionMappers.find(cameraId);
         if (mapper != states.distortionMappers.end()) {
             res = mapper->second.correctCaptureResult(
-                    &physicalMetadata.mPhysicalCameraMetadata);
+                    &physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
             if (res != OK) {
                 SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
                         frameNumber, strerror(-res), res);
@@ -456,7 +460,9 @@
         // Note: Physical camera continues to use SCALER_CROP_REGION to reflect
         // zoom levels.
         res = states.zoomRatioMappers[cameraId].updateCaptureResult(
-                &physicalMetadata.mPhysicalCameraMetadata, /*appUsesZoomRatio*/ false);
+                &physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>(),
+                /*zoomMethodIsRatio*/false,
+                /*zoomRatioIs1*/false);
         if (res != OK) {
             SET_ERR("Failed to update camera %s's physical zoom ratio metadata for "
                     "frame %d: %s(%d)", cameraId.c_str(), frameNumber, strerror(-res), res);
@@ -474,7 +480,7 @@
         const std::string &cameraId = physicalMetadata.mPhysicalCameraId;
         res = fixupMonochromeTags(states,
                 states.physicalDeviceInfoMap.at(cameraId),
-                physicalMetadata.mPhysicalCameraMetadata);
+                physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
         if (res != OK) {
             SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
             return;
@@ -484,7 +490,7 @@
     std::unordered_map<std::string, CameraMetadata> monitoredPhysicalMetadata;
     for (auto& m : physicalMetadatas) {
         monitoredPhysicalMetadata.emplace(m.mPhysicalCameraId,
-                CameraMetadata(m.mPhysicalCameraMetadata));
+                CameraMetadata(m.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>()));
     }
     states.tagMonitor.monitorMetadata(TagMonitor::RESULT,
             frameNumber, sensorTimestamp, captureResult.mMetadata,
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 5260ad3..ef2109a 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -290,7 +290,8 @@
     return res;
 }
 
-status_t ZoomRatioMapper::updateCaptureResult(CameraMetadata* result, bool useZoomRatio) {
+status_t ZoomRatioMapper::updateCaptureResult(
+        CameraMetadata* result, bool zoomMethodIsRatio, bool zoomRatioIs1) {
     if (!mIsValid) return INVALID_OPERATION;
 
     status_t res = OK;
@@ -300,6 +301,8 @@
     if (res != OK) {
         return res;
     }
+
+    bool useZoomRatio = !zoomRatioIs1 || zoomMethodIsRatio;
     if (mHalSupportsZoomRatio && !useZoomRatio) {
         res = combineZoomAndCropLocked(result, true/*isResult*/, arrayWidth, arrayHeight);
     } else if (!mHalSupportsZoomRatio && useZoomRatio) {
@@ -312,6 +315,12 @@
         }
     }
 
+    if (flags::zoom_method()) {
+        uint8_t zoomMethod = zoomMethodIsRatio ?  ANDROID_CONTROL_ZOOM_METHOD_ZOOM_RATIO :
+                ANDROID_CONTROL_ZOOM_METHOD_AUTO;
+        result->update(ANDROID_CONTROL_ZOOM_METHOD, &zoomMethod, 1);
+    }
+
     return res;
 }
 
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.h b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
index 0ac2e09..2ae2010 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.h
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
@@ -64,7 +64,9 @@
     /**
      * Update capture result to handle both cropRegion and zoomRatio.
      */
-    status_t updateCaptureResult(CameraMetadata *request, bool useZoomRatio);
+    status_t updateCaptureResult(CameraMetadata *request,
+                                 bool zoomMethodIsRatio,
+                                 bool zoomRatioIs1);
 
   public: // Visible for testing. Do not use concurently.
     void scaleCoordinates(int32_t* coordPairs, int coordCount,
diff --git a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp
index 00bbde3..41be9a4 100644
--- a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp
@@ -635,8 +635,7 @@
         if (detach) {
             res = consumer->detachBuffer(consumerSlot);
         } else {
-            res = consumer->releaseBuffer(consumerSlot, frameNumber, EGL_NO_DISPLAY,
-                                          EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence());
+            res = consumer->releaseBuffer(consumerSlot, frameNumber, tracker_ptr->getMergedFence());
         }
     } else {
         SP_LOGE("%s: consumer has become null!", __FUNCTION__);
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index c968e44..ec8da1a 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -248,9 +248,7 @@
 
         // item.mGraphicBuffer was populated with the proper graphic-buffer
         // at acquire even if it was previously acquired
-        err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer,
-                                  EGL_NO_DISPLAY,
-                                  EGL_NO_SYNC_KHR);
+        err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer);
         if (err != OK) {
             BI_LOGE("Failed to release buffer: %s (%d)",
                     strerror(-err), err);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
index de51ffa..24d9a7e 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
@@ -167,11 +167,19 @@
 }
 
 binder::Status H2BCameraDeviceCallbacks::onResultReceived(
-    const CameraMetadataNative& result,
+    const CameraMetadataInfo &resultInfo,
     const CaptureResultExtras& resultExtras,
     const ::std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) {
     // Wrap CameraMetadata, resultExtras and physicalCaptureResultInfos in on
     // sp<RefBase>-able structure and post it.
+    // We modify metadata - since we want to filter out tags based on the vndk
+    // version, and also this communication is an in process function call.
+    // So we don't use FMQ for the shim layer. FMQ is still used for VNDK IPC.
+    if (resultInfo.getTag() != CameraMetadataInfo::metadata) {
+        ALOGE("Vendor callbacks got metadata in fmq ? ");
+        return binder::Status::ok();
+    }
+    const CameraMetadataNative &result = resultInfo.get<CameraMetadataInfo::metadata>();
     sp<ResultWrapper> resultWrapper = new ResultWrapper(const_cast<CameraMetadataNative &>(result),
                                                         resultExtras, physicalCaptureResultInfos);
     sp<AMessage> msg = new AMessage(kWhatResultReceived, mHandler);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
index 98a0dbb..e36c2ea 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
@@ -54,6 +54,7 @@
 using hardware::kSynchronizedReadWrite;
 using hardware::MessageQueue;
 using CaptureResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 
 struct H2BCameraDeviceCallbacks :
     public H2BConverter<HCameraDeviceCallback, ICameraDeviceCallbacks, BnCameraDeviceCallbacks> {
@@ -72,7 +73,8 @@
                                             int64_t timestamp) override;
 
     virtual binder::Status onResultReceived(
-        const CameraMetadataNative& result, const CaptureResultExtras& resultExtras,
+        const CameraMetadataInfo &,
+        const CaptureResultExtras& resultExtras,
         const std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
 
     virtual binder::Status onPrepared(int32_t streamId) override;
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 9d140f2..9e66236 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -132,7 +132,7 @@
                     kDefaultDeviceId);
     clientAttribution.packageName = "";
     clientAttribution.attributionTag = std::nullopt;
-    binder::Status serviceRet = mAidlICameraService->connectDevice(
+    binder::Status serviceRet = mAidlICameraService->connectDeviceVendor(
             callbacks, cameraId, 0/*oomScoreOffset*/,
             /*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_NONE,
             clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, /*out*/&deviceRemote);
diff --git a/services/camera/libcameraservice/hidl/Utils.cpp b/services/camera/libcameraservice/hidl/Utils.cpp
index d0302d0..786087d 100644
--- a/services/camera/libcameraservice/hidl/Utils.cpp
+++ b/services/camera/libcameraservice/hidl/Utils.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include <hidl/Utils.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <cutils/native_handle.h>
-#include <mediautils/AImageReaderUtils.h>
 #include <camera/StringUtils.h>
+#include <cutils/native_handle.h>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <hidl/Utils.h>
+#include <mediautils/AImageReaderUtils.h>
 
 namespace android {
 namespace hardware {
@@ -28,6 +29,7 @@
 
 using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
 using aimg::AImageReader_getHGBPFromHandle;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 
 // Note: existing data in dst will be gone. Caller still owns the memory of src
 void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst) {
@@ -84,9 +86,9 @@
 
 hardware::camera2::params::OutputConfiguration convertFromHidl(
     const HOutputConfiguration &hOutputConfiguration) {
-    std::vector<sp<IGraphicBufferProducer>> iGBPs;
-    auto &windowHandles = hOutputConfiguration.windowHandles;
-    iGBPs.reserve(windowHandles.size());
+    std::vector<ParcelableSurfaceType> surfaces;
+    auto& windowHandles = hOutputConfiguration.windowHandles;
+    surfaces.reserve(windowHandles.size());
     for (auto &handle : windowHandles) {
         auto igbp = AImageReader_getHGBPFromHandle(handle);
         if (igbp == nullptr) {
@@ -94,10 +96,16 @@
                     __FUNCTION__, handle.getNativeHandle());
             continue;
         }
-        iGBPs.push_back(new H2BGraphicBufferProducer(igbp));
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+        view::Surface surface;
+        surface.graphicBufferProducer = new H2BGraphicBufferProducer(igbp);
+        surfaces.push_back(surface);
+#else
+        surfaces.push_back(new H2BGraphicBufferProducer(igbp));
+#endif
     }
     hardware::camera2::params::OutputConfiguration outputConfiguration(
-        iGBPs, convertFromHidl(hOutputConfiguration.rotation),
+        surfaces, convertFromHidl(hOutputConfiguration.rotation),
         hOutputConfiguration.physicalCameraId,
         hOutputConfiguration.windowGroupId, OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0,
         (windowHandles.size() > 1));
@@ -274,7 +282,8 @@
     hPhysicalCaptureResultInfo.physicalCameraId =
         toString8(physicalCaptureResultInfo.mPhysicalCameraId);
     const camera_metadata_t *rawMetadata =
-        physicalCaptureResultInfo.mPhysicalCameraMetadata.getAndLock();
+        physicalCaptureResultInfo.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+                getAndLock();
     // Try using fmq at first.
     size_t metadata_size = get_camera_metadata_size(rawMetadata);
     if ((metadata_size > 0) && (captureResultMetadataQueue->availableToWrite() > 0)) {
@@ -287,7 +296,8 @@
             hPhysicalCaptureResultInfo.physicalCameraMetadata.metadata(std::move(metadata));
         }
     }
-    physicalCaptureResultInfo.mPhysicalCameraMetadata.unlock(rawMetadata);
+    physicalCaptureResultInfo.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+            unlock(rawMetadata);
     return hPhysicalCaptureResultInfo;
 }
 
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 6c98837..8c7d39e 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -54,6 +54,7 @@
 
 using ICameraService::ROTATION_OVERRIDE_NONE;
 using ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT;
+using android::hardware::camera2::CameraMetadataInfo;
 
 const int32_t kPreviewThreshold = 8;
 const int32_t kNumRequestsTested = 8;
@@ -778,7 +779,7 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+    virtual binder::Status onResultReceived(const CameraMetadataInfo& /*metadata*/,
             const CaptureResultExtras& /*resultExtras*/,
             const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
         return binder::Status::ok();
diff --git a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
index ff58c4a..2f035e7 100644
--- a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
@@ -34,6 +34,7 @@
 
 using namespace android;
 using namespace android::hardware::camera;
+using android::hardware::camera2::CameraMetadataInfo;
 
 // Empty service listener.
 class TestCameraServiceListener : public hardware::BnCameraServiceListener {
@@ -107,7 +108,7 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+    virtual binder::Status onResultReceived(const CameraMetadataInfo& /*metadata*/,
             const CaptureResultExtras& /*resultExtras*/,
             const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
         return binder::Status::ok();
diff --git a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
index a531e10..f00d1e7 100644
--- a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
+++ b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
@@ -296,7 +296,8 @@
     }
 
     metadata.update(ANDROID_SCALER_CROP_REGION, test2xCropRegion[index], 4);
-    res = mapper.updateCaptureResult(&metadata, false/*useZoomRatio*/);
+    res = mapper.updateCaptureResult(&metadata, false /*zoomMethodIsRatio*/,
+                                     true/*requestedZoomRatioIs1*/);
     ASSERT_EQ(res, OK);
     entry = metadata.find(ANDROID_SCALER_CROP_REGION);
     ASSERT_EQ(entry.count, 4U);
@@ -340,7 +341,8 @@
     entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
     EXPECT_NEAR(entry.data.f[0], 2.0f, kMaxAllowedRatioError);
 
-    res = mapper.updateCaptureResult(&metadata, false/*useZoomRatio*/);
+    res = mapper.updateCaptureResult(&metadata, false/*useZoomMethod*/,
+                                     true/*requestedZoomRatioIs1*/);
     ASSERT_EQ(res, OK);
     entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
     EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
@@ -364,7 +366,8 @@
     entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
     EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
 
-    res = mapper.updateCaptureResult(&metadata, false/*useZoomRatio*/);
+    res = mapper.updateCaptureResult(&metadata, false/*zoomMethodIsRatio*/,
+                                     true/*requestedZoomRatioIs1*/);
     ASSERT_EQ(res, OK);
     entry = metadata.find(ANDROID_SCALER_CROP_REGION);
     ASSERT_EQ(entry.count, 4U);
@@ -452,7 +455,8 @@
     entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
     ASSERT_EQ(entry.data.f[0], zoomRatio);
 
-    res = mapper.updateCaptureResult(&metadata, true/*useZoomRatio*/);
+    res = mapper.updateCaptureResult(&metadata, false/*zoomMethodIsRatio*/,
+                                     false/*requestedZoomRatioIs1*/);
     ASSERT_EQ(res, OK);
     entry = metadata.find(ANDROID_SCALER_CROP_REGION);
     ASSERT_EQ(entry.count, 4U);
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index 85bca6f..8f93ee0 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -18,13 +18,14 @@
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
+#include <binder/IServiceManager.h>
+#include <camera/StringUtils.h>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
 #include <gui/Surface.h>
 #include <inttypes.h>
+#include <system/window.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
-#include <camera/StringUtils.h>
-#include <binder/IServiceManager.h>
-#include <system/window.h>
 
 #include "aidl/android/hardware/graphics/common/Dataspace.h"
 
@@ -265,16 +266,24 @@
             }
 
             // Check 4K
-            const auto& gbps = config.getGraphicBufferProducers();
+            const std::vector<ParcelableSurfaceType>& surfaces = config.getSurfaces();
             int32_t width = 0, height = 0;
-            if (gbps.size() > 0) {
-                if (gbps[0] == nullptr) {
+            if (surfaces.size() > 0) {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                if (surfaces[0].isEmpty()) {
+#else
+                if (surfaces[0] == nullptr) {
+#endif
                     ALOGE("%s: Failed to query size due to abandoned surface.",
                             __FUNCTION__);
                     return CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
                 }
 
-                sp<Surface> surface = new Surface(gbps[0], /*useAsync*/false);
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                sp<Surface> surface = surfaces[0].toSurface();
+#else
+                sp<Surface> surface = new Surface(surfaces[0], /*useAsync*/false);
+#endif
                 ANativeWindow *anw = surface.get();
 
                 width = ANativeWindow_getWidth(anw);
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..fd877ed 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -18,21 +18,23 @@
 
 #include "SessionConfigurationUtils.h"
 #include <android/data_space.h>
+#include <camera/StringUtils.h>
+#include <gui/Flags.h>  // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#include <ui/PublicFormat.h>
+#include "../CameraService.h"
 #include "../api2/DepthCompositeStream.h"
 #include "../api2/HeicCompositeStream.h"
+#include "SessionConfigurationUtils.h"
 #include "aidl/android/hardware/graphics/common/Dataspace.h"
 #include "api2/JpegRCompositeStream.h"
 #include "binder/Status.h"
 #include "common/CameraDeviceBase.h"
 #include "common/HalConversionsTemplated.h"
-#include "../CameraService.h"
-#include "device3/aidl/AidlCamera3Device.h"
-#include "device3/hidl/HidlCamera3Device.h"
 #include "device3/Camera3OutputStream.h"
 #include "device3/ZoomRatioMapper.h"
+#include "device3/aidl/AidlCamera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
 #include "system/graphics-base-v1.1.h"
-#include <camera/StringUtils.h>
-#include <ui/PublicFormat.h>
 
 using android::camera3::OutputStreamInfo;
 using android::camera3::OutputStreamInfo;
@@ -827,8 +829,7 @@
     }
 
     for (const auto &it : outputConfigs) {
-        const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
-            it.getGraphicBufferProducers();
+        const std::vector<ParcelableSurfaceType>& surfaces = it.getSurfaces();
         bool deferredConsumer = it.isDeferred();
         bool isConfigurationComplete = it.isComplete();
         const std::string &physicalCameraId = it.getPhysicalCameraId();
@@ -841,12 +842,12 @@
         const CameraMetadata &metadataChosen =
                 physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo;
 
-        size_t numBufferProducers = bufferProducers.size();
+        size_t numSurfaces = surfaces.size();
         bool isStreamInfoValid = false;
         int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
         OutputStreamInfo streamInfo;
 
-        res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType(),
+        res = checkSurfaceType(numSurfaces, deferredConsumer, it.getSurfaceType(),
                                isConfigurationComplete);
         if (!res.isOk()) {
             return res;
@@ -861,7 +862,7 @@
         int timestampBase = it.getTimestampBase();
         // If the configuration is a deferred consumer, or a not yet completed
         // configuration with no buffer producers attached.
-        if (deferredConsumer || (!isConfigurationComplete && numBufferProducers == 0)) {
+        if (deferredConsumer || (!isConfigurationComplete && numSurfaces == 0)) {
             streamInfo.width = it.getWidth();
             streamInfo.height = it.getHeight();
             auto surfaceType = it.getSurfaceType();
@@ -912,26 +913,31 @@
 
             isStreamInfoValid = true;
 
-            if (numBufferProducers == 0) {
+            if (numSurfaces == 0) {
                 continue;
             }
         }
 
-        for (auto& bufferProducer : bufferProducers) {
-            int mirrorMode = it.getMirrorMode(bufferProducer);
+        for (auto& surface_type : surfaces) {
             sp<Surface> surface;
-            res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
-                    logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
-                    streamUseCase, timestampBase, mirrorMode, colorSpace,
-                    /*respectSurfaceSize*/true);
+            int mirrorMode = it.getMirrorMode(surface_type);
+            res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface,
+                                       surface_type
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+                                       .graphicBufferProducer
+#endif
+                                       , logicalCameraId,
+                                       metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
+                                       streamUseCase, timestampBase, mirrorMode, colorSpace,
+                                       /*respectSurfaceSize*/ true);
 
-            if (!res.isOk())
-                return res;
+            if (!res.isOk()) return res;
 
             if (!isStreamInfoValid) {
-                auto status  = mapStream(streamInfo, isCompositeJpegRDisabled, deviceInfo,
-                        static_cast<camera_stream_rotation_t> (it.getRotation()), &streamIdx,
-                        physicalCameraId, groupId, logicalCameraId, streamConfiguration, earlyExit);
+                auto status = mapStream(streamInfo, isCompositeJpegRDisabled, deviceInfo,
+                                        static_cast<camera_stream_rotation_t>(it.getRotation()),
+                                        &streamIdx, physicalCameraId, groupId, logicalCameraId,
+                                        streamConfiguration, earlyExit);
                 if (*earlyExit || !status.isOk()) {
                     return status;
                 }
@@ -1253,14 +1259,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;
 }
 
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 66918c1..6c31d2c 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -150,15 +150,9 @@
 
         // Try other formats if the config from APM is the same as our current config.
         // Some HALs may report its format support incorrectly.
-        if (previousConfig.format == config.format) {
-            if (previousConfig.sample_rate == config.sample_rate) {
-                config.format = getNextFormatToTry(config.format);
-            } else if (!com::android::media::aaudio::sample_rate_conversion()) {
-                ALOGI("%s() - AAudio SRC feature not enabled, different rates! %d != %d",
-                      __func__, previousConfig.sample_rate, config.sample_rate);
-                result = AAUDIO_ERROR_INVALID_RATE;
-                break;
-            }
+        if ((previousConfig.format == config.format) &&
+                (previousConfig.sample_rate == config.sample_rate)) {
+            config.format = getNextFormatToTry(config.format);
         }
 
         ALOGD("%s() %#x %d failed, perhaps due to format or sample rate. Try again with %#x %d",
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index f54de5e..37ccf8a 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -75,6 +75,9 @@
 
     builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
 
+    // Each shared stream will use its own SRC.
+    builder.setSampleRate(AAUDIO_UNSPECIFIED);
+
     result = mStreamInternal->open(builder);
 
     setSampleRate(mStreamInternal->getSampleRate());
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 04fcd6d..bd58fa2 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -144,6 +144,9 @@
         goto error;
     }
 
+    // Use the sample rate of the endpoint as each shared stream should use its own SRC.
+    setSampleRate(endpoint->getSampleRate());
+
     // Is the request compatible with the shared endpoint?
     setFormat(configurationInput.getFormat());
     if (getFormat() == AUDIO_FORMAT_DEFAULT) {
@@ -154,16 +157,6 @@
         goto error;
     }
 
-    setSampleRate(configurationInput.getSampleRate());
-    if (getSampleRate() == AAUDIO_UNSPECIFIED) {
-        setSampleRate(endpoint->getSampleRate());
-    } else if (getSampleRate() != endpoint->getSampleRate()) {
-        ALOGD("%s() mSampleRate = %d, need %d",
-              __func__, getSampleRate(), endpoint->getSampleRate());
-        result = AAUDIO_ERROR_INVALID_RATE;
-        goto error;
-    }
-
     setChannelMask(configurationInput.getChannelMask());
     if (getChannelMask() == AAUDIO_UNSPECIFIED) {
         setChannelMask(endpoint->getChannelMask());