Merge "legacy camera api: Enable zsl if preview frame rate is supported." into sc-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 8fe48c2..716b550 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,8 @@
 [Hook Scripts]
 mainline_hook = ${REPO_ROOT}/frameworks/av/tools/mainline_hook_partial.sh ${REPO_ROOT} ${PREUPLOAD_FILES}
 
+hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
+
 [Builtin Hooks]
 clang_format = true
 
diff --git a/apex/Android.bp b/apex/Android.bp
index 6c45749..b9abd12 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -24,10 +24,8 @@
 apex_defaults {
     name: "com.android.media-defaults",
     updatable: true,
-    java_libs: [
-      "updatable-media",
-      "service-media-s",
-    ],
+    bootclasspath_fragments: ["com.android.media-bootclasspath-fragment"],
+    systemserverclasspath_fragments: ["com.android.media-systemserverclasspath-fragment"],
     multilib: {
         first: {
             // Extractor process runs only with the primary ABI.
@@ -86,6 +84,7 @@
     name: "com.android.media",
     manifest: "manifest.json",
     defaults: ["com.android.media-defaults"],
+    prebuilts: ["current_sdkinfo"],
 }
 
 linker_config {
@@ -94,6 +93,49 @@
     installable: false,
 }
 
+// Encapsulate the contributions made by the com.android.media to the bootclasspath.
+bootclasspath_fragment {
+    name: "com.android.media-bootclasspath-fragment",
+    contents: ["updatable-media"],
+    apex_available: ["com.android.media"],
+
+    api: {
+        stub_libs: [
+            // Stubs for the APIs provided by updatable-media. This has to be
+            // specified explicitly because updatable-media is not a
+            // java_sdk_library.
+            "framework-media",
+        ],
+    },
+
+    // The bootclasspath_fragments that provide APIs on which this depends.
+    fragments: [
+        {
+            apex: "com.android.art",
+            module: "art-bootclasspath-fragment",
+        },
+    ],
+
+    // Additional stubs libraries that this fragment's contents use which are
+    // not provided by another bootclasspath_fragment.
+    additional_stubs: [
+        "android-non-updatable",
+    ],
+
+    // Additional hidden API flag files to override the defaults. This must only be
+    // modified by the Soong or platform compat team.
+    hidden_api: {
+        max_target_o_low_priority: ["hiddenapi/hiddenapi-max-target-o-low-priority.txt"],
+    },
+}
+
+// Encapsulate the contributions made by the com.android.media to the systemserverclasspath.
+systemserverclasspath_fragment {
+    name: "com.android.media-systemserverclasspath-fragment",
+    contents: ["service-media-s"],
+    apex_available: ["com.android.media"],
+}
+
 filegroup {
     name: "com.android.media-androidManifest",
     srcs: ["AndroidManifest-media.xml"],
diff --git a/apex/hiddenapi/OWNERS b/apex/hiddenapi/OWNERS
new file mode 100644
index 0000000..ac8a2b6
--- /dev/null
+++ b/apex/hiddenapi/OWNERS
@@ -0,0 +1,5 @@
+# soong-team@ as the hiddenapi files are tightly coupled with Soong
+file:platform/build/soong:/OWNERS
+
+# compat-team@ for changes to hiddenapi files
+file:tools/platform-compat:/OWNERS
diff --git a/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
new file mode 100644
index 0000000..32bbb10
--- /dev/null
+++ b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
@@ -0,0 +1,6 @@
+Landroid/media/MediaSession2$ControllerInfo;-><init>(Landroid/content/Context;IILjava/lang/String;Landroid/os/IInterface;)V
+Landroid/media/MediaSession2$ControllerInfo;->getPackageName()Ljava/lang/String;
+Landroid/media/MediaSession2$ControllerInfo;->getProvider()Landroid/media/update/MediaSession2Provider$ControllerInfoProvider;
+Landroid/media/MediaSession2$ControllerInfo;->getUid()I
+Landroid/media/MediaSession2$ControllerInfo;->isTrusted()Z
+Landroid/media/MediaSession2$ControllerInfo;->mProvider:Landroid/media/update/MediaSession2Provider$ControllerInfoProvider;
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index f7d194e..604dbb8 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -71,9 +71,10 @@
 }
 
 sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
-        int clientUid, int clientPid)
+        int clientUid, int clientPid, int targetSdkVersion)
 {
-    return CameraBaseT::connect(cameraId, clientPackageName, clientUid, clientPid);
+    return CameraBaseT::connect(cameraId, clientPackageName, clientUid,
+            clientPid, targetSdkVersion);
 }
 
 status_t Camera::reconnect()
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 0b0f584..03439fd 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -152,7 +152,7 @@
 template <typename TCam, typename TCamTraits>
 sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                                const String16& clientPackageName,
-                                               int clientUid, int clientPid)
+                                               int clientUid, int clientPid, int targetSdkVersion)
 {
     ALOGV("%s: connect", __FUNCTION__);
     sp<TCam> c = new TCam(cameraId);
@@ -163,7 +163,7 @@
     if (cs != nullptr) {
         TCamConnectService fnConnectService = TCamTraits::fnConnectService;
         ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
-                                               clientPid, /*out*/ &c->mCamera);
+                                               clientPid, targetSdkVersion, /*out*/ &c->mCamera);
     }
     if (ret.isOk() && c->mCamera != nullptr) {
         IInterface::asBinder(c->mCamera)->linkToDeath(c);
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 873d738..78a77d4 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -82,7 +82,8 @@
     ICamera connect(ICameraClient client,
             int cameraId,
             String opPackageName,
-            int clientUid, int clientPid);
+            int clientUid, int clientPid,
+            int targetSdkVersion);
 
     /**
      * Open a camera device through the new camera API
@@ -92,7 +93,8 @@
             String cameraId,
             String opPackageName,
             @nullable String featureId,
-            int clientUid);
+            int clientUid, int oomScoreOffset,
+            int targetSdkVersion);
 
     /**
      * Add listener for changes to camera device and flashlight state.
@@ -114,13 +116,15 @@
       * corresponding camera ids.
       *
       * @param sessions the set of camera id and session configuration pairs to be queried.
+      * @param targetSdkVersion the target sdk level of the application calling this function.
       * @return true  - the set of concurrent camera id and stream combinations is supported.
       *         false - the set of concurrent camera id and stream combinations is not supported
       *                 OR the method was called with a set of camera ids not returned by
       *                 getConcurrentCameraIds().
       */
     boolean isConcurrentSessionConfigurationSupported(
-            in CameraIdAndSessionConfiguration[] sessions);
+            in CameraIdAndSessionConfiguration[] sessions,
+            int targetSdkVersion);
 
     /**
      * Remove listener for changes to camera device and flashlight state.
@@ -131,7 +135,7 @@
      * Read the static camera metadata for a camera device.
      * Only supported for device HAL versions >= 3.2
      */
-    CameraMetadataNative getCameraCharacteristics(String cameraId);
+    CameraMetadataNative getCameraCharacteristics(String cameraId, int targetSdkVersion);
 
     /**
      * Read in the vendor tag descriptors from the camera module HAL.
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index d6642f3..2bccd87 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -161,7 +161,7 @@
     }
 
     std::vector<int32_t> sensorPixelModesUsed;
-    if ((err = parcel->readParcelableVector(&sensorPixelModesUsed)) != OK) {
+    if ((err = parcel->readInt32Vector(&sensorPixelModesUsed)) != OK) {
         ALOGE("%s: Failed to read sensor pixel mode(s) from parcel", __FUNCTION__);
         return err;
     }
diff --git a/camera/include/camera/Camera.h b/camera/include/camera/Camera.h
index 5579183..58ccd69 100644
--- a/camera/include/camera/Camera.h
+++ b/camera/include/camera/Camera.h
@@ -58,7 +58,7 @@
     typedef ::android::hardware::ICameraClient TCamCallbacks;
     typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
         (const sp<::android::hardware::ICameraClient>&,
-        int, const String16&, int, int,
+        int, const String16&, int, int, int,
         /*out*/
         sp<::android::hardware::ICamera>*);
     static TCamConnectService     fnConnectService;
@@ -81,7 +81,7 @@
     static  sp<Camera>  create(const sp<::android::hardware::ICamera>& camera);
     static  sp<Camera>  connect(int cameraId,
                                 const String16& clientPackageName,
-                                int clientUid, int clientPid);
+                                int clientUid, int clientPid, int targetSdkVersion);
 
             virtual     ~Camera();
 
diff --git a/camera/include/camera/CameraBase.h b/camera/include/camera/CameraBase.h
index 499b0e6..e156994 100644
--- a/camera/include/camera/CameraBase.h
+++ b/camera/include/camera/CameraBase.h
@@ -113,7 +113,7 @@
 
     static sp<TCam>      connect(int cameraId,
                                  const String16& clientPackageName,
-                                 int clientUid, int clientPid);
+                                 int clientUid, int clientPid, int targetSdkVersion);
     virtual void         disconnect();
 
     void                 setListener(const sp<TCamListener>& listener);
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 73cabbf..95ef2b2 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -689,7 +689,9 @@
         return ACAMERA_ERROR_CAMERA_DISCONNECTED;
     }
     CameraMetadata rawMetadata;
-    binder::Status serviceRet = cs->getCameraCharacteristics(String16(cameraIdStr), &rawMetadata);
+    int targetSdkVersion = android_get_application_target_sdk_version();
+    binder::Status serviceRet = cs->getCameraCharacteristics(String16(cameraIdStr),
+            targetSdkVersion, &rawMetadata);
     if (!serviceRet.isOk()) {
         switch(serviceRet.serviceSpecificErrorCode()) {
             case hardware::ICameraService::ERROR_DISCONNECTED:
@@ -735,11 +737,13 @@
 
     sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
     sp<hardware::camera2::ICameraDeviceUser> deviceRemote;
+    int targetSdkVersion = android_get_application_target_sdk_version();
     // No way to get package name from native.
     // Send a zero length package name and let camera service figure it out from UID
     binder::Status serviceRet = cs->connectDevice(
             callbacks, String16(cameraId), String16(""), {},
-            hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
+            hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/0,
+            targetSdkVersion, /*out*/&deviceRemote);
 
     if (!serviceRet.isOk()) {
         ALOGE("%s: connect camera device failed: %s", __FUNCTION__, serviceRet.toString8().string());
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 1609c7b..3d93ba5 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3576,9 +3576,9 @@
      * <p>Not all output formats may be supported in a configuration with
      * an input stream of a particular format. For more details, see
      * android.scaler.availableInputOutputFormatsMap.</p>
-     * <p>The following table describes the minimum required output stream
-     * configurations based on the hardware level
-     * (ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL), prior to Android 12:</p>
+     * <p>For applications targeting SDK version older than 31, the following table
+     * describes the minimum required output stream configurations based on the hardware level
+     * (ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL):</p>
      * <p>Format         | Size                                         | Hardware Level | Notes
      * :-------------:|:--------------------------------------------:|:--------------:|:--------------:
      * JPEG           | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE          | Any            |
@@ -3589,10 +3589,13 @@
      * YUV_420_888    | all output sizes available for JPEG          | FULL           |
      * YUV_420_888    | all output sizes available for JPEG, up to the maximum video size | LIMITED        |
      * IMPLEMENTATION_DEFINED | same as YUV_420_888                  | Any            |</p>
-     * <p>Starting from Android 12, the camera device may not support JPEG sizes smaller than the
-     * minimum of 1080p and the camera sensor active array size. The requirements for
-     * IMPLEMENTATION_DEFINED and YUV_420_888 stay the same. This new minimum required output
-     * stream configurations are illustrated by the table below:</p>
+     * <p>For applications targeting SDK version 31 or newer, if the mobile device declares to be
+     * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CDOES/MEDIA_PERFORMANCE_CLASS.html">media performance class</a> S,
+     * the primary camera devices (first rear/front camera in the camera ID list) will not
+     * support JPEG sizes smaller than 1080p. If the application configures a JPEG stream
+     * smaller than 1080p, the camera device will round up the JPEG image size to at least
+     * 1080p. The requirements for IMPLEMENTATION_DEFINED and YUV_420_888 stay the same.
+     * This new minimum required output stream configurations are illustrated by the table below:</p>
      * <p>Format         | Size                                         | Hardware Level | Notes
      * :-------------:|:--------------------------------------------:|:--------------:|:--------------:
      * JPEG           | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE          | Any            |
@@ -3604,6 +3607,10 @@
      * YUV_420_888    | 320x240 (240p)                               | FULL           | if 240p &lt;= activeArraySize
      * YUV_420_888    | all output sizes available for FULL hardware level, up to the maximum video size | LIMITED        |
      * IMPLEMENTATION_DEFINED | same as YUV_420_888                  | Any            |</p>
+     * <p>For applications targeting SDK version 31 or newer, if the mobile device doesn't declare
+     * to be media performance class S, or if the camera device isn't a primary rear/front
+     * camera, the minimum required output stream configurations are the same as for applications
+     * targeting SDK version older than 31.</p>
      * <p>Refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES for additional
      * mandatory stream configurations on a per-capability basis.</p>
      * <p>Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability for
@@ -9224,10 +9231,10 @@
      * respective color channel provided in
      * ACAMERA_SENSOR_TEST_PATTERN_DATA.</p>
      * <p>For example:</p>
-     * <pre><code>android.control.testPatternData = [0, 0xFFFFFFFF, 0xFFFFFFFF, 0]
+     * <pre><code>ACAMERA_SENSOR_TEST_PATTERN_DATA = [0, 0xFFFFFFFF, 0xFFFFFFFF, 0]
      * </code></pre>
      * <p>All green pixels are 100% green. All red/blue pixels are black.</p>
-     * <pre><code>android.control.testPatternData = [0xFFFFFFFF, 0, 0xFFFFFFFF, 0]
+     * <pre><code>ACAMERA_SENSOR_TEST_PATTERN_DATA = [0xFFFFFFFF, 0, 0xFFFFFFFF, 0]
      * </code></pre>
      * <p>All red pixels are 100% red. Only the odd green pixels
      * are 100% green. All blue pixels are 100% black.</p>
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 0cf390f..9f2f430 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -363,7 +363,8 @@
 
         // Check metadata binder call
         CameraMetadata metadata;
-        res = service->getCameraCharacteristics(cameraId, &metadata);
+        res = service->getCameraCharacteristics(cameraId,
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, &metadata);
         EXPECT_TRUE(res.isOk()) << res;
         EXPECT_FALSE(metadata.isEmpty());
 
@@ -378,8 +379,8 @@
         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
         sp<hardware::camera2::ICameraDeviceUser> device;
         res = service->connectDevice(callbacks, cameraId, String16("meeeeeeeee!"),
-                {}, hardware::ICameraService::USE_CALLING_UID,
-                /*out*/&device);
+                {}, hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/ 0,
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*out*/&device);
         EXPECT_TRUE(res.isOk()) << res;
         ASSERT_NE(nullptr, device.get());
         device->disconnect();
@@ -421,8 +422,8 @@
         {
             SCOPED_TRACE("openNewDevice");
             binder::Status res = service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"),
-                    {}, hardware::ICameraService::USE_CALLING_UID,
-                    /*out*/&device);
+                    {}, hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/ 0,
+                    /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*out*/&device);
             EXPECT_TRUE(res.isOk()) << res;
         }
         auto p = std::make_pair(callbacks, device);
diff --git a/camera/tests/CameraCharacteristicsPermission.cpp b/camera/tests/CameraCharacteristicsPermission.cpp
index 135d2a3..76dc38c 100644
--- a/camera/tests/CameraCharacteristicsPermission.cpp
+++ b/camera/tests/CameraCharacteristicsPermission.cpp
@@ -73,7 +73,8 @@
 
         CameraMetadata metadata;
         std::vector<int32_t> tagsNeedingPermission;
-        rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata);
+        rc = mCameraService->getCameraCharacteristics(cameraIdStr,
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, &metadata);
         ASSERT_TRUE(rc.isOk());
         EXPECT_FALSE(metadata.isEmpty());
         EXPECT_EQ(metadata.removePermissionEntries(CAMERA_METADATA_INVALID_VENDOR_ID,
diff --git a/camera/tests/CameraZSLTests.cpp b/camera/tests/CameraZSLTests.cpp
index 02c6e2a..efd9dae 100644
--- a/camera/tests/CameraZSLTests.cpp
+++ b/camera/tests/CameraZSLTests.cpp
@@ -181,7 +181,8 @@
         }
 
         CameraMetadata metadata;
-        rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata);
+        rc = mCameraService->getCameraCharacteristics(cameraIdStr,
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, &metadata);
         if (!rc.isOk()) {
             // The test is relevant only for cameras with Hal 3.x
             // support.
@@ -207,7 +208,8 @@
 
         rc = mCameraService->connect(this, cameraId,
                 String16("ZSLTest"), hardware::ICameraService::USE_CALLING_UID,
-                hardware::ICameraService::USE_CALLING_PID, &cameraDevice);
+                hardware::ICameraService::USE_CALLING_PID,
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, &cameraDevice);
         EXPECT_TRUE(rc.isOk());
 
         CameraParameters params(cameraDevice->getParameters());
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 03a8dc9..803c4a4 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -16,9 +16,9 @@
         libstagefright_foundation libjpeg libui libgui libcutils liblog \
         libhidlbase libdatasource libaudioclient \
         android.hardware.media.omx@1.0 \
-        media_permission-aidl-cpp
+        framework-permission-aidl-cpp
 
-LOCAL_STATIC_LIBRARIES := media_permission-aidl-cpp
+LOCAL_STATIC_LIBRARIES := framework-permission-aidl-cpp
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -52,7 +52,7 @@
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libmedia liblog libutils libbinder \
         libstagefright_foundation libdatasource libaudioclient \
-        media_permission-aidl-cpp
+        framework-permission-aidl-cpp
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/camera/include \
@@ -90,7 +90,7 @@
         frameworks/av/media/libstagefright \
         frameworks/native/include/media/openmax \
         frameworks/native/include/media/hardware \
-        media_permission-aidl-cpp
+        framework-permission-aidl-cpp
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -119,7 +119,7 @@
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libmedia liblog libutils libbinder \
         libstagefright_foundation libaudioclient \
-        media_permission-aidl-cpp
+        framework-permission-aidl-cpp
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index c86a611..4b41ff8 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -24,7 +24,7 @@
 
 #include <utils/String16.h>
 
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <binder/ProcessState.h>
 #include <media/mediarecorder.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -39,7 +39,7 @@
 
 using namespace android;
 
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 static void usage(const char* name)
 {
@@ -113,10 +113,10 @@
         audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
         attr.source = AUDIO_SOURCE_MIC;
 
-        // TODO b/182392769: use identity util
+        // TODO b/182392769: use attribution source util
         source = new AudioSource(
                 &attr,
-                Identity(),
+                AttributionSourceState(),
                 sampleRate,
                 channels);
     } else {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index b92f236..3a675f6 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -235,6 +235,21 @@
     return Status::OK;
 }
 
+Return<void> CryptoPlugin::getLogMessages(
+        getLogMessages_cb _hidl_cb) {
+    using std::chrono::duration_cast;
+    using std::chrono::milliseconds;
+    using std::chrono::system_clock;
+
+    auto timeMillis = duration_cast<milliseconds>(
+            system_clock::now().time_since_epoch()).count();
+
+    std::vector<LogMessage> logs = {
+            { timeMillis, LogPriority::ERROR, std::string("Not implemented") }};
+    _hidl_cb(drm::V1_4::Status::OK, toHidlVec(logs));
+    return Void();
+}
+
 } // namespace clearkey
 } // namespace V1_4.
 } // namespace drm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 4318af4..6a374f9 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -645,22 +645,17 @@
     auto timeMillis = duration_cast<milliseconds>(
             system_clock::now().time_since_epoch()).count();
 
-    //TODO(b/182525516) Stub out for now
     std::vector<LogMessage> logs = {
-            { timeMillis, LogPriority::DEFAULT, std::string() }};
+            { timeMillis, LogPriority::ERROR, std::string("Not implemented") }};
     _hidl_cb(drm::V1_4::Status::OK, toHidlVec(logs));
     return Void();
 }
 
 Return<bool> DrmPlugin::requiresSecureDecoder(
         const hidl_string& mime, SecurityLevel level) {
-    if (!strncasecmp(mime.c_str(), "video/", 6)) {
-        // Type is video, so check level to see if we require a secure decoder.
-        return level == SecurityLevel::HW_SECURE_DECODE;
-    } else {
-        // Type is not video, so never require a secure decoder.
-        return false;
-    }
+    UNUSED(mime);
+    UNUSED(level);
+    return false;
 }
 
 Return<bool> DrmPlugin::requiresSecureDecoderDefault(const hidl_string& mime) {
@@ -679,22 +674,7 @@
     }
 
     std::vector<uint8_t> sid = toVector(sessionId);
-    sp<Session> session = mSessionLibrary->findSession(sid);
-    if (!session.get()) {
-        return Status::ERROR_DRM_SESSION_NOT_OPENED;
-    }
-
-    std::map<std::vector<uint8_t>, std::string>::iterator itr =
-            mPlaybackId.find(sid);
-    if (itr != mPlaybackId.end()) {
-        mPlaybackId[sid] = playbackId;
-    } else {
-        if (!mPlaybackId.insert(
-                std::pair<std::vector<uint8_t>, std::string>(sid, playbackId)).second) {
-            ALOGE("Failed to set playback Id");
-            return Status::ERROR_DRM_UNKNOWN;
-        }
-    }
+    mPlaybackId[sid] = playbackId;
     return Status::OK;
 }
 
@@ -766,21 +746,24 @@
     };
 
     // Set the setPlaybackId metric.
-    DrmMetricGroup::Attribute setPlaybackIdOKAttribute = {
-      "status", DrmMetricGroup::ValueType::INT64_TYPE,
-      (int64_t) Status::OK, 0.0, ""
-    };
-    std::string playbackId = mPlaybackId.begin()->second;
-    DrmMetricGroup::Value setPlaybackIdMetricValue = {
-      "value", DrmMetricGroup::ValueType::STRING_TYPE, 0, 0,  playbackId.c_str()
-    };
+    std::vector<DrmMetricGroup::Attribute> sids;
+    std::vector<DrmMetricGroup::Value> playbackIds;
+    for (const auto&[key, value] : mPlaybackId) {
+        std::string sid(key.begin(), key.end());
+        DrmMetricGroup::Attribute sessionIdAttribute = {
+            "sid", DrmMetricGroup::ValueType::STRING_TYPE, 0, 0, sid };
+        sids.push_back(sessionIdAttribute);
+
+        DrmMetricGroup::Value playbackIdMetricValue = {
+            "playbackId", DrmMetricGroup::ValueType::STRING_TYPE, 0, 0, value };
+        playbackIds.push_back(playbackIdMetricValue);
+    }
     DrmMetricGroup::Metric setPlaybackIdMetric = {
-      "set_playback_id", { setPlaybackIdOKAttribute }, { setPlaybackIdMetricValue }
-    };
+            "set_playback_id", { sids }, { playbackIds }};
 
-    DrmMetricGroup metrics = {{ openSessionMetric, closeSessionMetric,
-                                closeSessionNotOpenedMetric, setPlaybackIdMetric }};
-
+    DrmMetricGroup metrics = {
+            { openSessionMetric, closeSessionMetric,
+              closeSessionNotOpenedMetric, setPlaybackIdMetric }};
     _hidl_cb(Status::OK, hidl_vec<DrmMetricGroup>({metrics}));
     return Void();
 }
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
index a7b2427..b272a83 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
@@ -17,7 +17,7 @@
 #ifndef CLEARKEY_CRYPTO_PLUGIN_H_
 #define CLEARKEY_CRYPTO_PLUGIN_H_
 
-#include <android/hardware/drm/1.2/ICryptoPlugin.h>
+#include <android/hardware/drm/1.4/ICryptoPlugin.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 
 #include <mutex>
@@ -56,7 +56,7 @@
 
 typedef drm::V1_2::Status Status_V1_2;
 
-struct CryptoPlugin : public drm::V1_2::ICryptoPlugin {
+struct CryptoPlugin : public drm::V1_4::ICryptoPlugin {
     explicit CryptoPlugin(const hidl_vec<uint8_t>& sessionId) {
         mInitStatus = setMediaDrmSession(sessionId);
     }
@@ -104,6 +104,8 @@
 
     Return<Status> getInitStatus() const { return mInitStatus; }
 
+    Return<void> getLogMessages(
+            getLogMessages_cb _hidl_cb);
 private:
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN(CryptoPlugin);
 
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index 332696d..342d771 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -289,13 +289,14 @@
     mOutputDelayRingBufferFilled = 0;
     mBuffersInfo.clear();
 
-    // To make the codec behave the same before and after a reset, we need to invalidate the
-    // streaminfo struct. This does that:
-    mStreamInfo->sampleRate = 0; // TODO: mStreamInfo is read only
-
+    status_t status = UNKNOWN_ERROR;
+    if (mAACDecoder) {
+        aacDecoder_Close(mAACDecoder);
+        status = initDecoder();
+    }
     mSignalledError = false;
 
-    return C2_OK;
+    return status == OK ? C2_OK : C2_CORRUPTED;
 }
 
 void C2SoftAacDec::onReset() {
@@ -514,8 +515,8 @@
 
                 // TODO: error handling, proper usage, etc.
                 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-                c2_status_t err = pool->fetchLinearBlock(
-                        numSamples * sizeof(int16_t), usage, &block);
+                size_t bufferSize = numSamples * sizeof(int16_t);
+                c2_status_t err = pool->fetchLinearBlock(bufferSize, usage, &block);
                 if (err != C2_OK) {
                     ALOGD("failed to fetch a linear block (%d)", err);
                     return std::bind(fillEmptyWork, _1, C2_NO_MEMORY);
@@ -529,7 +530,7 @@
                     mSignalledError = true;
                     return std::bind(fillEmptyWork, _1, C2_CORRUPTED);
                 }
-                return [buffer = createLinearBuffer(block)](
+                return [buffer = createLinearBuffer(block, 0, bufferSize)](
                         const std::unique_ptr<C2Work> &work) {
                     work->result = C2_OK;
                     C2FrameData &output = work->worklets.front()->output;
diff --git a/media/codec2/components/amr_nb_wb/C2SoftAmrDec.cpp b/media/codec2/components/amr_nb_wb/C2SoftAmrDec.cpp
index c08e02b..e92d38d 100644
--- a/media/codec2/components/amr_nb_wb/C2SoftAmrDec.cpp
+++ b/media/codec2/components/amr_nb_wb/C2SoftAmrDec.cpp
@@ -143,7 +143,7 @@
     if (!mIsWide) {
         Speech_Decode_Frame_reset(mAmrHandle);
     } else {
-        pvDecoder_AmrWb_Reset(mAmrHandle, 0 /* reset_all */);
+        pvDecoder_AmrWb_Reset(mAmrHandle, 1 /* reset_all */);
     }
     mSignalledError = false;
     mSignalledOutputEos = false;
@@ -361,7 +361,13 @@
 
     work->worklets.front()->output.flags = work->input.flags;
     work->worklets.front()->output.buffers.clear();
-    work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
+    // we filled the output buffer to (intptr_t)output - (intptr_t)wView.data()
+    // use calOutSize as that contains the expected number of samples
+    ALOGD_IF(calOutSize != ((intptr_t)output - (intptr_t)wView.data()),
+            "Expected %zu output bytes, but filled %lld",
+             calOutSize, (long long)((intptr_t)output - (intptr_t)wView.data()));
+    work->worklets.front()->output.buffers.push_back(
+            createLinearBuffer(block, 0, calOutSize));
     work->worklets.front()->output.ordinal = work->input.ordinal;
     if (eos) {
         mSignalledOutputEos = true;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index 0b121ad..d65ffa5 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -393,6 +393,61 @@
                                          C2P<C2StreamPictureQuantizationTuning::output> &me) {
         (void)mayBlock;
         (void)me;
+
+        // TODO: refactor with same algorithm in the SetQp()
+        int32_t iMin = DEFAULT_I_QP_MIN, pMin = DEFAULT_P_QP_MIN, bMin = DEFAULT_B_QP_MIN;
+        int32_t iMax = DEFAULT_I_QP_MAX, pMax = DEFAULT_P_QP_MAX, bMax = DEFAULT_B_QP_MAX;
+
+        for (size_t i = 0; i < me.v.flexCount(); ++i) {
+            const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+
+            if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+                iMax = layer.max;
+                iMin = layer.min;
+                ALOGV("iMin %d iMax %d", iMin, iMax);
+            } else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+                pMax = layer.max;
+                pMin = layer.min;
+                ALOGV("pMin %d pMax %d", pMin, pMax);
+            } else if (layer.type_ == C2Config::picture_type_t(B_FRAME)) {
+                bMax = layer.max;
+                bMin = layer.min;
+                ALOGV("bMin %d bMax %d", bMin, bMax);
+            }
+        }
+
+        ALOGV("PictureQuantizationSetter(entry): i %d-%d p %d-%d b %d-%d",
+              iMin, iMax, pMin, pMax, bMin, bMax);
+
+        // ensure we have legal values
+        iMax = std::clamp(iMax, CODEC_QP_MIN, CODEC_QP_MAX);
+        iMin = std::clamp(iMin, CODEC_QP_MIN, CODEC_QP_MAX);
+        pMax = std::clamp(pMax, CODEC_QP_MIN, CODEC_QP_MAX);
+        pMin = std::clamp(pMin, CODEC_QP_MIN, CODEC_QP_MAX);
+        bMax = std::clamp(bMax, CODEC_QP_MIN, CODEC_QP_MAX);
+        bMin = std::clamp(bMin, CODEC_QP_MIN, CODEC_QP_MAX);
+
+        // put them back into the structure
+        for (size_t i = 0; i < me.v.flexCount(); ++i) {
+            const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+
+            if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+                me.set().m.values[i].max = iMax;
+                me.set().m.values[i].min = iMin;
+            }
+            if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+                me.set().m.values[i].max = pMax;
+                me.set().m.values[i].min = pMin;
+            }
+            if (layer.type_ == C2Config::picture_type_t(B_FRAME)) {
+                me.set().m.values[i].max = bMax;
+                me.set().m.values[i].min = bMin;
+            }
+        }
+
+        ALOGV("PictureQuantizationSetter(exit): i %d-%d p %d-%d b %d-%d",
+              iMin, iMax, pMin, pMax, bMin, bMax);
+
         return C2R::Ok();
     }
 
@@ -765,10 +820,11 @@
     s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL;
     s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP;
 
-    // these are the ones we're going to set, so want them to default ....
-    // to the DEFAULT values for the codec instea dof CODEC_ bounding
-    int32_t iMin = INT32_MIN, pMin = INT32_MIN, bMin = INT32_MIN;
-    int32_t iMax = INT32_MAX, pMax = INT32_MAX, bMax = INT32_MAX;
+    // TODO: refactor with same algorithm in the PictureQuantizationSetter()
+    int32_t iMin = DEFAULT_I_QP_MIN, pMin = DEFAULT_P_QP_MIN, bMin = DEFAULT_B_QP_MIN;
+    int32_t iMax = DEFAULT_I_QP_MAX, pMax = DEFAULT_P_QP_MAX, bMax = DEFAULT_B_QP_MAX;
+
+    IntfImpl::Lock lock = mIntf->lock();
 
     std::shared_ptr<C2StreamPictureQuantizationTuning::output> qp =
                     mIntf->getPictureQuantization_l();
@@ -790,22 +846,6 @@
         }
     }
 
-    // INT32_{MIN,MAX} means unspecified, so use the codec's default
-    if (iMax == INT32_MAX) iMax = DEFAULT_I_QP_MAX;
-    if (iMin == INT32_MIN) iMin = DEFAULT_I_QP_MIN;
-    if (pMax == INT32_MAX) pMax = DEFAULT_P_QP_MAX;
-    if (pMin == INT32_MIN) pMin = DEFAULT_P_QP_MIN;
-    if (bMax == INT32_MAX) bMax = DEFAULT_B_QP_MAX;
-    if (bMin == INT32_MIN) bMin = DEFAULT_B_QP_MIN;
-
-    // ensure we have legal values
-    iMax = std::clamp(iMax, CODEC_QP_MIN, CODEC_QP_MAX);
-    iMin = std::clamp(iMin, CODEC_QP_MIN, CODEC_QP_MAX);
-    pMax = std::clamp(pMax, CODEC_QP_MIN, CODEC_QP_MAX);
-    pMin = std::clamp(pMin, CODEC_QP_MIN, CODEC_QP_MAX);
-    bMax = std::clamp(bMax, CODEC_QP_MIN, CODEC_QP_MAX);
-    bMin = std::clamp(bMin, CODEC_QP_MIN, CODEC_QP_MAX);
-
     s_qp_ip.u4_i_qp_max = iMax;
     s_qp_ip.u4_i_qp_min = iMin;
     s_qp_ip.u4_p_qp_max = pMax;
@@ -818,7 +858,7 @@
     s_qp_ip.u4_p_qp = std::clamp(DEFAULT_P_QP, pMin, pMax);
     s_qp_ip.u4_b_qp = std::clamp(DEFAULT_B_QP, bMin, bMax);
 
-    ALOGV("setting QP: i %d-%d p %d-%d b %d-%d", iMin, iMax, pMin, pMax, bMin, bMax);
+    ALOGV("setQp(): i %d-%d p %d-%d b %d-%d", iMin, iMax, pMin, pMax, bMin, bMax);
 
 
     s_qp_ip.u4_timestamp_high = -1;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.h b/media/codec2/components/avc/C2SoftAvcEnc.h
index baf33e2..1fecd9e 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.h
+++ b/media/codec2/components/avc/C2SoftAvcEnc.h
@@ -99,8 +99,10 @@
 #define STRLENGTH                   500
 #define DEFAULT_CONSTRAINED_INTRA   0
 
-/** limits as specified by h264 */
-#define CODEC_QP_MIN                0
+/** limits as specified by h264
+ *  (QP_MIN==4 is actually a limitation of this SW codec, not the H.264 standard)
+ **/
+#define CODEC_QP_MIN                4
 #define CODEC_QP_MAX                51
 
 
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index dfad226..6c4b7d9 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -592,21 +592,11 @@
 }
 
 std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
-        const std::shared_ptr<C2LinearBlock> &block) {
-    return createLinearBuffer(block, block->offset(), block->size());
-}
-
-std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
         const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
     return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
 }
 
 std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
-        const std::shared_ptr<C2GraphicBlock> &block) {
-    return createGraphicBuffer(block, C2Rect(block->width(), block->height()));
-}
-
-std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
         const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
     return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
 }
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index 22d5714..e5e16d8 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -140,15 +140,9 @@
 
 
     std::shared_ptr<C2Buffer> createLinearBuffer(
-            const std::shared_ptr<C2LinearBlock> &block);
-
-    std::shared_ptr<C2Buffer> createLinearBuffer(
             const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size);
 
     std::shared_ptr<C2Buffer> createGraphicBuffer(
-            const std::shared_ptr<C2GraphicBlock> &block);
-
-    std::shared_ptr<C2Buffer> createGraphicBuffer(
             const std::shared_ptr<C2GraphicBlock> &block,
             const C2Rect &crop);
 
diff --git a/media/codec2/components/g711/C2SoftG711Dec.cpp b/media/codec2/components/g711/C2SoftG711Dec.cpp
index f9299af..f952f22 100644
--- a/media/codec2/components/g711/C2SoftG711Dec.cpp
+++ b/media/codec2/components/g711/C2SoftG711Dec.cpp
@@ -199,7 +199,7 @@
 
     work->worklets.front()->output.flags = work->input.flags;
     work->worklets.front()->output.buffers.clear();
-    work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
+    work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
     work->worklets.front()->output.ordinal = work->input.ordinal;
 
     if (eos) {
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 76345ae..f857e87 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -26,6 +26,11 @@
 #include <media/stagefright/foundation/MediaDefs.h>
 
 namespace android {
+namespace {
+
+constexpr uint8_t NEUTRAL_UV_VALUE = 128;
+
+}  // namespace
 
 // codecname set and passed in as a compile flag from Android.bp
 constexpr char COMPONENT_NAME[] = CODECNAME;
@@ -51,8 +56,8 @@
         DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
             .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
             .withFields({
-                C2F(mSize, width).inRange(2, 2048, 2),
-                C2F(mSize, height).inRange(2, 2048, 2),
+                C2F(mSize, width).inRange(2, 4096, 2),
+                C2F(mSize, height).inRange(2, 4096, 2),
             })
             .withSetter(SizeSetter)
             .build());
@@ -65,12 +70,14 @@
                                               C2Config::PROFILE_AV1_1}),
                                   C2F(mProfileLevel, level)
                                       .oneOf({
-                                          C2Config::LEVEL_AV1_2,
-                                          C2Config::LEVEL_AV1_2_1,
-                                          C2Config::LEVEL_AV1_2_2,
-                                          C2Config::LEVEL_AV1_3,
-                                          C2Config::LEVEL_AV1_3_1,
-                                          C2Config::LEVEL_AV1_3_2,
+                                          C2Config::LEVEL_AV1_2, C2Config::LEVEL_AV1_2_1,
+                                          C2Config::LEVEL_AV1_2_2, C2Config::LEVEL_AV1_2_3,
+                                          C2Config::LEVEL_AV1_3, C2Config::LEVEL_AV1_3_1,
+                                          C2Config::LEVEL_AV1_3_2, C2Config::LEVEL_AV1_3_3,
+                                          C2Config::LEVEL_AV1_4, C2Config::LEVEL_AV1_4_1,
+                                          C2Config::LEVEL_AV1_4_2, C2Config::LEVEL_AV1_4_3,
+                                          C2Config::LEVEL_AV1_5, C2Config::LEVEL_AV1_5_1,
+                                          C2Config::LEVEL_AV1_5_2, C2Config::LEVEL_AV1_5_3,
                                       })})
                      .withSetter(ProfileLevelSetter, mSize)
                      .build());
@@ -462,7 +469,8 @@
                                         const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
                                         size_t srcYStride, size_t srcUStride, size_t srcVStride,
                                         size_t dstYStride, size_t dstUVStride,
-                                        uint32_t width, uint32_t height) {
+                                        uint32_t width, uint32_t height,
+                                        bool isMonochrome) {
 
   for (size_t i = 0; i < height; ++i) {
     memcpy(dstY, srcY, width);
@@ -470,6 +478,17 @@
     dstY += dstYStride;
   }
 
+  if (isMonochrome) {
+    // Fill with neutral U/V values.
+    for (size_t i = 0; i < height / 2; ++i) {
+      memset(dstV, NEUTRAL_UV_VALUE, width / 2);
+      memset(dstU, NEUTRAL_UV_VALUE, width / 2);
+      dstV += dstUVStride;
+      dstU += dstUVStride;
+    }
+    return;
+  }
+
   for (size_t i = 0; i < height / 2; ++i) {
     memcpy(dstV, srcV, width / 2);
     srcV += srcVStride;
@@ -555,7 +574,7 @@
     const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
     size_t srcYStride, size_t srcUStride, size_t srcVStride,
     size_t dstYStride, size_t dstUVStride,
-    size_t width, size_t height) {
+    size_t width, size_t height, bool isMonochrome) {
 
   for (size_t y = 0; y < height; ++y) {
     for (size_t x = 0; x < width; ++x) {
@@ -566,6 +585,17 @@
     dstY += dstYStride;
   }
 
+  if (isMonochrome) {
+    // Fill with neutral U/V values.
+    for (size_t y = 0; y < (height + 1) / 2; ++y) {
+      memset(dstV, NEUTRAL_UV_VALUE, (width + 1) / 2);
+      memset(dstU, NEUTRAL_UV_VALUE, (width + 1) / 2);
+      dstV += dstUVStride;
+      dstU += dstUVStride;
+    }
+    return;
+  }
+
   for (size_t y = 0; y < (height + 1) / 2; ++y) {
     for (size_t x = 0; x < (width + 1) / 2; ++x) {
       dstU[x] = (uint8_t)(srcU[x] >> 2);
@@ -621,8 +651,16 @@
     }
   }
 
-  // TODO(vigneshv): Add support for monochrome videos since AV1 supports it.
-  CHECK(buffer->image_format == libgav1::kImageFormatYuv420);
+  if (!(buffer->image_format == libgav1::kImageFormatYuv420 ||
+        buffer->image_format == libgav1::kImageFormatMonochrome400)) {
+    ALOGE("image_format %d not supported", buffer->image_format);
+    mSignalledError = true;
+    work->workletsProcessed = 1u;
+    work->result = C2_CORRUPTED;
+    return false;
+  }
+  const bool isMonochrome =
+      buffer->image_format == libgav1::kImageFormatMonochrome400;
 
   std::shared_ptr<C2GraphicBlock> block;
   uint32_t format = HAL_PIXEL_FORMAT_YV12;
@@ -634,6 +672,13 @@
     if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
         defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
         defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
+      if (buffer->image_format != libgav1::kImageFormatYuv420) {
+        ALOGE("Only YUV420 output is supported when targeting RGBA_1010102");
+        mSignalledError = true;
+        work->result = C2_OMITTED;
+        work->workletsProcessed = 1u;
+        return false;
+      }
       format = HAL_PIXEL_FORMAT_RGBA_1010102;
     }
   }
@@ -680,21 +725,18 @@
           (uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
           srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight);
     } else {
-      convertYUV420Planar16ToYUV420Planar(dstY, dstU, dstV,
-                                          srcY, srcU, srcV,
-                                          srcYStride / 2, srcUStride / 2, srcVStride / 2,
-                                          dstYStride, dstUVStride,
-                                          mWidth, mHeight);
+      convertYUV420Planar16ToYUV420Planar(
+          dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
+          srcVStride / 2, dstYStride, dstUVStride, mWidth, mHeight,
+          isMonochrome);
     }
   } else {
     const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
     const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
     const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
-    copyOutputBufferToYV12Frame(dstY, dstU, dstV,
-                                srcY, srcU, srcV,
-                                srcYStride, srcUStride, srcVStride,
-                                dstYStride, dstUVStride,
-                                mWidth, mHeight);
+    copyOutputBufferToYV12Frame(
+        dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+        dstYStride, dstUVStride, mWidth, mHeight, isMonochrome);
   }
   finishWork(buffer->user_private_data, work, std::move(block));
   block = nullptr;
diff --git a/media/codec2/components/opus/C2SoftOpusEnc.cpp b/media/codec2/components/opus/C2SoftOpusEnc.cpp
index b47275f..370d33c 100644
--- a/media/codec2/components/opus/C2SoftOpusEnc.cpp
+++ b/media/codec2/components/opus/C2SoftOpusEnc.cpp
@@ -78,6 +78,19 @@
                 .build());
 
         addParameter(
+            DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
+                .withDefault(new C2StreamBitrateModeTuning::output(
+                        0u, C2Config::BITRATE_VARIABLE))
+                .withFields({
+                    C2F(mBitrateMode, value).oneOf({
+                        C2Config::BITRATE_CONST,
+                        C2Config::BITRATE_VARIABLE})
+                })
+                .withSetter(
+                    Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
+                .build());
+
+        addParameter(
                 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
                 .withDefault(new C2StreamBitrateInfo::output(0u, 128000))
                 .withFields({C2F(mBitrate, value).inRange(500, 512000)})
@@ -100,12 +113,14 @@
     uint32_t getSampleRate() const { return mSampleRate->value; }
     uint32_t getChannelCount() const { return mChannelCount->value; }
     uint32_t getBitrate() const { return mBitrate->value; }
+    uint32_t getBitrateMode() const { return mBitrateMode->value; }
     uint32_t getComplexity() const { return mComplexity->value; }
 
 private:
     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+    std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
     std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
 };
@@ -135,6 +150,7 @@
     mSampleRate = mIntf->getSampleRate();
     mChannelCount = mIntf->getChannelCount();
     uint32_t bitrate = mIntf->getBitrate();
+    uint32_t bitrateMode = mIntf->getBitrateMode();
     int complexity = mIntf->getComplexity();
     mNumSamplesPerFrame = mSampleRate / (1000 / mFrameDurationMs);
     mNumPcmBytesPerInputFrame =
@@ -189,14 +205,24 @@
         return C2_BAD_VALUE;
     }
 
-    // Constrained VBR
-    if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR(1) != OPUS_OK)) {
-        ALOGE("failed to set vbr type");
-        return C2_BAD_VALUE;
-    }
-    if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR_CONSTRAINT(1) !=
-            OPUS_OK)) {
-        ALOGE("failed to set vbr constraint");
+    if (bitrateMode == C2Config::BITRATE_VARIABLE) {
+        // Constrained VBR
+        if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR(1) != OPUS_OK)) {
+            ALOGE("failed to set vbr type");
+            return C2_BAD_VALUE;
+        }
+        if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR_CONSTRAINT(1) !=
+                OPUS_OK)) {
+            ALOGE("failed to set vbr constraint");
+            return C2_BAD_VALUE;
+        }
+    } else if (bitrateMode == C2Config::BITRATE_CONST) {
+        if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR(0) != OPUS_OK)) {
+            ALOGE("failed to set cbr type");
+            return C2_BAD_VALUE;
+        }
+    } else {
+        ALOGE("unknown bitrate mode");
         return C2_BAD_VALUE;
     }
 
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 7e9090f..7486d27 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -635,7 +635,8 @@
             }
             work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
             work->worklets.front()->output.buffers.clear();
-            std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block);
+            std::shared_ptr<C2Buffer> buffer =
+                createLinearBuffer(block, 0, encoded_packet->data.frame.sz);
             if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) {
                 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
                         0u /* stream id */, C2Config::SYNC_FRAME));
diff --git a/media/codec2/components/xaac/C2SoftXaacDec.cpp b/media/codec2/components/xaac/C2SoftXaacDec.cpp
index 6deafda..8bf4b72 100644
--- a/media/codec2/components/xaac/C2SoftXaacDec.cpp
+++ b/media/codec2/components/xaac/C2SoftXaacDec.cpp
@@ -361,9 +361,8 @@
     C2WriteView wView = block->map().get();
     int16_t* outBuffer = reinterpret_cast<int16_t*>(wView.data());
     memcpy(outBuffer, mOutputDrainBuffer, mOutputDrainBufferWritePos);
-    mOutputDrainBufferWritePos = 0;
 
-    auto fillWork = [buffer = createLinearBuffer(block)](
+    auto fillWork = [buffer = createLinearBuffer(block, 0, mOutputDrainBufferWritePos)](
         const std::unique_ptr<C2Work>& work) {
         uint32_t flags = 0;
         if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
@@ -376,6 +375,9 @@
         work->worklets.front()->output.ordinal = work->input.ordinal;
         work->workletsProcessed = 1u;
     };
+
+    mOutputDrainBufferWritePos = 0;
+
     if (work && work->input.ordinal.frameIndex == c2_cntr64_t(mCurFrameIndex)) {
         fillWork(work);
     } else {
diff --git a/media/codec2/core/include/C2Buffer.h b/media/codec2/core/include/C2Buffer.h
index a5d6fbf..abe343b 100644
--- a/media/codec2/core/include/C2Buffer.h
+++ b/media/codec2/core/include/C2Buffer.h
@@ -898,6 +898,12 @@
      * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
      * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
      *
+     * \note The returned buffer may have a larger capacity than requested. In this case the
+     * larger (returned) capacity may be fully used.
+     *
+     * \note There is no guarantee on the alignedness of the returned block. The only guarantee is
+     * that its capacity is equal to or larger than the requested capacity.
+     *
      * \param capacity the size of requested block.
      * \param usage    the memory usage info for the requested block. Returned blocks will be
      *                 optimized for this usage, but may be used with any usage. One exception:
@@ -926,6 +932,12 @@
      * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
      * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
      *
+     * \note The returned buffer may have a larger capacity than requested. In this case the
+     * larger (returned) capacity may be fully used.
+     *
+     * \note There is no guarantee on the alignedness of the returned block. The only guarantee is
+     * that its capacity is equal to or larger than the requested capacity.
+     *
      * \param capacity the size of requested circular block. (note: the size of the obtained
      *                 block could be slightly larger, e.g. to accommodate any system-required
      *                 alignment)
@@ -956,6 +968,12 @@
      * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
      * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
      *
+     * \note The returned buffer may have a larger capacity (width and height) than requested. In
+     * this case the larger (returned) capacity may be fully used.
+     *
+     * \note There is no guarantee on the alignedness of the returned block. The only guarantee is
+     * that its capacity is equal to or larger than the requested capacity (width and height).
+     *
      * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
      *               to accommodate any system-required alignment)
      * \param height the height of requested block (the obtained block could be slightly larger,
@@ -1000,6 +1018,12 @@
      * fence is signalled when the temporary restriction on fetch is lifted.
      * e.g. more memory is available to fetch because some meomory or prior blocks were released.
      *
+     * \note The returned buffer may have a larger capacity than requested. In this case the
+     * larger (returned) capacity may be fully used.
+     *
+     * \note There is no guarantee on the alignedness of the returned block. The only guarantee is
+     * that its capacity is equal to or larger than the requested capacity.
+     *
      * \param capacity the size of requested block.
      * \param usage    the memory usage info for the requested block. Returned blocks will be
      *                 optimized for this usage, but may be used with any usage. One exception:
@@ -1039,6 +1063,12 @@
      * fence is signalled when the temporary restriction on fetch is lifted.
      * e.g. more memory is available to fetch because some meomory or prior blocks were released.
      *
+     * \note The returned buffer may have a larger capacity (width and height) than requested. In
+     * this case the larger (returned) capacity may be fully used.
+     *
+     * \note There is no guarantee on the alignedness of the returned block. The only guarantee is
+     * that its capacity is equal to or larger than the requested capacity (width and height).
+     *
      * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
      *               to accommodate any system-required alignment)
      * \param height the height of requested block (the obtained block could be slightly larger,
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 9d9ed70..2cc7ab7 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -262,6 +262,8 @@
     kParamIndexTunneledMode, // struct
     kParamIndexTunnelHandle, // int32[]
     kParamIndexTunnelSystemTime, // int64
+    kParamIndexTunnelHoldRender, // bool
+    kParamIndexTunnelStartRender, // bool
 
     // dmabuf allocator
     kParamIndexStoreDmaBufUsage,  // store, struct
@@ -572,7 +574,6 @@
     PROFILE_MPEGH_HIGH,                         ///< MPEG-H High
     PROFILE_MPEGH_LC,                           ///< MPEG-H Low-complexity
     PROFILE_MPEGH_BASELINE,                     ///< MPEG-H Baseline
-
 };
 
 enum C2Config::level_t : uint32_t {
@@ -2366,22 +2367,49 @@
         C2PortTunnelSystemTime;
 constexpr char C2_PARAMKEY_OUTPUT_RENDER_TIME[] = "output.render-time";
 
-C2ENUM(C2PlatformConfig::encoding_quality_level_t, uint32_t,
-    NONE,
-    S_HANDHELD,
-    S_HANDHELD_PC
-);
 
-namespace android {
+/**
+ * Tunneled mode video peek signaling flag.
+ *
+ * When a video frame is pushed to the decoder with this parameter set to true,
+ * the decoder must decode the frame, signal partial completion, and hold on the
+ * frame until C2StreamTunnelStartRender is set to true (which resets this
+ * flag). Flush will also result in the frames being returned back to the
+ * client (but not rendered).
+ */
+typedef C2StreamParam<C2Info, C2EasyBoolValue, kParamIndexTunnelHoldRender>
+        C2StreamTunnelHoldRender;
+constexpr char C2_PARAMKEY_TUNNEL_HOLD_RENDER[] = "output.tunnel-hold-render";
+
+/**
+ * Tunneled mode video peek signaling flag.
+ *
+ * Upon receiving this flag, the decoder shall set C2StreamTunnelHoldRender to
+ * false, which shall cause any frames held for rendering to be immediately
+ * displayed, regardless of their timestamps.
+*/
+typedef C2StreamParam<C2Info, C2EasyBoolValue, kParamIndexTunnelStartRender>
+        C2StreamTunnelStartRender;
+constexpr char C2_PARAMKEY_TUNNEL_START_RENDER[] = "output.tunnel-start-render";
 
 /**
  * Encoding quality level signaling.
+ *
+ * Signal the 'minimum encoding quality' introduced in Android 12/S. It indicates
+ * whether the underlying codec is expected to take extra steps to ensure quality meets the
+ * appropriate minimum. A value of NONE indicates that the codec is not to apply
+ * any minimum quality bar requirements. Other values indicate that the codec is to apply
+ * a minimum quality bar, with the exact quality bar being decided by the parameter value.
  */
 typedef C2GlobalParam<C2Setting,
         C2SimpleValueStruct<C2EasyEnum<C2PlatformConfig::encoding_quality_level_t>>,
         kParamIndexEncodingQualityLevel> C2EncodingQualityLevel;
+constexpr char C2_PARAMKEY_ENCODING_QUALITY_LEVEL[] = "algo.encoding-quality-level";
 
-}
+C2ENUM(C2PlatformConfig::encoding_quality_level_t, uint32_t,
+    NONE = 0,
+    S_HANDHELD = 1              // corresponds to VMAF=70
+);
 
 /// @}
 
diff --git a/media/codec2/core/include/C2Work.h b/media/codec2/core/include/C2Work.h
index 67084cc..794402f 100644
--- a/media/codec2/core/include/C2Work.h
+++ b/media/codec2/core/include/C2Work.h
@@ -145,10 +145,35 @@
          */
         FLAG_INCOMPLETE = (1 << 3),
         /**
+         * This frame has been corrected due to a bitstream error. This is a hint, and in most cases
+         * can be ignored. This flag can be set by components on their output to signal the clients
+         * that errors may be present but the frame should be used nonetheless. It can also be set
+         * by clients to signal that the input frame has been corrected, but nonetheless should be
+         * processed.
+         */
+        FLAG_CORRECTED = (1 << 4),
+        /**
+         * This frame is corrupt due to a bitstream error. This is similar to FLAG_CORRECTED,
+         * with the exception that this is a hint that downstream components should not process this
+         * frame.
+         * <p>
+         * If set on the input by the client, the input is likely non-processable and should be
+         * handled similarly to uncorrectable bitstream error detected. For components that operat
+         * on whole access units, this flag can be propagated to the output. Other components should
+         * aim to detect access unit boundaries to determine if any part of the input frame can be
+         * processed.
+         * <p>
+         * If set by the component, this signals to the client that the output is non-usable -
+         * including possibly the metadata that may also be non-usable; -- however, the component
+         * will try to recover on successive input frames.
+         */
+        FLAG_CORRUPT = (1 << 5),
+
+        /**
          * This frame contains only codec-specific configuration data, and no actual access unit.
          *
-         * \deprecated pass codec configuration with using the \todo codec-specific configuration
-         * info together with the access unit.
+         * \deprecated pass codec configuration with using the C2InitData info parameter together
+         *             with the access unit.
          */
         FLAG_CODEC_CONFIG  = (1u << 31),
     };
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 58a568e..abd8b2d 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -36,13 +36,13 @@
 using CsdFlushTestParameters = std::tuple<std::string, std::string, bool>;
 static std::vector<CsdFlushTestParameters> gCsdFlushTestParameters;
 
-struct CompToURL {
+struct CompToFiles {
     std::string mime;
-    std::string mURL;
-    std::string info;
+    std::string inputFile;
+    std::string infoFile;
 };
 
-std::vector<CompToURL> gCompToURL = {
+std::vector<CompToFiles> gCompToFiles = {
         {"mp4a-latm", "bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.info"},
         {"mp4a-latm", "bbb_aac_stereo_128kbps_48000hz.aac",
          "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"},
@@ -110,6 +110,15 @@
         mTimestampUs = 0u;
         mWorkResult = C2_OK;
         mTimestampDevTest = false;
+
+        bool valid = getFileNames(mStreamIndex);
+        if (!valid) {
+            GTEST_SKIP() << "No test file for  mime " << mMime << " index: " << mStreamIndex;
+        }
+        ALOGV("mStreamIndex : %zu", mStreamIndex);
+        ALOGV("mInputFile : %s", mInputFile.c_str());
+        ALOGV("mInfoFile : %s", mInfoFile.c_str());
+
         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
     }
 
@@ -126,7 +135,7 @@
 
     virtual void validateTimestampList(int32_t* bitStreamInfo);
 
-    void GetURLForComponent(char* mURL, char* info, size_t streamIndex = 0);
+    bool getFileNames(size_t streamIndex = 0);
 
     struct outputMetaData {
         uint64_t timestampUs;
@@ -193,6 +202,10 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
+    std::string mInputFile;
+    std::string mInfoFile;
+    size_t mStreamIndex = 0;
+
   protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
@@ -204,6 +217,7 @@
     void getParams() {
         mInstanceName = std::get<0>(GetParam());
         mComponentName = std::get<1>(GetParam());
+        mStreamIndex = 0;
     }
 };
 
@@ -285,18 +299,20 @@
 }
 
 // LookUpTable of clips and metadata for component testing
-void Codec2AudioDecHidlTestBase::GetURLForComponent(char* mURL, char* info, size_t streamIndex) {
+bool Codec2AudioDecHidlTestBase::getFileNames(size_t streamIndex) {
     int streamCount = 0;
-    for (size_t i = 0; i < gCompToURL.size(); ++i) {
-        if (mMime.find(gCompToURL[i].mime) != std::string::npos) {
+
+    for (size_t i = 0; i < gCompToFiles.size(); ++i) {
+        if (mMime.find(gCompToFiles[i].mime) != std::string::npos) {
             if (streamCount == streamIndex) {
-                strcat(mURL, gCompToURL[i].mURL.c_str());
-                strcat(info, gCompToURL[i].info.c_str());
-                return;
+                mInputFile = sResourceDir + gCompToFiles[i].inputFile;
+                mInfoFile = sResourceDir + gCompToFiles[i].infoFile;
+                return true;
             }
             streamCount++;
         }
     }
+    return false;
 }
 
 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
@@ -429,6 +445,7 @@
     void getParams() {
         mInstanceName = std::get<0>(GetParam());
         mComponentName = std::get<1>(GetParam());
+        mStreamIndex = std::get<2>(GetParam());
     }
 };
 
@@ -436,22 +453,12 @@
     description("Decodes input file");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    uint32_t streamIndex = std::get<2>(GetParam());
     bool signalEOS = std::get<3>(GetParam());
     mTimestampDevTest = true;
-    char mURL[512], info[512];
     android::Vector<FrameInfo> Info;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info, streamIndex);
-    if (!strcmp(mURL, sResourceDir.c_str())) {
-        ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL  %s ", sResourceDir.c_str(), mURL);
-        return;
-    }
-
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
-    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
+    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
 
     // Reset total no of frames received
     mFramesReceived = 0;
@@ -468,9 +475,8 @@
         return;
     }
     ASSERT_EQ(mComponent->start(), C2_OK);
-    ALOGV("mURL : %s", mURL);
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
@@ -507,15 +513,10 @@
     description("Test Request for thumbnail");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512], info[512];
     android::Vector<FrameInfo> Info;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
-    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
+    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
 
     int32_t bitStreamInfo[2] = {0};
     if (mMime.find("raw") != std::string::npos) {
@@ -529,7 +530,6 @@
         return;
     }
     ASSERT_EQ(mComponent->start(), C2_OK);
-    ALOGV("mURL : %s", mURL);
 
     // request EOS for thumbnail
     // signal EOS flag with last frame
@@ -542,7 +542,7 @@
 
     } while (!(flags & SYNC_FRAME));
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
@@ -599,15 +599,10 @@
 TEST_P(Codec2AudioDecHidlTest, FlushTest) {
     description("Tests Flush calls");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
-    char mURL[512], info[512];
     android::Vector<FrameInfo> Info;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
-    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
+    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
 
     int32_t bitStreamInfo[2] = {0};
     if (mMime.find("raw") != std::string::npos) {
@@ -629,9 +624,8 @@
             verifyFlushOutput(flushedWork, mWorkQueue, mFlushedIndices, mQueueLock));
     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
 
-    ALOGV("mURL : %s", mURL);
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     // Decode 30 frames and flush.
     uint32_t numFramesFlushed = FLUSH_INTERVAL;
@@ -684,15 +678,10 @@
     description("Decode with multiple empty input frames");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-
-    eleInfo.open(info);
-    ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
+    eleInfo.open(mInfoFile);
+    ASSERT_EQ(eleInfo.is_open(), true) << mInputFile << " - file not found";
     android::Vector<FrameInfo> Info;
     int bytesCount = 0;
     uint32_t frameId = 0;
@@ -730,8 +719,7 @@
         return;
     }
     ASSERT_EQ(mComponent->start(), C2_OK);
-    ALOGV("mURL : %s", mURL);
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
@@ -759,6 +747,7 @@
     void getParams() {
         mInstanceName = std::get<0>(GetParam());
         mComponentName = std::get<1>(GetParam());
+        mStreamIndex = 0;
     }
 };
 
@@ -768,19 +757,9 @@
     description("Tests codecs for flush at different states");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512], info[512];
     android::Vector<FrameInfo> Info;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-    if (!strcmp(mURL, sResourceDir.c_str())) {
-        ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL  %s ", sResourceDir.c_str(), mURL);
-        return;
-    }
-    ALOGV("mURL : %s", mURL);
-
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
     ASSERT_GE(numCsds, 0) << "Error in parsing input info file";
 
     int32_t bitStreamInfo[2] = {0};
@@ -797,7 +776,7 @@
 
     ASSERT_EQ(mComponent->start(), C2_OK);
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
 
     bool signalEOS = false;
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index 92b53a0..d77b943 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -84,6 +84,17 @@
         mWorkResult = C2_OK;
         mOutputSize = 0u;
         getInputMaxBufSize();
+
+        c2_status_t status = getChannelCount(&mNumChannels);
+        ASSERT_EQ(status, C2_OK) << "Unable to get supported channel count";
+
+        status = getSampleRate(&mSampleRate);
+        ASSERT_EQ(status, C2_OK) << "Unable to get supported sample rate";
+
+        status = getSamplesPerFrame(mNumChannels, &mSamplesPerFrame);
+        ASSERT_EQ(status, C2_OK) << "Unable to get supported number of samples per frame";
+
+        getFile(mNumChannels, mSampleRate);
     }
 
     virtual void TearDown() override {
@@ -97,7 +108,11 @@
     // Get the test parameters from GetParam call.
     virtual void getParams() {}
 
-    void GetURLForComponent(char* mURL, int32_t channelCount, int32_t sampleRate);
+    c2_status_t getChannelCount(int32_t* nChannels);
+    c2_status_t getSampleRate(int32_t* nSampleRate);
+    c2_status_t getSamplesPerFrame(int32_t nChannels, int32_t* samplesPerFrame);
+
+    void getFile(int32_t channelCount, int32_t sampleRate);
 
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -145,6 +160,12 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
+    int32_t mNumChannels;
+    int32_t mSampleRate;
+    int32_t mSamplesPerFrame;
+
+    std::string mInputFile;
+
   protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
@@ -222,14 +243,13 @@
     return false;
 }
 
-c2_status_t getChannelCount(const std::shared_ptr<android::Codec2Client::Component>& component,
-                            int32_t* nChannels) {
+c2_status_t Codec2AudioEncHidlTestBase::getChannelCount(int32_t* nChannels) {
     std::unique_ptr<C2StreamChannelCountInfo::input> channelCount =
             std::make_unique<C2StreamChannelCountInfo::input>();
     std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
             C2FieldSupportedValuesQuery::Current(
                     C2ParamField(channelCount.get(), &C2StreamChannelCountInfo::value))};
-    c2_status_t c2err = component->querySupportedValues(validValueInfos, C2_DONT_BLOCK);
+    c2_status_t c2err = mComponent->querySupportedValues(validValueInfos, C2_DONT_BLOCK);
     if (c2err != C2_OK || validValueInfos.size() != 1u) {
         ALOGE("querySupportedValues_vb failed for channelCount");
         return c2err;
@@ -264,13 +284,11 @@
     }
     return C2_OK;
 }
-
-c2_status_t getSampleRate(const std::shared_ptr<android::Codec2Client::Component>& component,
-                          int32_t* nSampleRate) {
-    // Use the default sample rate for components
+c2_status_t Codec2AudioEncHidlTestBase::getSampleRate(int32_t* nSampleRate) {
+    // Use the default sample rate for mComponents
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err = component->query({}, {C2StreamSampleRateInfo::input::PARAM_TYPE},
-                                         C2_DONT_BLOCK, &queried);
+    c2_status_t c2err = mComponent->query({}, {C2StreamSampleRateInfo::input::PARAM_TYPE},
+                                          C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK || queried.size() == 0) return c2err;
 
     size_t offset = sizeof(C2Param);
@@ -280,11 +298,11 @@
     return C2_OK;
 }
 
-c2_status_t getSamplesPerFrame(const std::shared_ptr<android::Codec2Client::Component>& component,
-                               int32_t nChannels, int32_t* samplesPerFrame) {
+c2_status_t Codec2AudioEncHidlTestBase::getSamplesPerFrame(int32_t nChannels,
+                                                           int32_t* samplesPerFrame) {
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err = component->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
-                                         C2_DONT_BLOCK, &queried);
+    c2_status_t c2err = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
+                                          C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK || queried.size() == 0) return c2err;
 
     size_t offset = sizeof(C2Param);
@@ -295,24 +313,8 @@
     return C2_OK;
 }
 
-// Get config params for a component
-bool getConfigParams(const std::shared_ptr<android::Codec2Client::Component>& component,
-                     int32_t* nChannels, int32_t* nSampleRate, int32_t* samplesPerFrame) {
-    c2_status_t status = getChannelCount(component, nChannels);
-    if (status != C2_OK) return false;
-
-    status = getSampleRate(component, nSampleRate);
-    if (status != C2_OK) return false;
-
-    status = getSamplesPerFrame(component, *nChannels, samplesPerFrame);
-    if (status != C2_OK) return false;
-
-    return true;
-}
-
 // LookUpTable of clips and metadata for component testing
-void Codec2AudioEncHidlTestBase::GetURLForComponent(char* mURL, int32_t channelCount,
-                                                    int32_t sampleRate) {
+void Codec2AudioEncHidlTestBase::getFile(int32_t channelCount, int32_t sampleRate) {
     std::string rawInput = "bbb_raw_1ch_8khz_s16le.raw";
     if (channelCount == 1 && sampleRate == 16000) {
         rawInput = "bbb_raw_1ch_16khz_s16le.raw";
@@ -320,7 +322,7 @@
         rawInput = "bbb_raw_2ch_48khz_s16le.raw";
     }
 
-    strcat(mURL, rawInput.c_str());
+    mInputFile = sResourceDir + rawInput;
 }
 
 void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
@@ -440,38 +442,23 @@
     bool signalEOS = std::get<2>(GetParam());
     // Ratio w.r.t to mInputMaxBufSize
     int32_t inputMaxBufRatio = std::get<3>(GetParam());
+    mSamplesPerFrame = ((mInputMaxBufSize / inputMaxBufRatio) / (mNumChannels * 2));
 
-    int32_t nChannels;
-    int32_t nSampleRate;
-    int32_t samplesPerFrame;
+    ALOGV("signalEOS %d mInputMaxBufSize %d mSamplesPerFrame %d", signalEOS, mInputMaxBufSize,
+          mSamplesPerFrame);
 
-    if (!getConfigParams(mComponent, &nChannels, &nSampleRate, &samplesPerFrame)) {
-        std::cout << "Failed to get the config params for " << mComponentName << "\n";
-        std::cout << "[   WARN   ] Test Skipped \n";
-        return;
-    }
-
-    samplesPerFrame = ((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2));
-    ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS, mInputMaxBufSize,
-          samplesPerFrame);
-
-    if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
-        std::cout << "[   WARN   ] Test Skipped \n";
-        return;
-    }
-    char mURL[512];
-    strcpy(mURL, sResourceDir.c_str());
-    GetURLForComponent(mURL, nChannels, nSampleRate);
+    ASSERT_TRUE(setupConfigParam(mComponent, mNumChannels, mSampleRate))
+            << "Unable to configure for channels: " << mNumChannels << " and sampling rate "
+            << mSampleRate;
 
     ASSERT_EQ(mComponent->start(), C2_OK);
     std::ifstream eleStream;
     uint32_t numFrames = 16;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
-    ALOGV("mURL : %s", mURL);
     ASSERT_NO_FATAL_FAILURE(encodeNFrames(
             mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool,
-            eleStream, numFrames, samplesPerFrame, nChannels, nSampleRate, false, signalEOS));
+            eleStream, numFrames, mSamplesPerFrame, mNumChannels, mSampleRate, false, signalEOS));
 
     // If EOS is not sent, sending empty input with EOS flag
     if (!signalEOS) {
@@ -545,30 +532,17 @@
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     mFlushedIndices.clear();
-    int32_t nChannels;
-    int32_t nSampleRate;
-    int32_t samplesPerFrame;
 
-    if (!getConfigParams(mComponent, &nChannels, &nSampleRate, &samplesPerFrame)) {
-        std::cout << "Failed to get the config params for " << mComponentName << "\n";
-        std::cout << "[   WARN   ] Test Skipped \n";
-        return;
-    }
-
-    if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
-        std::cout << "[   WARN   ] Test Skipped \n";
-        return;
-    }
-    char mURL[512];
-    strcpy(mURL, sResourceDir.c_str());
-    GetURLForComponent(mURL, nChannels, nSampleRate);
+    ASSERT_TRUE(setupConfigParam(mComponent, mNumChannels, mSampleRate))
+            << "Unable to configure for channels: " << mNumChannels << " and sampling rate "
+            << mSampleRate;
 
     ASSERT_EQ(mComponent->start(), C2_OK);
 
     std::ifstream eleStream;
     uint32_t numFramesFlushed = 30;
     uint32_t numFrames = 128;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     // flush
     std::list<std::unique_ptr<C2Work>> flushedWork;
@@ -577,10 +551,9 @@
     ASSERT_NO_FATAL_FAILURE(
             verifyFlushOutput(flushedWork, mWorkQueue, mFlushedIndices, mQueueLock));
     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
-    ALOGV("mURL : %s", mURL);
     ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                           mFlushedIndices, mLinearPool, eleStream, numFramesFlushed,
-                                          samplesPerFrame, nChannels, nSampleRate));
+                                          mSamplesPerFrame, mNumChannels, mSampleRate));
     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
     waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
@@ -590,8 +563,8 @@
     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
     ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                           mFlushedIndices, mLinearPool, eleStream,
-                                          numFrames - numFramesFlushed, samplesPerFrame, nChannels,
-                                          nSampleRate, true));
+                                          numFrames - numFramesFlushed, mSamplesPerFrame,
+                                          mNumChannels, mSampleRate, true));
     eleStream.close();
     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
@@ -609,33 +582,20 @@
     description("Encodes input file for different channel count");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    int32_t nSampleRate;
-    int32_t samplesPerFrame;
-    int32_t nChannels;
     int32_t numFrames = 16;
     int32_t maxChannelCount = 8;
 
-    if (!getConfigParams(mComponent, &nChannels, &nSampleRate, &samplesPerFrame)) {
-        std::cout << "Failed to get the config params for " << mComponentName << "\n";
-        std::cout << "[   WARN   ] Test Skipped \n";
-        return;
-    }
-    char mURL[512];
-    strcpy(mURL, sResourceDir.c_str());
-    GetURLForComponent(mURL, nChannels, nSampleRate);
-
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
-    ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
-    ALOGV("mURL : %s", mURL);
+    eleStream.open(mInputFile, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true) << mInputFile << " file not found";
 
     uint64_t prevOutputSize = 0u;
     uint32_t prevChannelCount = 0u;
 
     // Looping through the maximum number of channel count supported by encoder
-    for (nChannels = 1; nChannels < maxChannelCount; nChannels++) {
+    for (int32_t nChannels = 1; nChannels < maxChannelCount; nChannels++) {
         ALOGV("Configuring encoder %s  for channel count = %d", mComponentName.c_str(), nChannels);
-        if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
+        if (!setupConfigParam(mComponent, nChannels, mSampleRate)) {
             std::cout << "[   WARN   ] Test Skipped \n";
             return;
         }
@@ -656,9 +616,9 @@
 
         // To check if the input stream is sufficient to encode for the higher channel count
         struct stat buf;
-        stat(mURL, &buf);
+        stat(mInputFile.c_str(), &buf);
         size_t fileSize = buf.st_size;
-        int32_t bytesCount = (samplesPerFrame * nChannels * 2) * numFrames;
+        int32_t bytesCount = (mSamplesPerFrame * nChannels * 2) * numFrames;
         if (fileSize < bytesCount) {
             std::cout << "[   WARN   ] Test Skipped for ChannelCount " << nChannels
                       << " because of insufficient input data\n";
@@ -669,7 +629,7 @@
 
         ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                               mFlushedIndices, mLinearPool, eleStream, numFrames,
-                                              samplesPerFrame, nChannels, nSampleRate));
+                                              mSamplesPerFrame, nChannels, mSampleRate));
 
         // mDisableTest will be set if buffer was not fetched properly.
         // This may happen when config params is not proper but config succeeded
@@ -711,24 +671,11 @@
     description("Encodes input file for different SampleRate");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    int32_t nSampleRate;
-    int32_t samplesPerFrame;
-    int32_t nChannels;
     int32_t numFrames = 16;
 
-    if (!getConfigParams(mComponent, &nChannels, &nSampleRate, &samplesPerFrame)) {
-        std::cout << "Failed to get the config params for " << mComponentName << "\n";
-        std::cout << "[   WARN   ] Test Skipped \n";
-        return;
-    }
-    char mURL[512];
-    strcpy(mURL, sResourceDir.c_str());
-    GetURLForComponent(mURL, nChannels, nSampleRate);
-
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
-    ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
-    ALOGV("mURL : %s", mURL);
+    eleStream.open(mInputFile, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true) << mInputFile << " file not found";
 
     int32_t sampleRateValues[] = {1000, 8000, 16000, 24000, 48000, 96000, 192000};
 
@@ -737,7 +684,7 @@
 
     for (int32_t nSampleRate : sampleRateValues) {
         ALOGV("Configuring encoder %s  for SampleRate = %d", mComponentName.c_str(), nSampleRate);
-        if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
+        if (!setupConfigParam(mComponent, mNumChannels, nSampleRate)) {
             std::cout << "[   WARN   ] Test Skipped \n";
             return;
         }
@@ -759,9 +706,9 @@
 
         // To check if the input stream is sufficient to encode for the higher SampleRate
         struct stat buf;
-        stat(mURL, &buf);
+        stat(mInputFile.c_str(), &buf);
         size_t fileSize = buf.st_size;
-        int32_t bytesCount = (samplesPerFrame * nChannels * 2) * numFrames;
+        int32_t bytesCount = (mSamplesPerFrame * mNumChannels * 2) * numFrames;
         if (fileSize < bytesCount) {
             std::cout << "[   WARN   ] Test Skipped for SampleRate " << nSampleRate
                       << " because of insufficient input data\n";
@@ -772,7 +719,7 @@
 
         ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                               mFlushedIndices, mLinearPool, eleStream, numFrames,
-                                              samplesPerFrame, nChannels, nSampleRate));
+                                              mSamplesPerFrame, mNumChannels, nSampleRate));
 
         // mDisableTest will be set if buffer was not fetched properly.
         // This may happen when config params is not proper but config succeeded
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 8d917b3..c331d0b 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -43,13 +43,13 @@
 using CsdFlushTestParameters = std::tuple<std::string, std::string, bool>;
 static std::vector<CsdFlushTestParameters> gCsdFlushTestParameters;
 
-struct CompToURL {
+struct CompToFiles {
     std::string mime;
-    std::string mURL;
-    std::string info;
-    std::string chksum;
+    std::string inputFile;
+    std::string infoFile;
+    std::string chksumFile;
 };
-std::vector<CompToURL> gCompToURL = {
+std::vector<CompToFiles> gCompToFiles = {
         {"avc", "bbb_avc_176x144_300kbps_60fps.h264", "bbb_avc_176x144_300kbps_60fps.info",
          "bbb_avc_176x144_300kbps_60fps_chksum.md5"},
         {"avc", "bbb_avc_640x360_768kbps_30fps.h264", "bbb_avc_640x360_768kbps_30fps.info",
@@ -92,8 +92,8 @@
     // google.codec2 Video test setup
     virtual void SetUp() override {
         getParams();
+
         mDisableTest = false;
-        ALOGV("Codec2VideoDecHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
                 mInstanceName.c_str(),
                 !bool(android::Codec2Client::CreateFromService("default", true)));
@@ -135,6 +135,15 @@
             mDisableTest = true;
         }
 
+        bool valid = getFileNames(mStreamIndex);
+        if (!valid) {
+            GTEST_SKIP() << "No test file for  mime " << mMime << " index: " << mStreamIndex;
+        }
+        ALOGV("mStreamIndex : %zu", mStreamIndex);
+        ALOGV("mInputFile : %s", mInputFile.c_str());
+        ALOGV("mInfoFile : %s", mInfoFile.c_str());
+        ALOGV("mChksumFile : %s", mChksumFile.c_str());
+
         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
     }
 
@@ -149,8 +158,7 @@
     // Get the test parameters from GetParam call.
     virtual void getParams() {}
 
-    void GetURLChksmForComponent(char* mURL, char* info, char* chksum, size_t streamIndex);
-    void GetURLForComponent(char* mURL, char* info, size_t streamIndex = 0);
+    bool getFileNames(size_t streamIndex = 0);
 
     /* Calculate the CKSUM for the data in inbuf */
     void calc_md5_cksum(uint8_t* pu1_inbuf, uint32_t u4_stride, uint32_t u4_width,
@@ -311,6 +319,11 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
+    std::string mInputFile;
+    std::string mInfoFile;
+    std::string mChksumFile;
+    size_t mStreamIndex = 0;
+
   protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
@@ -322,6 +335,7 @@
     void getParams() {
         mInstanceName = std::get<0>(GetParam());
         mComponentName = std::get<1>(GetParam());
+        mStreamIndex = 0;
     }
 };
 
@@ -358,27 +372,24 @@
 
 // number of elementary streams per component
 #define STREAM_COUNT 3
-// LookUpTable of clips, metadata and chksum for component testing
-void Codec2VideoDecHidlTestBase::GetURLChksmForComponent(char* mURL, char* info, char* chksum,
-                                                         size_t streamIndex) {
+// number of elementary streams required for adaptive testing
+#define ADAPTIVE_STREAM_COUNT 2
+// LookUpTable of clips, metadata and mChksumFile for component testing
+bool Codec2VideoDecHidlTestBase::getFileNames(size_t streamIndex) {
     int streamCount = 0;
-    for (size_t i = 0; i < gCompToURL.size(); ++i) {
-        if (mMime.find(gCompToURL[i].mime) != std::string::npos) {
+
+    for (size_t i = 0; i < gCompToFiles.size(); ++i) {
+        if (mMime.find(gCompToFiles[i].mime) != std::string::npos) {
             if (streamCount == streamIndex) {
-                strcat(mURL, gCompToURL[i].mURL.c_str());
-                strcat(info, gCompToURL[i].info.c_str());
-                strcat(chksum, gCompToURL[i].chksum.c_str());
-                return;
+                mInputFile = sResourceDir + gCompToFiles[i].inputFile;
+                mInfoFile = sResourceDir + gCompToFiles[i].infoFile;
+                mChksumFile = sResourceDir + gCompToFiles[i].chksumFile;
+                return true;
             }
             streamCount++;
         }
     }
-}
-
-void Codec2VideoDecHidlTestBase::GetURLForComponent(char* mURL, char* info, size_t streamIndex) {
-    char chksum[512];
-    strcpy(chksum, sResourceDir.c_str());
-    GetURLChksmForComponent(mURL, info, chksum, streamIndex);
+    return false;
 }
 
 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
@@ -529,6 +540,7 @@
     void getParams() {
         mInstanceName = std::get<0>(GetParam());
         mComponentName = std::get<1>(GetParam());
+        mStreamIndex = std::get<2>(GetParam());
     }
 };
 
@@ -537,24 +549,13 @@
     description("Decodes input file");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    uint32_t streamIndex = std::get<2>(GetParam());
     bool signalEOS = std::get<3>(GetParam());
     mTimestampDevTest = true;
 
-    char mURL[512], info[512], chksum[512];
     android::Vector<FrameInfo> Info;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    strcpy(chksum, sResourceDir.c_str());
-
-    GetURLChksmForComponent(mURL, info, chksum, streamIndex);
-    if (!(strcmp(mURL, sResourceDir.c_str())) || !(strcmp(info, sResourceDir.c_str()))) {
-        ALOGV("Skipping Test, Stream not available");
-        return;
-    }
     mMd5Enable = true;
-    if (!strcmp(chksum, sResourceDir.c_str())) mMd5Enable = false;
+    if (!mChksumFile.compare(sResourceDir)) mMd5Enable = false;
 
     uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
     if (!configPixelFormat(format)) {
@@ -565,23 +566,22 @@
     mFlushedIndices.clear();
     mTimestampUslist.clear();
 
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
-    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
+    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
 
     ASSERT_EQ(mComponent->start(), C2_OK);
     // Reset total no of frames received
     mFramesReceived = 0;
     mTimestampUs = 0;
-    ALOGV("mURL : %s", mURL);
+
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
 
     size_t refChksmSize = 0;
     std::ifstream refChksum;
     if (mMd5Enable) {
-        ALOGV("chksum file name: %s", chksum);
-        refChksum.open(chksum, std::ifstream::binary | std::ifstream::ate);
+        refChksum.open(mChksumFile, std::ifstream::binary | std::ifstream::ate);
         ASSERT_EQ(refChksum.is_open(), true);
         refChksmSize = refChksum.tellg();
         refChksum.seekg(0, std::ifstream::beg);
@@ -650,20 +650,17 @@
     uint32_t timestampOffset = 0;
     uint32_t offset = 0;
     android::Vector<FrameInfo> Info;
-    for (uint32_t i = 0; i < STREAM_COUNT * 2; i++) {
-        char mURL[512], info[512];
+    for (uint32_t i = 0; i < ADAPTIVE_STREAM_COUNT * 2; i++) {
         std::ifstream eleStream, eleInfo;
 
-        strcpy(mURL, sResourceDir.c_str());
-        strcpy(info, sResourceDir.c_str());
-        GetURLForComponent(mURL, info, i % STREAM_COUNT);
-        if (!(strcmp(mURL, sResourceDir.c_str())) || !(strcmp(info, sResourceDir.c_str()))) {
+        bool valid = getFileNames(i % ADAPTIVE_STREAM_COUNT);
+        if (!valid) {
             ALOGV("Stream not available, skipping this index");
             continue;
         }
 
-        eleInfo.open(info);
-        ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
+        eleInfo.open(mInfoFile);
+        ASSERT_EQ(eleInfo.is_open(), true) << mInputFile << " - file not found";
         int bytesCount = 0;
         uint32_t flags = 0;
         uint32_t timestamp = 0;
@@ -690,8 +687,7 @@
 
         // Reset Total frames before second decode loop
         // mFramesReceived = 0;
-        ALOGV("mURL : %s", mURL);
-        eleStream.open(mURL, std::ifstream::binary);
+        eleStream.open(mInputFile, std::ifstream::binary);
         ASSERT_EQ(eleStream.is_open(), true);
         ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                               mFlushedIndices, mLinearPool, eleStream, &Info,
@@ -747,15 +743,9 @@
     description("Test Request for thumbnail");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512], info[512];
     android::Vector<FrameInfo> Info;
-
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
-    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
+    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
 
     uint32_t flags = 0;
     for (size_t i = 0; i < MAX_ITERATIONS; i++) {
@@ -772,7 +762,7 @@
         } while (!(flags & SYNC_FRAME));
 
         std::ifstream eleStream;
-        eleStream.open(mURL, std::ifstream::binary);
+        eleStream.open(mInputFile, std::ifstream::binary);
         ASSERT_EQ(eleStream.is_open(), true);
         ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                               mFlushedIndices, mLinearPool, eleStream, &Info, 0,
@@ -834,19 +824,12 @@
 
     ASSERT_EQ(mComponent->start(), C2_OK);
 
-    char mURL[512], info[512];
     android::Vector<FrameInfo> Info;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-
     mFlushedIndices.clear();
 
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
-    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
-
-    ALOGV("mURL : %s", mURL);
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
+    ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
 
     // flush
     std::list<std::unique_ptr<C2Work>> flushedWork;
@@ -857,7 +840,7 @@
     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
 
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     // Decode 30 frames and flush. here 30 is chosen to ensure there is a key
     // frame after this so that the below section can be covered for all
@@ -910,15 +893,10 @@
     description("Decode with multiple empty input frames");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-
-    eleInfo.open(info);
-    ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
+    eleInfo.open(mInfoFile);
+    ASSERT_EQ(eleInfo.is_open(), true) << mInputFile << " - file not found";
     android::Vector<FrameInfo> Info;
     int bytesCount = 0;
     uint32_t frameId = 0;
@@ -946,8 +924,7 @@
     eleInfo.close();
 
     ASSERT_EQ(mComponent->start(), C2_OK);
-    ALOGV("mURL : %s", mURL);
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
@@ -973,6 +950,7 @@
     void getParams() {
         mInstanceName = std::get<0>(GetParam());
         mComponentName = std::get<1>(GetParam());
+        mStreamIndex = 0;
     }
 };
 
@@ -982,22 +960,15 @@
     description("Tests codecs for flush at different states");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512], info[512];
-
     android::Vector<FrameInfo> Info;
 
-    strcpy(mURL, sResourceDir.c_str());
-    strcpy(info, sResourceDir.c_str());
-    GetURLForComponent(mURL, info);
-
-    int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
+    int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
     ASSERT_GE(numCsds, 0) << "Error in parsing input info file";
 
     ASSERT_EQ(mComponent->start(), C2_OK);
 
-    ALOGV("mURL : %s", mURL);
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     bool flushedDecoder = false;
     bool signalEOS = false;
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index c557de1..6a00edd 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -95,9 +95,10 @@
         mMinWidth = INT32_MAX;
         mMinHeight = INT32_MAX;
 
-        ASSERT_EQ(getMaxMinResolutionSupported(mComponent), C2_OK);
+        ASSERT_EQ(getMaxMinResolutionSupported(), C2_OK);
         mWidth = std::max(std::min(mWidth, mMaxWidth), mMinWidth);
         mHeight = std::max(std::min(mHeight, mMaxHeight), mMinHeight);
+        ALOGV("mWidth %d mHeight %d", mWidth, mHeight);
 
         C2SecureModeTuning secureModeTuning{};
         mComponent->query({&secureModeTuning}, {}, C2_MAY_BLOCK, nullptr);
@@ -106,6 +107,7 @@
             mDisableTest = true;
         }
 
+        getFile();
         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
     }
 
@@ -119,10 +121,9 @@
 
     // Get the test parameters from GetParam call.
     virtual void getParams() {}
-
+    void getFile();
     bool setupConfigParam(int32_t nWidth, int32_t nHeight, int32_t nBFrame = 0);
-    c2_status_t getMaxMinResolutionSupported(
-            const std::shared_ptr<android::Codec2Client::Component>& component);
+    c2_status_t getMaxMinResolutionSupported();
 
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -215,6 +216,8 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
+    std::string mInputFile;
+
   protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
@@ -284,9 +287,8 @@
     return true;
 }
 
-// LookUpTable of clips for component testing
-void GetURLForComponent(char* URL) {
-    strcat(URL, "bbb_352x288_420p_30fps_32frames.yuv");
+void Codec2VideoEncHidlTestBase::getFile() {
+    mInputFile = sResourceDir + "bbb_352x288_420p_30fps_32frames.yuv";
 }
 
 void fillByteBuffer(char* inputBuffer, char* mInputData, uint32_t nWidth, int32_t nHeight) {
@@ -439,8 +441,7 @@
     }
 };
 
-c2_status_t Codec2VideoEncHidlTestBase::getMaxMinResolutionSupported(
-        const std::shared_ptr<android::Codec2Client::Component>& component) {
+c2_status_t Codec2VideoEncHidlTestBase::getMaxMinResolutionSupported() {
     std::unique_ptr<C2StreamPictureSizeInfo::input> param =
             std::make_unique<C2StreamPictureSizeInfo::input>();
     std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
@@ -448,7 +449,7 @@
                     C2ParamField(param.get(), &C2StreamPictureSizeInfo::width)),
             C2FieldSupportedValuesQuery::Current(
                     C2ParamField(param.get(), &C2StreamPictureSizeInfo::height))};
-    c2_status_t c2err = component->querySupportedValues(validValueInfos, C2_MAY_BLOCK);
+    c2_status_t c2err = mComponent->querySupportedValues(validValueInfos, C2_MAY_BLOCK);
     if (c2err != C2_OK || validValueInfos.size() != 2u) {
         ALOGE("querySupportedValues_vb failed for pictureSize");
         return c2err;
@@ -491,19 +492,14 @@
     description("Encodes input file");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512];
     bool signalEOS = std::get<3>(GetParam());
     // Send an empty frame to receive CSD data from encoder.
     bool sendEmptyFirstFrame = std::get<3>(GetParam());
     mConfigBPictures = std::get<4>(GetParam());
 
-    strcpy(mURL, sResourceDir.c_str());
-    GetURLForComponent(mURL);
-
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
-    ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
-    ALOGV("mURL : %s", mURL);
+    eleStream.open(mInputFile, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true) << mInputFile << " file not found";
 
     mTimestampUs = 0;
     mTimestampDevTest = true;
@@ -640,11 +636,6 @@
     description("Test Request for flush");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512];
-
-    strcpy(mURL, sResourceDir.c_str());
-    GetURLForComponent(mURL);
-
     if (!setupConfigParam(mWidth, mHeight)) {
         ASSERT_TRUE(false) << "Failed while configuring height and width for " << mComponentName;
     }
@@ -655,9 +646,9 @@
     std::ifstream eleStream;
     uint32_t numFramesFlushed = 10;
     uint32_t numFrames = ENC_NUM_FRAMES;
-    eleStream.open(mURL, std::ifstream::binary);
+    eleStream.open(mInputFile, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
-    ALOGV("mURL : %s", mURL);
+
     // flush
     std::list<std::unique_ptr<C2Work>> flushedWork;
     c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
@@ -820,15 +811,9 @@
     description("Encodes input file for different bitrates");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    char mURL[512];
-
-    strcpy(mURL, sResourceDir.c_str());
-    GetURLForComponent(mURL);
-
     std::ifstream eleStream;
-    eleStream.open(mURL, std::ifstream::binary);
-    ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
-    ALOGV("mURL : %s", mURL);
+    eleStream.open(mInputFile, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true) << mInputFile << " file not found";
 
     mFlushedIndices.clear();
 
diff --git a/media/codec2/hidl/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hidl/plugin/samples/SampleFilterPlugin.cpp
index 7de3503..b942be7 100644
--- a/media/codec2/hidl/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hidl/plugin/samples/SampleFilterPlugin.cpp
@@ -626,6 +626,14 @@
             }
             LOG(VERBOSE) << "work #" << workCount << ": flags=" << work->input.flags
                     << " timestamp=" << work->input.ordinal.timestamp.peek();;
+
+            std::vector<C2Param *> configUpdate;
+            for (const std::unique_ptr<C2Param> &param : work->input.configUpdate) {
+                configUpdate.push_back(param.get());
+            }
+            std::vector<std::unique_ptr<C2SettingResult>> failures;
+            mIntf->config_vb(configUpdate, C2_MAY_BLOCK, &failures);
+
             std::shared_ptr<C2StreamHdrStaticInfo::input> hdrStaticInfo =
                 mIntf->getHdrStaticMetadata();
             uint32_t dataspace = mIntf->getDataSpace();
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 051e9cf..16398a4 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -673,6 +673,10 @@
         mCodec->mCallback->onOutputBuffersChanged();
     }
 
+    void onFirstTunnelFrameReady() override {
+        mCodec->mCallback->onFirstTunnelFrameReady();
+    }
+
 private:
     CCodec *mCodec;
 };
@@ -2688,7 +2692,11 @@
             *maxUsage = 0;
             continue;
         }
-        *minUsage |= supported.values[0].u64;
+        if (supported.values.size() > 1) {
+            *minUsage |= supported.values[1].u64;
+        } else {
+            *minUsage |= supported.values[0].u64;
+        }
         int64_t currentMaxUsage = 0;
         for (const C2Value::Primitive &flags : supported.values) {
             currentMaxUsage |= flags.u64;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 3c3b41d..f88408e 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -209,6 +209,7 @@
     int32_t flags = 0;
     int32_t tmp = 0;
     bool eos = false;
+    bool tunnelFirstFrame = false;
     if (buffer->meta()->findInt32("eos", &tmp) && tmp) {
         eos = true;
         mInputMetEos = true;
@@ -217,6 +218,9 @@
     if (buffer->meta()->findInt32("csd", &tmp) && tmp) {
         flags |= C2FrameData::FLAG_CODEC_CONFIG;
     }
+    if (buffer->meta()->findInt32("tunnel-first-frame", &tmp) && tmp) {
+        tunnelFirstFrame = true;
+    }
     ALOGV("[%s] queueInputBuffer: buffer->size() = %zu", mName, buffer->size());
     std::list<std::unique_ptr<C2Work>> items;
     std::unique_ptr<C2Work> work(new C2Work);
@@ -288,6 +292,13 @@
         // TODO: fill info's
 
         work->input.configUpdate = std::move(mParamsToBeSet);
+        if (tunnelFirstFrame) {
+            C2StreamTunnelHoldRender::input tunnelHoldRender{
+                0u /* stream */,
+                C2_TRUE /* value */
+            };
+            work->input.configUpdate.push_back(C2Param::Copy(tunnelHoldRender));
+        }
         work->worklets.clear();
         work->worklets.emplace_back(new C2Worklet);
 
@@ -1724,6 +1735,15 @@
                 }
                 break;
             }
+            case C2StreamTunnelHoldRender::CORE_INDEX: {
+                C2StreamTunnelHoldRender::output firstTunnelFrameHoldRender;
+                if (!(worklet->output.flags & C2FrameData::FLAG_INCOMPLETE)) break;
+                if (!firstTunnelFrameHoldRender.updateFrom(*param)) break;
+                if (firstTunnelFrameHoldRender.value != C2_TRUE) break;
+                ALOGV("[%s] onWorkDone: first tunnel frame ready", mName);
+                mCCodecCallback->onFirstTunnelFrameReady();
+                break;
+            }
             default:
                 ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
                       mName, param->index());
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 45da003..5a2aca2 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -45,6 +45,7 @@
     virtual void onError(status_t err, enum ActionCode actionCode) = 0;
     virtual void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) = 0;
     virtual void onOutputBuffersChanged() = 0;
+    virtual void onFirstTunnelFrameReady() = 0;
 };
 
 /**
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 27e87e6..c275187 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -909,6 +909,8 @@
             }
         }));
 
+    add(ConfigMapper("android._encoding-quality-level", C2_PARAMKEY_ENCODING_QUALITY_LEVEL, "value")
+        .limitTo(D::ENCODER & (D::CONFIG | D::PARAM)));
     add(ConfigMapper(KEY_QUALITY, C2_PARAMKEY_QUALITY, "value")
         .limitTo(D::ENCODER & (D::CONFIG | D::PARAM)));
     add(ConfigMapper(KEY_FLAC_COMPRESSION_LEVEL, C2_PARAMKEY_COMPLEXITY, "value")
@@ -938,6 +940,14 @@
             return value == 0 ? C2_FALSE : C2_TRUE;
         }));
 
+    add(ConfigMapper("android._trigger-tunnel-peek", C2_PARAMKEY_TUNNEL_START_RENDER, "value")
+        .limitTo(D::PARAM & D::VIDEO & D::DECODER)
+        .withMapper([](C2Value v) -> C2Value {
+            int32_t value = 0;
+            (void)v.get(&value);
+            return value == 0 ? C2_FALSE : C2_TRUE;
+        }));
+
     /* still to do
     constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
 
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 34e6a88..691bab1 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -679,17 +679,20 @@
 std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
 #ifdef __LP64__
     static std::once_flag s_checkOnce;
-    static bool s_64bitonly {false};
+    static bool s_is64bitOk {true};
     std::call_once(s_checkOnce, [&](){
         const std::string abi32list =
         ::android::base::GetProperty("ro.product.cpu.abilist32", "");
-        if (abi32list.empty()) {
-            s_64bitonly = true;
+        if (!abi32list.empty()) {
+            int32_t inputSurfaceSetting =
+            ::android::base::GetIntProperty("debug.stagefright.c2inputsurface", int32_t(0));
+            s_is64bitOk = inputSurfaceSetting != 0;
         }
     });
 
-    if (!s_64bitonly) {
-        ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object");
+    if (!s_is64bitOk) {
+        ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object"\
+              "when debug.stagefright.c2inputsurface is set to 0");
         return nullptr;
     }
 #endif
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 0966988..5f87c66 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -507,9 +507,21 @@
     };
 }
 
+// Matrix coefficient to convert RGB to Planar YUV data.
+// Each sub-array represents the 3X3 coeff used with R, G and B
+static const int16_t bt601Matrix[2][3][3] = {
+    { { 76, 150, 29 }, { -43, -85, 128 }, { 128, -107, -21 } }, /* RANGE_FULL */
+    { { 66, 129, 25 }, { -38, -74, 112 }, { 112, -94, -18 } },  /* RANGE_LIMITED */
+};
+
+static const int16_t bt709Matrix[2][3][3] = {
+    { { 54, 183, 18 }, { -29, -99, 128 }, { 128, -116, -12 } }, /* RANGE_FULL */
+    { { 47, 157, 16 }, { -26, -86, 112 }, { 112, -102, -10 } }, /* RANGE_LIMITED */
+};
+
 status_t ConvertRGBToPlanarYUV(
         uint8_t *dstY, size_t dstStride, size_t dstVStride, size_t bufferSize,
-        const C2GraphicView &src) {
+        const C2GraphicView &src, C2Color::matrix_t colorMatrix, C2Color::range_t colorRange) {
     CHECK(dstY != nullptr);
     CHECK((src.width() & 1) == 0);
     CHECK((src.height() & 1) == 0);
@@ -527,28 +539,38 @@
     const uint8_t *pGreen = src.data()[C2PlanarLayout::PLANE_G];
     const uint8_t *pBlue  = src.data()[C2PlanarLayout::PLANE_B];
 
-#define CLIP3(x,y,z) (((z) < (x)) ? (x) : (((z) > (y)) ? (y) : (z)))
+    // set default range as limited
+    if (colorRange != C2Color::RANGE_FULL && colorRange != C2Color::RANGE_LIMITED) {
+        colorRange = C2Color::RANGE_LIMITED;
+    }
+    const int16_t (*weights)[3] =
+        (colorMatrix == C2Color::MATRIX_BT709) ?
+            bt709Matrix[colorRange - 1] : bt601Matrix[colorRange - 1];
+    uint8_t zeroLvl =  colorRange == C2Color::RANGE_FULL ? 0 : 16;
+    uint8_t maxLvlLuma =  colorRange == C2Color::RANGE_FULL ? 255 : 235;
+    uint8_t maxLvlChroma =  colorRange == C2Color::RANGE_FULL ? 255 : 240;
+
+#define CLIP3(min,v,max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max)))
     for (size_t y = 0; y < src.height(); ++y) {
         for (size_t x = 0; x < src.width(); ++x) {
-            uint8_t red = *pRed;
-            uint8_t green = *pGreen;
-            uint8_t blue = *pBlue;
+            uint8_t r = *pRed;
+            uint8_t g = *pGreen;
+            uint8_t b = *pBlue;
 
-            // using ITU-R BT.601 conversion matrix
-            unsigned luma =
-                CLIP3(0, (((red * 66 + green * 129 + blue * 25) >> 8) + 16), 255);
+            unsigned luma = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2]) >> 8) +
+                             zeroLvl;
 
-            dstY[x] = luma;
+            dstY[x] = CLIP3(zeroLvl, luma, maxLvlLuma);
 
             if ((x & 1) == 0 && (y & 1) == 0) {
-                unsigned U =
-                    CLIP3(0, (((-red * 38 - green * 74 + blue * 112) >> 8) + 128), 255);
+                unsigned U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2]) >> 8) +
+                              128;
 
-                unsigned V =
-                    CLIP3(0, (((red * 112 - green * 94 - blue * 18) >> 8) + 128), 255);
+                unsigned V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2]) >> 8) +
+                              128;
 
-                dstU[x >> 1] = U;
-                dstV[x >> 1] = V;
+                dstU[x >> 1] = CLIP3(zeroLvl, U, maxLvlChroma);
+                dstV[x >> 1] = CLIP3(zeroLvl, V, maxLvlChroma);
             }
             pRed   += layout.planes[C2PlanarLayout::PLANE_R].colInc;
             pGreen += layout.planes[C2PlanarLayout::PLANE_G].colInc;
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index af29e81..9fa642d 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -18,6 +18,7 @@
 #define CODEC2_BUFFER_UTILS_H_
 
 #include <C2Buffer.h>
+#include <C2Config.h>
 #include <C2ParamDef.h>
 
 #include <media/hardware/VideoAPI.h>
@@ -39,7 +40,8 @@
  */
 status_t ConvertRGBToPlanarYUV(
         uint8_t *dstY, size_t dstStride, size_t dstVStride, size_t bufferSize,
-        const C2GraphicView &src);
+        const C2GraphicView &src, C2Color::matrix_t colorMatrix = C2Color::MATRIX_BT601,
+        C2Color::range_t colorRange = C2Color::RANGE_LIMITED);
 
 /**
  * Returns a planar YUV 420 8-bit media image descriptor.
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 00bf84f..4d939fa 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -92,6 +92,7 @@
 
 ALookup<C2Config::bitrate_mode_t, int32_t> sBitrateModes = {
     { C2Config::BITRATE_CONST,      BITRATE_MODE_CBR },
+    { C2Config::BITRATE_CONST_SKIP_ALLOWED, BITRATE_MODE_CBR_FD },
     { C2Config::BITRATE_VARIABLE,   BITRATE_MODE_VBR },
     { C2Config::BITRATE_IGNORE,     BITRATE_MODE_CQ },
 };
diff --git a/media/codec2/vndk/C2AllocatorBlob.cpp b/media/codec2/vndk/C2AllocatorBlob.cpp
index 6340cba..8cfa1d7 100644
--- a/media/codec2/vndk/C2AllocatorBlob.cpp
+++ b/media/codec2/vndk/C2AllocatorBlob.cpp
@@ -178,6 +178,8 @@
         return C2_CORRUPTED;
     }
 
+    // Note: the BLOB allocator does not support padding as this functionality is expected
+    // to be provided by the gralloc implementation.
     std::shared_ptr<C2GraphicAllocation> graphicAllocation;
     c2_status_t status = mC2AllocatorGralloc->newGraphicAllocation(
             capacity, kLinearBufferHeight, kLinearBufferFormat, usage, &graphicAllocation);
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index a8528df..77b265a 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -417,15 +417,16 @@
                 buffer = -1;
             }
         }
-        return new Impl(ionFd, allocSize, bufferFd, buffer, id, ret);
-
+        // the padding is not usable so deduct it from the advertised capacity
+        return new Impl(ionFd, allocSize - sPadding, bufferFd, buffer, id, ret);
     } else {
         ret = ion_alloc_fd(ionFd, allocSize, align, heapMask, flags, &bufferFd);
         ALOGV("ion_alloc_fd(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
               "returned (%d) ; bufferFd = %d",
               ionFd, allocSize, align, heapMask, flags, ret, bufferFd);
 
-        return new ImplV2(ionFd, allocSize, bufferFd, id, ret);
+        // the padding is not usable so deduct it from the advertised capacity
+        return new ImplV2(ionFd, allocSize - sPadding, bufferFd, id, ret);
     }
 }
 
diff --git a/media/codec2/vndk/C2DmaBufAllocator.cpp b/media/codec2/vndk/C2DmaBufAllocator.cpp
index 6d8552a..1aa3d69 100644
--- a/media/codec2/vndk/C2DmaBufAllocator.cpp
+++ b/media/codec2/vndk/C2DmaBufAllocator.cpp
@@ -111,8 +111,27 @@
     virtual bool equals(const std::shared_ptr<C2LinearAllocation>& other) const override;
 
     // internal methods
-    C2DmaBufAllocation(BufferAllocator& alloc, size_t size, C2String heap_name, unsigned flags,
-                       C2Allocator::id_t id);
+
+    /**
+      * Constructs an allocation via a new allocation.
+      *
+      * @param alloc     allocator
+      * @param allocSize size used for the allocator
+      * @param capacity  capacity advertised to the client
+      * @param heap_name name of the dmabuf heap (device)
+      * @param flags     flags
+      * @param id        allocator id
+      */
+    C2DmaBufAllocation(BufferAllocator& alloc, size_t allocSize, size_t capacity,
+                       C2String heap_name, unsigned flags, C2Allocator::id_t id);
+
+    /**
+      * Constructs an allocation by wrapping an existing allocation.
+      *
+      * @param size    capacity advertised to the client
+      * @param shareFd dmabuf fd of the wrapped allocation
+      * @param id      allocator id
+      */
     C2DmaBufAllocation(size_t size, int shareFd, C2Allocator::id_t id);
 
     c2_status_t status() const;
@@ -246,19 +265,19 @@
     }
 }
 
-C2DmaBufAllocation::C2DmaBufAllocation(BufferAllocator& alloc, size_t size, C2String heap_name,
-                                       unsigned flags, C2Allocator::id_t id)
-    : C2LinearAllocation(size), mHandle(-1, 0) {
+C2DmaBufAllocation::C2DmaBufAllocation(BufferAllocator& alloc, size_t allocSize, size_t capacity,
+                                       C2String heap_name, unsigned flags, C2Allocator::id_t id)
+    : C2LinearAllocation(capacity), mHandle(-1, 0) {
     int bufferFd = -1;
     int ret = 0;
 
-    bufferFd = alloc.Alloc(heap_name, size, flags);
+    bufferFd = alloc.Alloc(heap_name, allocSize, flags);
     if (bufferFd < 0) {
         ret = bufferFd;
     }
 
     // this may be a non-working handle if bufferFd is negative
-    mHandle = C2HandleBuf(bufferFd, size);
+    mHandle = C2HandleBuf(bufferFd, capacity);
     mId = id;
     mInit = c2_status_t(c2_map_errno<ENOMEM, EACCES, EINVAL>(ret));
 }
@@ -381,7 +400,7 @@
     size_t allocSize = (size_t)capacity + sPadding;
     // TODO: should we align allocation size to mBlockSize to reflect the true allocation size?
     std::shared_ptr<C2DmaBufAllocation> alloc = std::make_shared<C2DmaBufAllocation>(
-            mBufferAllocator, allocSize, heap_name, flags, getId());
+            mBufferAllocator, allocSize, allocSize - sPadding, heap_name, flags, getId());
     ret = alloc->status();
     if (ret == C2_OK) {
         *allocation = alloc;
diff --git a/media/codecs/m4v_h263/dec/test/Android.bp b/media/codecs/m4v_h263/dec/test/Android.bp
index 6eed66f..d8de569 100644
--- a/media/codecs/m4v_h263/dec/test/Android.bp
+++ b/media/codecs/m4v_h263/dec/test/Android.bp
@@ -47,6 +47,10 @@
         },
     },
 
+    // this unit test also runs within the mainline tests (MTS),
+    // so it must be compatible back to Android Q/10 (sdk 29)
+    min_sdk_version: "29",
+
     srcs: [
         "Mpeg4H263DecoderTest.cpp",
     ],
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 4fd3a56..443e26c 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1700,17 +1700,17 @@
         return ERROR_MALFORMED;
     }
 
-    size_t header_start = 0;
-    size_t header_lenth = 0;
+    long header_start = 0;
+    long header_length = 0;
     for (header_start = 0; header_start < frame.len - 4; header_start++) {
         if (ntohl(0x000001b3) == *(uint32_t*)((uint8_t*)tmpData.get() + header_start)) {
             break;
         }
     }
     bool isComplete_csd = false;
-    for (header_lenth = 0; header_lenth < frame.len - 4 - header_start; header_lenth++) {
+    for (header_length = 0; header_length < frame.len - 4 - header_start; header_length++) {
         if (ntohl(0x000001b8) == *(uint32_t*)((uint8_t*)tmpData.get()
-                                + header_start + header_lenth)) {
+                                + header_start + header_length)) {
             isComplete_csd = true;
             break;
         }
@@ -1720,7 +1720,7 @@
         return ERROR_MALFORMED;
     }
     addESDSFromCodecPrivate(trackInfo->mMeta, false,
-                              (uint8_t*)(tmpData.get()) + header_start, header_lenth);
+                            (uint8_t*)(tmpData.get()) + header_start, header_length);
 
     return OK;
 
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 5bbabdf..248a39c 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -504,7 +504,14 @@
             }
 
             mCurrentTimeUs = seekTimeUs;
-            mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000;
+            int64_t seekTimeUsTimesBitrate;
+            if (__builtin_mul_overflow(seekTimeUs, bitrate, &seekTimeUsTimesBitrate)) {
+              return AMEDIA_ERROR_UNSUPPORTED;
+            }
+            if (__builtin_add_overflow(
+                    mFirstFramePos, seekTimeUsTimesBitrate / 8000000, &mCurrentPos)) {
+                return AMEDIA_ERROR_UNSUPPORTED;
+            }
             seekCBR = true;
         } else {
             mCurrentTimeUs = actualSeekTimeUs;
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 3333925..4b08295 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -82,7 +82,9 @@
 
     /**
      * This format uses 24-bit samples packed into 3 bytes.
-     * The bytes are in the native endian order.
+     * The bytes are in little-endian order, so the least significant byte
+     * comes first in the byte array.
+     *
      * The maximum range of the data is -8388608 (0x800000)
      * to 8388607 (0x7FFFFF).
      *
@@ -635,13 +637,14 @@
 AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* builder,
                                                 int32_t deviceId) __INTRODUCED_IN(26);
 
-// TODO b/182392769: reexamine if Identity can be used
 /**
  * Declare the name of the package creating the stream.
  *
  * This is usually {@code Context#getPackageName()}.
  *
  * The default, if you do not call this function, is a random package in the calling uid.
+ * The vast majority of apps have only one package per calling UID. If the package
+ * name does not match the calling UID, then requests will be rejected.
  *
  * Available since API level 31.
  *
@@ -656,7 +659,7 @@
  *
  * This is usually {@code Context#getAttributionTag()}.
  *
- * The default, if you do not call this function, is the default attribution tag.
+ * The default, if you do not call this function, is null.
  *
  * Available since API level 31.
  *
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index fe2d98e..33a5c7f 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -52,6 +52,7 @@
         "libcutils",
         "libutils",
         "libbinder",
+        "libpermission",
     ],
 
     sanitize: {
@@ -86,7 +87,7 @@
     export_header_lib_headers: ["libaaudio_headers"],
 
     export_shared_lib_headers: [
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     shared_libs: [
@@ -99,15 +100,11 @@
         "libcutils",
         "libutils",
         "libbinder",
+        "framework-permission-aidl-cpp",
         "aaudio-aidl-cpp",
-        "media_permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
     ],
 
-    static_libs: [
-        "media_permission-aidl-cpp",
-    ],
-
     cflags: [
         "-Wno-unused-parameter",
         "-Wall",
@@ -177,7 +174,7 @@
     imports: [
         "audio_common-aidl",
         "shared-file-region-aidl",
-        "media_permission-aidl",
+        "framework-permission-aidl"
     ],
     backend:
     {
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 5e0a4bb..8d90034 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -31,7 +31,7 @@
 
 AAudioStreamRequest::AAudioStreamRequest(const StreamRequest& parcelable) :
         mConfiguration(std::move(parcelable.params)),
-        mIdentity(parcelable.identity),
+        mAttributionSource(parcelable.attributionSource),
         mSharingModeMatchRequired(parcelable.sharingModeMatchRequired),
         mInService(parcelable.inService) {
 }
@@ -39,7 +39,7 @@
 StreamRequest AAudioStreamRequest::parcelable() const {
     StreamRequest result;
     result.params = std::move(mConfiguration).parcelable();
-    result.identity = mIdentity;
+    result.attributionSource = mAttributionSource;
     result.sharingModeMatchRequired = mSharingModeMatchRequired;
     result.inService = mInService;
     return result;
@@ -50,7 +50,7 @@
 }
 
 void AAudioStreamRequest::dump() const {
-    ALOGD("mIdentity  = %s", mIdentity.toString().c_str());
+    ALOGD("mAttributionSource  = %s", mAttributionSource.toString().c_str());
     ALOGD("mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
     ALOGD("mInService = %d", mInService);
     mConfiguration.dump();
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 02341c8..cc43a48 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -23,10 +23,12 @@
 #include <aaudio/StreamRequest.h>
 
 #include "binding/AAudioStreamConfiguration.h"
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 namespace aaudio {
 
+using android::content::AttributionSourceState;
+
 class AAudioStreamRequest {
 public:
     AAudioStreamRequest() = default;
@@ -34,12 +36,12 @@
     // Construct based on a parcelable representation.
     explicit AAudioStreamRequest(const StreamRequest& parcelable);
 
-    const android::media::permission::Identity &getIdentity() const {
-        return mIdentity;
+    const AttributionSourceState &getAttributionSource() const {
+        return mAttributionSource;
     }
 
-    void setIdentity(const android::media::permission::Identity &identity) {
-        mIdentity = identity;
+    void setAttributionSource(const AttributionSourceState &attributionSource) {
+        mAttributionSource = attributionSource;
     }
 
     bool isSharingModeMatchRequired() const {
@@ -75,7 +77,7 @@
 
 private:
     AAudioStreamConfiguration  mConfiguration;
-    android::media::permission::Identity mIdentity;
+    AttributionSourceState mAttributionSource;
     bool                       mSharingModeMatchRequired = false;
     bool                       mInService = false; // Stream opened by AAudioservice
 };
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
index 12802e6..53787a0 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
@@ -17,11 +17,11 @@
 package aaudio;
 
 import aaudio.StreamParameters;
-import android.media.permission.Identity;
+import android.content.AttributionSourceState;
 
 parcelable StreamRequest {
-    StreamParameters    params;
-    Identity            identity;
-    boolean             sharingModeMatchRequired; // = false;
-    boolean             inService; // = false; // Stream opened by AAudioservice
+    StreamParameters       params;
+    AttributionSourceState attributionSource;
+    boolean                sharingModeMatchRequired; // = false;
+    boolean                inService; // = false; // Stream opened by AAudioservice
 }
\ No newline at end of file
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 0a19d17..ebc9f2b 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -166,6 +166,10 @@
                                   ? &mDataWriteCounter
                                   : descriptor->writeCounterAddress;
 
+    // Clear buffer to avoid an initial glitch on some devices.
+    size_t bufferSizeBytes = descriptor->capacityInFrames * descriptor->bytesPerFrame;
+    memset(descriptor->dataAddress, 0, bufferSizeBytes);
+
     mDataQueue = std::make_unique<FifoBufferIndirect>(
             descriptor->bytesPerFrame,
             descriptor->capacityInFrames,
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index d8b27c3..cf2abe8 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -51,7 +51,7 @@
 
 using android::Mutex;
 using android::WrappingBuffer;
-using android::media::permission::Identity;
+using android::content::AttributionSourceState;
 
 using namespace aaudio;
 
@@ -108,15 +108,16 @@
     // Request FLOAT for the shared mixer or the device.
     request.getConfiguration().setFormat(AUDIO_FORMAT_PCM_FLOAT);
 
-    // TODO b/182392769: use identity util
-    Identity identity;
-    identity.uid = VALUE_OR_FATAL(android::legacy2aidl_uid_t_int32_t(getuid()));
-    identity.pid = VALUE_OR_FATAL(android::legacy2aidl_pid_t_int32_t(getpid()));
-    identity.packageName = builder.getOpPackageName();
-    identity.attributionTag = builder.getAttributionTag();
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource;
+    attributionSource.uid = VALUE_OR_FATAL(android::legacy2aidl_uid_t_int32_t(getuid()));
+    attributionSource.pid = VALUE_OR_FATAL(android::legacy2aidl_pid_t_int32_t(getpid()));
+    attributionSource.packageName = builder.getOpPackageName();
+    attributionSource.attributionTag = builder.getAttributionTag();
+    attributionSource.token = sp<android::BBinder>::make();
 
     // Build the request to send to the server.
-    request.setIdentity(identity);
+    request.setAttributionSource(attributionSource);
     request.setSharingModeMatchRequired(isSharingModeMatchRequired());
     request.setInService(isInService());
 
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 0d60120..acfac24 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -25,8 +25,7 @@
 
 // TODO These defines should be moved to a central place in audio.
 #define SAMPLES_PER_FRAME_MIN        1
-// TODO Remove 8 channel limitation.
-#define SAMPLES_PER_FRAME_MAX        FCC_8
+#define SAMPLES_PER_FRAME_MAX        FCC_LIMIT
 #define SAMPLE_RATE_HZ_MIN           8000
 // HDMI supports up to 32 channels at 1536000 Hz.
 #define SAMPLE_RATE_HZ_MAX           1600000
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 2135c54..e015592 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -43,8 +43,7 @@
 // on the edge of being ridiculous.
 // TODO These defines should be moved to a central place in audio.
 #define SAMPLES_PER_FRAME_MIN        1
-// TODO Remove 8 channel limitation.
-#define SAMPLES_PER_FRAME_MAX        FCC_8
+#define SAMPLES_PER_FRAME_MAX        FCC_LIMIT
 #define SAMPLE_RATE_HZ_MIN           8000
 // HDMI supports up to 32 channels at 1536000 Hz.
 #define SAMPLE_RATE_HZ_MAX           1600000
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 60eb73a..e96e134 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -94,10 +94,15 @@
             AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
             if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
                 ALOGW("processCallbackCommon() data, stream disconnected");
+                // This will kill the stream and prevent it from being restarted.
+                // That is OK because the stream is disconnected.
                 audioBuffer->size = SIZE_STOP_CALLBACKS;
             } else if (!mCallbackEnabled.load()) {
-                ALOGW("processCallbackCommon() no data because callback disabled");
-                audioBuffer->size = SIZE_STOP_CALLBACKS;
+                ALOGW("processCallbackCommon() no data because callback disabled, set size=0");
+                // Do NOT use SIZE_STOP_CALLBACKS here because that will kill the stream and
+                // prevent it from being restarted. This can occur because of a race condition
+                // caused by Legacy callbacks running after the track is "stopped".
+                audioBuffer->size = 0;
             } else {
                 if (audioBuffer->frameCount == 0) {
                     ALOGW("processCallbackCommon() data, frameCount is zero");
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index eca5392..dc66742 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -32,7 +32,7 @@
 #include "utility/AudioClock.h"
 #include "utility/FixedBlockWriter.h"
 
-using android::media::permission::Identity;
+using android::content::AttributionSourceState;
 
 using namespace android;
 using namespace aaudio;
@@ -157,12 +157,13 @@
             .tags = ""
     };
 
-    // TODO b/182392769: use identity util
-    Identity identity;
-    identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
-    identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
-    identity.packageName = builder.getOpPackageName();
-    identity.attributionTag = builder.getAttributionTag();
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource;
+    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
+    attributionSource.packageName = builder.getOpPackageName();
+    attributionSource.attributionTag = builder.getAttributionTag();
+    attributionSource.token = sp<BBinder>::make();
 
     // ----------- open the AudioRecord ---------------------
     // Might retry, but never more than once.
@@ -170,7 +171,7 @@
         const audio_format_t requestedInternalFormat = getDeviceFormat();
 
         mAudioRecord = new AudioRecord(
-                identity
+                attributionSource
         );
         mAudioRecord->set(
                 AUDIO_SOURCE_DEFAULT, // ignored because we pass attributes below
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index 7d0a197..692651d 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -25,7 +25,7 @@
 #include "AAudioLegacy.h"
 #include "legacy/AudioStreamLegacy.h"
 #include "utility/FixedBlockWriter.h"
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 namespace aaudio {
 
@@ -87,7 +87,7 @@
     FixedBlockWriter                 mFixedBlockWriter;
 
     // TODO add 64-bit position reporting to AudioRecord and use it.
-    android::media::permission::Identity mIdentity;
+    android::content::AttributionSourceState mAttributionSource;
 
     // Only one type of conversion buffer is used.
     std::unique_ptr<float[]>         mFormatConversionBufferFloat;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 04a9dec..1d412c0 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -33,7 +33,7 @@
 using namespace android;
 using namespace aaudio;
 
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 // Arbitrary and somewhat generous number of bursts.
 #define DEFAULT_BURSTS_PER_BUFFER_CAPACITY     8
@@ -151,7 +151,7 @@
     };
 
     mAudioTrack = new AudioTrack();
-    // TODO b/182392769: use identity util
+    // TODO b/182392769: use attribution source util
     mAudioTrack->set(
             AUDIO_STREAM_DEFAULT,  // ignored because we pass attributes below
             getSampleRate(),
@@ -167,7 +167,7 @@
             sessionId,
             streamTransferType,
             NULL,    // DEFAULT audio_offload_info_t
-            Identity(), // DEFAULT uid and pid
+            AttributionSourceState(), // DEFAULT uid and pid
             &attributes,
             // WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
             // headphones a few times.
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index c77aeeb..321e7f9 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -1182,7 +1182,7 @@
         const media::AudioClient& aidl) {
     AudioClient legacy;
     legacy.clientTid = VALUE_OR_RETURN(aidl2legacy_int32_t_pid_t(aidl.clientTid));
-    legacy.identity = aidl.identity;
+    legacy.attributionSource = aidl.attributionSource;
     return legacy;
 }
 
@@ -1190,7 +1190,7 @@
         const AudioClient& legacy) {
     media::AudioClient aidl;
     aidl.clientTid = VALUE_OR_RETURN(legacy2aidl_pid_t_int32_t(legacy.clientTid));
-    aidl.identity = legacy.identity;
+    aidl.attributionSource = legacy.attributionSource;
     return aidl;
 }
 
@@ -2323,4 +2323,28 @@
     return unexpected(BAD_VALUE);
 }
 
+ConversionResult<TrackSecondaryOutputInfoPair>
+aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair(
+        const media::TrackSecondaryOutputInfo& aidl) {
+    TrackSecondaryOutputInfoPair trackSecondaryOutputInfoPair;
+    trackSecondaryOutputInfoPair.first =
+            VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.portId));
+    trackSecondaryOutputInfoPair.second =
+            VALUE_OR_RETURN(convertContainer<std::vector<audio_port_handle_t>>(
+                    aidl.secondaryOutputIds, aidl2legacy_int32_t_audio_io_handle_t));
+    return trackSecondaryOutputInfoPair;
+}
+
+ConversionResult<media::TrackSecondaryOutputInfo>
+legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo(
+        const TrackSecondaryOutputInfoPair& legacy) {
+    media::TrackSecondaryOutputInfo trackSecondaryOutputInfo;
+    trackSecondaryOutputInfo.portId =
+            VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy.first));
+    trackSecondaryOutputInfo.secondaryOutputIds =
+            VALUE_OR_RETURN(convertContainer<std::vector<int32_t>>(
+                    legacy.second, legacy2aidl_audio_io_handle_t_int32_t));
+    return trackSecondaryOutputInfo;
+}
+
 }  // namespace android
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 19d68a0..9c307ff 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -132,12 +132,12 @@
         "libshmemcompat",
         "libutils",
         "libvibrator",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
     export_shared_lib_headers: [
         "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libbinder",
     ],
 
@@ -164,7 +164,6 @@
         // for memory heap analysis
         "libc_malloc_debug_backtrace",
         "shared-file-region-aidl-cpp",
-        "media_permission-aidl-cpp",
     ],
     cflags: [
         "-Wall",
@@ -232,7 +231,7 @@
         "libshmemcompat",
         "libutils",
         "shared-file-region-aidl-cpp",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
     export_shared_lib_headers: [
         "audioclient-types-aidl-cpp",
@@ -351,10 +350,11 @@
         "aidl/android/media/AudioVibratorInfo.aidl",
         "aidl/android/media/EffectDescriptor.aidl",
         "aidl/android/media/ExtraAudioDescriptor.aidl",
+        "aidl/android/media/TrackSecondaryOutputInfo.aidl",
     ],
     imports: [
         "audio_common-aidl",
-        "media_permission-aidl",
+        "framework-permission-aidl",
     ],
     backend: {
         cpp: {
@@ -436,7 +436,7 @@
         "av-types-aidl",
         "effect-aidl",
         "shared-file-region-aidl",
-        "media_permission-aidl",
+        "framework-permission-aidl",
     ],
     double_loadable: true,
     backend: {
@@ -461,7 +461,6 @@
         "aidl/android/media/GetOutputForAttrResponse.aidl",
         "aidl/android/media/Int.aidl",
         "aidl/android/media/RecordClientInfo.aidl",
-
         "aidl/android/media/IAudioPolicyService.aidl",
         "aidl/android/media/IAudioPolicyServiceClient.aidl",
     ],
@@ -470,8 +469,9 @@
         "audioclient-types-aidl",
         "audiopolicy-types-aidl",
         "capture_state_listener-aidl",
-        "media_permission-aidl",
+        "framework-permission-aidl",
     ],
+
     double_loadable: true,
     backend: {
         cpp: {
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index d5047b1..6ad5483 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -42,7 +42,6 @@
 using aidl_utils::statusTFromBinderStatus;
 using binder::Status;
 using media::IAudioPolicyService;
-using media::permission::Identity;
 
 namespace {
 
@@ -58,8 +57,8 @@
 
 // ---------------------------------------------------------------------------
 
-AudioEffect::AudioEffect(const Identity& identity)
-    : mClientIdentity(identity)
+AudioEffect::AudioEffect(const android::content::AttributionSourceState& attributionSource)
+    : mClientAttributionSource(attributionSource)
 {
 }
 
@@ -108,12 +107,12 @@
     mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
     mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);
 
-    // TODO b/182392769: use identity util
+    // TODO b/182392769: use attribution source util
     mIEffectClient = new EffectClient(this);
     pid_t pid = IPCThreadState::self()->getCallingPid();
-    mClientIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(pid));
+    mClientAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(pid));
     pid_t uid = IPCThreadState::self()->getCallingUid();
-    mClientIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
+    mClientAttributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
 
     media::CreateEffectRequest request;
     request.desc = VALUE_OR_RETURN_STATUS(
@@ -123,7 +122,7 @@
     request.output = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(io));
     request.sessionId = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_session_t_int32_t(mSessionId));
     request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioDeviceTypeAddress(device));
-    request.identity = mClientIdentity;
+    request.attributionSource = mClientAttributionSource;
     request.probe = probe;
 
     media::CreateEffectResponse response;
@@ -178,7 +177,7 @@
 
     IInterface::asBinder(iEffect)->linkToDeath(mIEffectClient);
     ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
-            mStatus, mEnabled, mClientIdentity.pid);
+            mStatus, mEnabled, mClientAttributionSource.pid);
 
     if (!audio_is_global_session(mSessionId)) {
         AudioSystem::acquireAudioSessionId(mSessionId, pid, uid);
@@ -223,7 +222,7 @@
     if (!mProbe && (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS)) {
         if (!audio_is_global_session(mSessionId)) {
             AudioSystem::releaseAudioSessionId(mSessionId,
-                VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid)));
+                VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientAttributionSource.pid)));
         }
         if (mIEffect != NULL) {
             mIEffect->disconnect();
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 1a4bde9..a1d3bdb 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -39,7 +39,7 @@
 
 namespace android {
 
-using android::media::permission::Identity;
+using android::content::AttributionSourceState;
 using aidl_utils::statusTFromBinderStatus;
 
 // ---------------------------------------------------------------------------
@@ -126,11 +126,11 @@
     return NO_ERROR;
 }
 
-AudioRecord::AudioRecord(const Identity &client)
-    : mActive(false), mStatus(NO_INIT), mClientIdentity(client), mSessionId(AUDIO_SESSION_ALLOCATE),
-      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
+AudioRecord::AudioRecord(const AttributionSourceState &client)
+    : mActive(false), mStatus(NO_INIT), mClientAttributionSource(client),
+      mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+      mPreviousSchedulingGroup(SP_DEFAULT), mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE), mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
       mSelectedMicFieldDimension(MIC_FIELD_DIMENSION_DEFAULT)
 {
 }
@@ -140,7 +140,7 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        const Identity& client,
+        const AttributionSourceState& client,
         size_t frameCount,
         callback_t cbf,
         void* user,
@@ -154,14 +154,14 @@
         float microphoneFieldDimension)
     : mActive(false),
       mStatus(NO_INIT),
-      mClientIdentity(client),
+      mClientAttributionSource(client),
       mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mProxy(NULL)
 {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mClientIdentity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid));
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mClientAttributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientAttributionSource.pid));
     (void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
             notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
             uid, pid, pAttributes, selectedDeviceId, selectedMicDirection,
@@ -191,7 +191,7 @@
         IPCThreadState::self()->flushCommands();
         ALOGV("%s(%d): releasing session id %d",
                 __func__, mPortId, mSessionId);
-        pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid));
+        pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientAttributionSource.pid));
         AudioSystem::releaseAudioSessionId(mSessionId, pid);
     }
 }
@@ -243,11 +243,11 @@
 
     // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
     ALOGV("%s(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
-          "notificationFrames %u, sessionId %d, transferType %d, flags %#x, identity %s"
+          "notificationFrames %u, sessionId %d, transferType %d, flags %#x, attributionSource %s"
           "uid %d, pid %d",
           __func__,
           inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
-          sessionId, transferType, flags, mClientIdentity.toString().c_str(), uid, pid);
+          sessionId, transferType, flags, mClientAttributionSource.toString().c_str(), uid, pid);
 
     // TODO b/182392553: refactor or remove
     pid_t callingPid = IPCThreadState::self()->getCallingPid();
@@ -256,13 +256,13 @@
     if (pid == -1 || (callingPid != myPid)) {
         adjPid = callingPid;
     }
-    mClientIdentity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(adjPid));
+    mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(adjPid));
 
     uid_t adjUid = uid;
     if (uid == -1 || (callingPid != myPid)) {
         adjUid = IPCThreadState::self()->getCallingUid();
     }
-    mClientIdentity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(adjUid));
+    mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(adjUid));
 
     mTracker.reset(new RecordingActivityTracker());
 
@@ -801,7 +801,7 @@
     input.config.sample_rate = mSampleRate;
     input.config.channel_mask = mChannelMask;
     input.config.format = mFormat;
-    input.clientInfo.identity = mClientIdentity;
+    input.clientInfo.attributionSource = mClientAttributionSource;
     input.clientInfo.clientTid = -1;
     if (mFlags & AUDIO_INPUT_FLAG_FAST) {
         if (mAudioRecordThread != 0) {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 0bc592d..88e752b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -52,7 +52,7 @@
 using aidl_utils::statusTFromBinderStatus;
 using binder::Status;
 using media::IAudioPolicyService;
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 // client singleton for AudioFlinger binder interface
 Mutex AudioSystem::gLock;
@@ -71,6 +71,25 @@
 Mutex gSoundTriggerCaptureStateListenerLock;
 sp<CaptureStateListenerImpl> gSoundTriggerCaptureStateListener = nullptr;
 
+// Binder for the AudioFlinger service that's passed to this client process from the system server.
+// This allows specific isolated processes to access the audio system. Currently used only for the
+// HotwordDetectionService.
+sp<IBinder> gAudioFlingerBinder = nullptr;
+
+void AudioSystem::setAudioFlingerBinder(const sp<IBinder>& audioFlinger) {
+    if (audioFlinger->getInterfaceDescriptor() != media::IAudioFlingerService::descriptor) {
+        ALOGE("setAudioFlingerBinder: received a binder of type %s",
+              String8(audioFlinger->getInterfaceDescriptor()).string());
+        return;
+    }
+    Mutex::Autolock _l(gLock);
+    if (gAudioFlinger != nullptr) {
+        ALOGW("setAudioFlingerBinder: ignoring; AudioFlinger connection already established.");
+        return;
+    }
+    gAudioFlingerBinder = audioFlinger;
+}
+
 // establish binder interface to AudioFlinger service
 const sp<IAudioFlinger> AudioSystem::get_audio_flinger() {
     sp<IAudioFlinger> af;
@@ -79,15 +98,19 @@
     {
         Mutex::Autolock _l(gLock);
         if (gAudioFlinger == 0) {
-            sp<IServiceManager> sm = defaultServiceManager();
             sp<IBinder> binder;
-            do {
-                binder = sm->getService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME));
-                if (binder != 0)
-                    break;
-                ALOGW("AudioFlinger not published, waiting...");
-                usleep(500000); // 0.5 s
-            } while (true);
+            if (gAudioFlingerBinder != nullptr) {
+                binder = gAudioFlingerBinder;
+            } else {
+                sp<IServiceManager> sm = defaultServiceManager();
+                do {
+                    binder = sm->getService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME));
+                    if (binder != 0)
+                        break;
+                    ALOGW("AudioFlinger not published, waiting...");
+                    usleep(500000); // 0.5 s
+                } while (true);
+            }
             if (gAudioFlingerClient == NULL) {
                 gAudioFlingerClient = new AudioFlingerClient();
             } else {
@@ -941,7 +964,7 @@
                                        audio_io_handle_t* output,
                                        audio_session_t session,
                                        audio_stream_type_t* stream,
-                                       const Identity& identity,
+                                       const AttributionSourceState& attributionSource,
                                        const audio_config_t* config,
                                        audio_output_flags_t flags,
                                        audio_port_handle_t* selectedDeviceId,
@@ -984,7 +1007,7 @@
     media::GetOutputForAttrResponse responseAidl;
 
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-            aps->getOutputForAttr(attrAidl, sessionAidl, identity, configAidl, flagsAidl,
+            aps->getOutputForAttr(attrAidl, sessionAidl, attributionSource, configAidl, flagsAidl,
                                   selectedDeviceIdAidl, &responseAidl)));
 
     *output = VALUE_OR_RETURN_STATUS(
@@ -1038,7 +1061,7 @@
                                       audio_io_handle_t* input,
                                       audio_unique_id_t riid,
                                       audio_session_t session,
-                                      const Identity &identity,
+                                      const AttributionSourceState &attributionSource,
                                       const audio_config_base_t* config,
                                       audio_input_flags_t flags,
                                       audio_port_handle_t* selectedDeviceId,
@@ -1077,7 +1100,7 @@
     media::GetInputForAttrResponse response;
 
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-            aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl, identity,
+            aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl, attributionSource,
                 configAidl, flagsAidl, selectedDeviceIdAidl, &response)));
 
     *input = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_io_handle_t(response.input));
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 1bc3baa..6765bdb 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -48,7 +48,7 @@
 // ---------------------------------------------------------------------------
 
 using media::VolumeShaper;
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 // TODO: Move to a separate .h
 
@@ -225,11 +225,11 @@
     return NO_ERROR;
 }
 
-AudioTrack::AudioTrack() : AudioTrack(Identity())
+AudioTrack::AudioTrack() : AudioTrack(AttributionSourceState())
 {
 }
 
-AudioTrack::AudioTrack(const Identity& identity)
+AudioTrack::AudioTrack(const AttributionSourceState& attributionSource)
     : mStatus(NO_INIT),
       mState(STATE_STOPPED),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -237,7 +237,7 @@
       mPausedPosition(0),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
       mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mClientIdentity(identity),
+      mClientAttributionSource(attributionSource),
       mAudioTrackCallback(new AudioTrackCallback())
 {
     mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
@@ -259,7 +259,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        const Identity& identity,
+        const AttributionSourceState& attributionSource,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
         float maxRequiredSpeed,
@@ -275,8 +275,8 @@
 
     (void)set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
-            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
-            offloadInfo, identity, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
+            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
+            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
 }
 
 AudioTrack::AudioTrack(
@@ -292,7 +292,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        const Identity& identity,
+        const AttributionSourceState& attributionSource,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
         float maxRequiredSpeed)
@@ -309,7 +309,7 @@
     (void)set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
             sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
-            identity, pAttributes, doNotReconnect, maxRequiredSpeed);
+            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed);
 }
 
 AudioTrack::~AudioTrack()
@@ -335,7 +335,7 @@
         mCblkMemory.clear();
         mSharedBuffer.clear();
         IPCThreadState::self()->flushCommands();
-        pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid));
+        pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientAttributionSource.pid));
         ALOGV("%s(%d), releasing session id %d from %d on behalf of %d",
                 __func__, mPortId,
                 mSessionId, IPCThreadState::self()->getCallingPid(), clientPid);
@@ -381,7 +381,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        const Identity& identity,
+        const AttributionSourceState& attributionSource,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
         float maxRequiredSpeed,
@@ -391,15 +391,15 @@
     uint32_t channelCount;
     pid_t callingPid;
     pid_t myPid;
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
 
     // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
     ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
           __func__,
           streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
-          sessionId, transferType, identity.uid, identity.pid);
+          sessionId, transferType, attributionSource.uid, attributionSource.pid);
 
     mThreadCanCallJava = threadCanCallJava;
     mSelectedDeviceId = selectedDeviceId;
@@ -596,18 +596,15 @@
     }
     mNotificationFramesAct = 0;
     // TODO b/182392553: refactor or remove
+    mClientAttributionSource = AttributionSourceState(attributionSource);
     callingPid = IPCThreadState::self()->getCallingPid();
     myPid = getpid();
     if (uid == -1 || (callingPid != myPid)) {
-        mClientIdentity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
+        mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
             IPCThreadState::self()->getCallingUid()));
-    } else {
-        mClientIdentity.uid = identity.uid;
     }
     if (pid == (pid_t)-1 || (callingPid != myPid)) {
-        mClientIdentity.pid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(callingPid));
-    } else {
-        mClientIdentity.pid = identity.pid;
+        mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(callingPid));
     }
     mAuxEffectId = 0;
     mOrigFlags = mFlags = flags;
@@ -692,13 +689,14 @@
         float maxRequiredSpeed,
         audio_port_handle_t selectedDeviceId)
 {
-    Identity identity;
-    identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
-    identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
+    AttributionSourceState attributionSource;
+    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
+    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
+    attributionSource.token = sp<BBinder>::make();
     return set(streamType, sampleRate, format,
             static_cast<audio_channel_mask_t>(channelMask),
             frameCount, flags, cbf, user, notificationFrames, sharedBuffer,
-            threadCanCallJava, sessionId, transferType, offloadInfo, identity,
+            threadCanCallJava, sessionId, transferType, offloadInfo, attributionSource,
             pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
 }
 
@@ -1700,7 +1698,7 @@
     input.config.channel_mask = mChannelMask;
     input.config.format = mFormat;
     input.config.offload_info = mOffloadInfoCopy;
-    input.clientInfo.identity = mClientIdentity;
+    input.clientInfo.attributionSource = mClientAttributionSource;
     input.clientInfo.clientTid = -1;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         // It is currently meaningless to request SCHED_FIFO for a Java thread.  Even if the
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 389b73f..0564cdf 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -743,6 +743,16 @@
     return statusTFromBinderStatus(mDelegate->setVibratorInfos(vibratorInfos));
 }
 
+status_t AudioFlingerClientAdapter::updateSecondaryOutputs(
+        const TrackSecondaryOutputsMap& trackSecondaryOutputs) {
+    std::vector<media::TrackSecondaryOutputInfo> trackSecondaryOutputInfos =
+            VALUE_OR_RETURN_STATUS(
+                    convertContainer<std::vector<media::TrackSecondaryOutputInfo>>(
+                            trackSecondaryOutputs,
+                            legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo));
+    return statusTFromBinderStatus(mDelegate->updateSecondaryOutputs(trackSecondaryOutputInfos));
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // AudioFlingerServerAdapter
@@ -1199,4 +1209,13 @@
     return Status::fromStatusT(mDelegate->setVibratorInfos(vibratorInfos));
 }
 
+Status AudioFlingerServerAdapter::updateSecondaryOutputs(
+        const std::vector<media::TrackSecondaryOutputInfo>& trackSecondaryOutputInfos) {
+    TrackSecondaryOutputsMap trackSecondaryOutputs =
+            VALUE_OR_RETURN_BINDER(convertContainer<TrackSecondaryOutputsMap>(
+                    trackSecondaryOutputInfos,
+                    aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair));
+    return Status::fromStatusT(mDelegate->updateSecondaryOutputs(trackSecondaryOutputs));
+}
+
 } // namespace android
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 451c4b1..e5e8496 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -27,7 +27,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 // Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
 const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
@@ -1260,10 +1260,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 bool ToneGenerator::initAudioTrack() {
     // Open audio track in mono, PCM 16bit, default sampling rate.
-    // TODO b/182392769: use identity util
-    Identity identity = Identity();
-    identity.packageName = mOpPackageName;
-    mpAudioTrack = new AudioTrack(identity);
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource = AttributionSourceState();
+    attributionSource.packageName = mOpPackageName;
+    attributionSource.token = sp<BBinder>::make();
+    mpAudioTrack = new AudioTrack(attributionSource);
     ALOGV("AudioTrack(%p) created", mpAudioTrack.get());
 
     audio_attributes_t attr;
@@ -1289,7 +1290,7 @@
             AUDIO_SESSION_ALLOCATE,
             AudioTrack::TRANSFER_CALLBACK,
             nullptr,
-            identity,
+            attributionSource,
             &attr);
     // Set caller name so it can be logged in destructor.
     // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR
diff --git a/media/libaudioclient/aidl/android/media/AudioClient.aidl b/media/libaudioclient/aidl/android/media/AudioClient.aidl
index aa4d8f5..e98fed3 100644
--- a/media/libaudioclient/aidl/android/media/AudioClient.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioClient.aidl
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.media.permission.Identity;
+import android.content.AttributionSourceState;
 
 /**
  * {@hide}
@@ -24,5 +24,5 @@
 parcelable AudioClient {
     /** Interpreted as pid_t. */
     int clientTid;
-    Identity identity;
+    AttributionSourceState attributionSource;
 }
diff --git a/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl b/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl
index 5737fcd..2d274f4 100644
--- a/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl
@@ -19,7 +19,7 @@
 import android.media.AudioDevice;
 import android.media.EffectDescriptor;
 import android.media.IEffectClient;
-import android.media.permission.Identity;
+import android.content.AttributionSourceState;
 
 /**
  * Input arguments of the createEffect() method.
@@ -35,6 +35,6 @@
     /** Interpreted as audio_session_t. */
     int sessionId;
     AudioDevice device;
-    Identity identity;
+    AttributionSourceState attributionSource;
     boolean probe;
 }
diff --git a/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
index 5b26d22..7e3c240 100644
--- a/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
@@ -19,7 +19,6 @@
 import android.media.AudioAttributesInternal;
 import android.media.AudioClient;
 import android.media.AudioConfigBase;
-import android.media.permission.Identity;
 
 /**
  * CreateRecordRequest contains all input arguments sent by AudioRecord to AudioFlinger
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index abbced5..d2cae6d 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -40,6 +40,7 @@
 import android.media.IAudioTrack;
 import android.media.MicrophoneInfoData;
 import android.media.RenderPosition;
+import android.media.TrackSecondaryOutputInfo;
 import android.media.audio.common.AudioFormat;
 
 /**
@@ -207,4 +208,9 @@
     // Set vibrators' information.
     // The value will be used to initialize HapticGenerator.
     void setVibratorInfos(in AudioVibratorInfo[] vibratorInfos);
+
+    // Update secondary outputs.
+    // This usually happens when there is a dynamic policy registered.
+    void updateSecondaryOutputs(
+            in TrackSecondaryOutputInfo[] trackSecondaryOutputInfos);
 }
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index f8924f3..65bcd82 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import android.content.AttributionSourceState;
+
 import android.media.audio.common.AudioFormat;
 
 import android.media.AudioAttributesEx;
@@ -48,7 +50,6 @@
 import android.media.IAudioPolicyServiceClient;
 import android.media.ICaptureStateListener;
 import android.media.Int;
-import android.media.permission.Identity;
 import android.media.SoundTriggerSession;
 
 /**
@@ -81,7 +82,7 @@
 
     GetOutputForAttrResponse getOutputForAttr(in AudioAttributesInternal attr,
                                               int /* audio_session_t */ session,
-                                              in Identity identity,
+                                              in AttributionSourceState attributionSource,
                                               in AudioConfig config,
                                               int /* Bitmask, indexed by AudioOutputFlags */ flags,
                                               int /* audio_port_handle_t */ selectedDeviceId);
@@ -96,7 +97,7 @@
                                             int /* audio_io_handle_t */ input,
                                             int /* audio_unique_id_t */ riid,
                                             int /* audio_session_t */ session,
-                                            in Identity identity,
+                                            in AttributionSourceState attributionSource,
                                             in AudioConfigBase config,
                                             int /* Bitmask, indexed by AudioInputFlags */ flags,
                                             int /* audio_port_handle_t */ selectedDeviceId);
diff --git a/media/libaudioclient/aidl/android/media/TrackSecondaryOutputInfo.aidl b/media/libaudioclient/aidl/android/media/TrackSecondaryOutputInfo.aidl
new file mode 100644
index 0000000..113328e
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/TrackSecondaryOutputInfo.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * This is a class that contains port handle for a track and handles for all secondary
+ * outputs of the track.
+ * @hide
+ */
+parcelable TrackSecondaryOutputInfo {
+    int portId; // audio_port_handle_t
+    int[] secondaryOutputIds; // audio_io_handle_t[]
+}
\ No newline at end of file
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index 21e25b9..b290aa8 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -65,7 +65,7 @@
         "libutils",
         "libxml2",
         "mediametricsservice-aidl-cpp",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
     header_libs: [
         "libaudiofoundation_headers",
diff --git a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
index 1b75917..d03c6fa 100644
--- a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
+++ b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
@@ -23,7 +23,7 @@
  */
 
 #include <android_audio_policy_configuration_V7_0-enums.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 #include <media/AidlConversion.h>
@@ -48,7 +48,7 @@
 using namespace ::android::audio::policy::configuration::V7_0;
 }
 
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 constexpr audio_unique_id_use_t kUniqueIds[] = {
     AUDIO_UNIQUE_ID_USE_UNSPECIFIED, AUDIO_UNIQUE_ID_USE_SESSION, AUDIO_UNIQUE_ID_USE_MODULE,
@@ -225,15 +225,16 @@
     attributes.usage = usage;
     sp<AudioTrack> track = new AudioTrack();
 
-    // TODO b/182392769: use identity util
-    Identity i;
-    i.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
-    i.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource;
+    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
+    attributionSource.token = sp<BBinder>::make();
     track->set(AUDIO_STREAM_DEFAULT, sampleRate, format, channelMask, frameCount, flags, nullptr,
                nullptr, notificationFrames, sharedBuffer, false, sessionId,
                ((fast && sharedBuffer == 0) || offload) ? AudioTrack::TRANSFER_CALLBACK
                                                         : AudioTrack::TRANSFER_DEFAULT,
-               offload ? &offloadInfo : nullptr, i, &attributes, false, 1.0f,
+               offload ? &offloadInfo : nullptr, attributionSource, &attributes, false, 1.0f,
                AUDIO_PORT_HANDLE_NONE);
 
     status_t status = track->initCheck();
@@ -308,10 +309,11 @@
 
     attributes.source = inputSource;
 
-    // TODO b/182392769: use identity util
-    Identity i;
-    i.packageName = std::string(mFdp.ConsumeRandomLengthString().c_str());
-    sp<AudioRecord> record = new AudioRecord(i);
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource;
+    attributionSource.packageName = std::string(mFdp.ConsumeRandomLengthString().c_str());
+    attributionSource.token = sp<BBinder>::make();
+    sp<AudioRecord> record = new AudioRecord(attributionSource);
     record->set(AUDIO_SOURCE_DEFAULT, sampleRate, format, channelMask, frameCount, nullptr, nullptr,
                 notificationFrames, false, sessionId,
                 fast ? AudioRecord::TRANSFER_CALLBACK : AudioRecord::TRANSFER_DEFAULT, flags,
@@ -418,9 +420,9 @@
     request.output = io;
     request.sessionId = sessionId;
     request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioDeviceTypeAddress(device));
-    // TODO b/182392769: use identity util
-    request.identity.packageName = opPackageName;
-    request.identity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(getpid()));
+    // TODO b/182392769: use attribution source util
+    request.attributionSource.packageName = opPackageName;
+    request.attributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(getpid()));
     request.probe = false;
 
     media::CreateEffectResponse response{};
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index 1dd9d60..4ec69c7 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -50,6 +50,7 @@
 #include <android/media/AudioUniqueIdUse.h>
 #include <android/media/EffectDescriptor.h>
 #include <android/media/ExtraAudioDescriptor.h>
+#include <android/media/TrackSecondaryOutputInfo.h>
 
 #include <android/media/SharedFileRegion.h>
 #include <binder/IMemory.h>
@@ -407,6 +408,13 @@
 legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(
         const audio_encapsulation_type_t & legacy);
 
+using TrackSecondaryOutputInfoPair = std::pair<audio_port_handle_t, std::vector<audio_io_handle_t>>;
+ConversionResult<TrackSecondaryOutputInfoPair>
+aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair(
+        const media::TrackSecondaryOutputInfo& aidl);
+ConversionResult<media::TrackSecondaryOutputInfo>
+legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo(
+        const TrackSecondaryOutputInfoPair& legacy);
 
 
 }  // namespace android
diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h
index 295fd4f..3be8ce2 100644
--- a/media/libaudioclient/include/media/AudioClient.h
+++ b/media/libaudioclient/include/media/AudioClient.h
@@ -19,7 +19,7 @@
 #define ANDROID_AUDIO_CLIENT_H
 
 #include <sys/types.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 namespace android {
 
@@ -29,7 +29,7 @@
         clientTid(-1) {}
 
     pid_t clientTid;
-    android::media::permission::Identity identity;
+    android::content::AttributionSourceState attributionSource;
 };
 
 }; // namespace android
diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h
index 8e446ea..5dfe5fc 100644
--- a/media/libaudioclient/include/media/AudioCommonTypes.h
+++ b/media/libaudioclient/include/media/AudioCommonTypes.h
@@ -29,6 +29,8 @@
 using AttributesVector = std::vector<audio_attributes_t>;
 using StreamTypeVector = std::vector<audio_stream_type_t>;
 
+using TrackSecondaryOutputsMap = std::map<audio_port_handle_t, std::vector<audio_io_handle_t>>;
+
 constexpr bool operator==(const audio_attributes_t &lhs, const audio_attributes_t &rhs)
 {
     return lhs.usage == rhs.usage && lhs.content_type == rhs.content_type &&
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index 974ce62..3c19ec1 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -23,7 +23,7 @@
 #include <media/IAudioFlinger.h>
 #include <media/AudioSystem.h>
 #include <system/audio_effect.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
@@ -337,9 +337,9 @@
      *
      * Parameters:
      *
-     * client:      Identity for app-op checks
+     * client:      Attribution source for app-op checks
      */
-    explicit AudioEffect(const media::permission::Identity& client);
+    explicit AudioEffect(const android::content::AttributionSourceState& client);
 
     /* Terminates the AudioEffect and unregisters it from AudioFlinger.
      * The effect engine is also destroyed if this AudioEffect was the last controlling
@@ -531,7 +531,7 @@
      static const uint32_t kMaxPreProcessing = 10;
 
 protected:
-     media::permission::Identity mClientIdentity; // Identity used for app op checks.
+     android::content::AttributionSourceState mClientAttributionSource; // source for app op checks.
      bool                    mEnabled = false;   // enable state
      audio_session_t         mSessionId = AUDIO_SESSION_OUTPUT_MIX; // audio session ID
      int32_t                 mPriority = 0;      // priority for effect control
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 9965e25..326919a 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -32,7 +32,7 @@
 #include <utils/threads.h>
 
 #include "android/media/IAudioRecord.h"
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 namespace android {
 
@@ -149,9 +149,9 @@
      *
      * Parameters:
      *
-     * clientIdentity:          The identity of the owner of the record
+     * client:          The attribution source of the owner of the record
      */
-                        AudioRecord(const media::permission::Identity& clientIdentity);
+                        AudioRecord(const android::content::AttributionSourceState& client);
 
     /* Creates an AudioRecord object and registers it with AudioFlinger.
      * Once created, the track needs to be started before it can be used.
@@ -164,7 +164,7 @@
      * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
      *                     16 bits per sample).
      * channelMask:        Channel mask, such that audio_is_input_channel(channelMask) is true.
-     * client:             The identity of the owner of the record
+     * client:             The attribution source of the owner of the record
      * frameCount:         Minimum size of track PCM buffer in frames. This defines the
      *                     application's contribution to the
      *                     latency of the track.  The actual size selected by the AudioRecord could
@@ -187,7 +187,7 @@
                                     uint32_t sampleRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
-                                    const media::permission::Identity& clientIdentity,
+                                    const android::content::AttributionSourceState& client,
                                     size_t frameCount = 0,
                                     callback_t cbf = NULL,
                                     void* user = NULL,
@@ -696,7 +696,7 @@
 
     status_t                mStatus;
 
-    media::permission::Identity mClientIdentity;    // The identity of the owner of this record
+    android::content::AttributionSourceState mClientAttributionSource; // Owner's attribution source
 
     size_t                  mFrameCount;            // corresponds to current IAudioRecord, value is
                                                     // reported back by AudioFlinger to the client
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 4c99dbd..a9109c8 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -22,7 +22,7 @@
 #include <android/media/AudioVibratorInfo.h>
 #include <android/media/BnAudioFlingerClient.h>
 #include <android/media/BnAudioPolicyServiceClient.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <media/AidlConversionUtil.h>
 #include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioPolicy.h>
@@ -38,6 +38,8 @@
 #include <utils/Mutex.h>
 #include <vector>
 
+using android::content::AttributionSourceState;
+
 namespace android {
 
 struct record_client_info {
@@ -146,6 +148,11 @@
     static void setRecordConfigCallback(record_config_callback);
     static void setRoutingCallback(routing_callback cb);
 
+    // Sets the binder to use for accessing the AudioFlinger service. This enables the system server
+    // to grant specific isolated processes access to the audio system. Currently used only for the
+    // HotwordDetectionService.
+    static void setAudioFlingerBinder(const sp<IBinder>& audioFlinger);
+
     // helper function to obtain AudioFlinger service handle
     static const sp<IAudioFlinger> get_audio_flinger();
 
@@ -264,7 +271,7 @@
                                      audio_io_handle_t *output,
                                      audio_session_t session,
                                      audio_stream_type_t *stream,
-                                     const media::permission::Identity& identity,
+                                     const AttributionSourceState& attributionSource,
                                      const audio_config_t *config,
                                      audio_output_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId,
@@ -280,7 +287,7 @@
                                     audio_io_handle_t *input,
                                     audio_unique_id_t riid,
                                     audio_session_t session,
-                                    const media::permission::Identity& identity,
+                                     const AttributionSourceState& attributionSource,
                                     const audio_config_base_t *config,
                                     audio_input_flags_t flags,
                                     audio_port_handle_t *selectedDeviceId,
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index c293343..f61eef2 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -26,7 +26,7 @@
 #include <media/Modulo.h>
 #include <media/VolumeShaper.h>
 #include <utils/threads.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <string>
 
@@ -36,6 +36,8 @@
 
 namespace android {
 
+using content::AttributionSourceState;
+
 // ----------------------------------------------------------------------------
 
 struct audio_track_cblk_t;
@@ -182,7 +184,7 @@
      */
                         AudioTrack();
 
-                        AudioTrack(const media::permission::Identity& identity);
+                        AudioTrack(const AttributionSourceState& attributionSourceState);
 
     /* Creates an AudioTrack object and registers it with AudioFlinger.
      * Once created, the track needs to be started before it can be used.
@@ -230,7 +232,8 @@
      * transferType:       How data is transferred to AudioTrack.
      * offloadInfo:        If not NULL, provides offload parameters for
      *                     AudioSystem::getOutputForAttr().
-     * identity:           The identity of the app which initiallly requested this AudioTrack.
+     * attributionSource:  The attribution source of the app which initially requested this
+     *                     AudioTrack.
      *                     Includes the UID and PID for power management tracking, or -1 for
      *                     current user/process ID, plus the package name.
      * pAttributes:        If not NULL, supersedes streamType for use case selection.
@@ -259,8 +262,8 @@
                                     audio_session_t sessionId  = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    const media::permission::Identity& identity =
-                                        media::permission::Identity(),
+                                    const AttributionSourceState& attributionSource =
+                                        AttributionSourceState(),
                                     const audio_attributes_t* pAttributes = NULL,
                                     bool doNotReconnect = false,
                                     float maxRequiredSpeed = 1.0f,
@@ -290,8 +293,8 @@
                                     audio_session_t sessionId   = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    const media::permission::Identity& identity =
-                                        media::permission::Identity(),
+                                    const AttributionSourceState& attributionSource =
+                                        AttributionSourceState(),
                                     const audio_attributes_t* pAttributes = NULL,
                                     bool doNotReconnect = false,
                                     float maxRequiredSpeed = 1.0f);
@@ -338,8 +341,8 @@
                             audio_session_t sessionId  = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             const audio_offload_info_t *offloadInfo = NULL,
-                            const media::permission::Identity& identity =
-                                media::permission::Identity(),
+                            const AttributionSourceState& attributionSource =
+                                AttributionSourceState(),
                             const audio_attributes_t* pAttributes = NULL,
                             bool doNotReconnect = false,
                             float maxRequiredSpeed = 1.0f,
@@ -1347,7 +1350,7 @@
 
     sp<DeathNotifier>       mDeathNotifier;
     uint32_t                mSequence;              // incremented for each new IAudioTrack attempt
-    media::permission::Identity mClientIdentity;
+    AttributionSourceState mClientAttributionSource;
 
     wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
 
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 3a04569..327b37e 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -26,19 +26,21 @@
 #include <binder/IInterface.h>
 #include <media/AidlConversion.h>
 #include <media/AudioClient.h>
+#include <media/AudioCommonTypes.h>
 #include <media/DeviceDescriptorBase.h>
 #include <system/audio.h>
 #include <system/audio_effect.h>
 #include <system/audio_policy.h>
 #include <utils/String8.h>
 #include <media/MicrophoneInfo.h>
+#include <map>
 #include <string>
 #include <vector>
 
 #include <android/media/AudioVibratorInfo.h>
 #include <android/media/BnAudioFlingerService.h>
 #include <android/media/BpAudioFlingerService.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include "android/media/CreateEffectRequest.h"
 #include "android/media/CreateEffectResponse.h"
 #include "android/media/CreateRecordRequest.h"
@@ -55,6 +57,7 @@
 #include "android/media/OpenInputResponse.h"
 #include "android/media/OpenOutputRequest.h"
 #include "android/media/OpenOutputResponse.h"
+#include "android/media/TrackSecondaryOutputInfo.h"
 
 namespace android {
 
@@ -128,7 +131,6 @@
         audio_attributes_t attr;
         audio_config_base_t config;
         AudioClient clientInfo;
-        media::permission::Identity identity;
         audio_unique_id_t riid;
         int32_t maxSharedAudioHistoryMs;
 
@@ -338,6 +340,9 @@
     // The values will be used to initialize HapticGenerator.
     virtual status_t setVibratorInfos(
             const std::vector<media::AudioVibratorInfo>& vibratorInfos) = 0;
+
+    virtual status_t updateSecondaryOutputs(
+            const TrackSecondaryOutputsMap& trackSecondaryOutputs) = 0;
 };
 
 /**
@@ -430,6 +435,8 @@
     status_t getMicrophones(std::vector<media::MicrophoneInfo>* microphones) override;
     status_t setAudioHalPids(const std::vector<pid_t>& pids) override;
     status_t setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos) override;
+    status_t updateSecondaryOutputs(
+            const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
 
 private:
     const sp<media::IAudioFlingerService> mDelegate;
@@ -513,6 +520,7 @@
             SET_EFFECT_SUSPENDED = media::BnAudioFlingerService::TRANSACTION_setEffectSuspended,
             SET_AUDIO_HAL_PIDS = media::BnAudioFlingerService::TRANSACTION_setAudioHalPids,
             SET_VIBRATOR_INFOS = media::BnAudioFlingerService::TRANSACTION_setVibratorInfos,
+            UPDATE_SECONDARY_OUTPUTS = media::BnAudioFlingerService::TRANSACTION_updateSecondaryOutputs,
         };
 
         /**
@@ -619,6 +627,8 @@
     Status getMicrophones(std::vector<media::MicrophoneInfoData>* _aidl_return) override;
     Status setAudioHalPids(const std::vector<int32_t>& pids) override;
     Status setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos) override;
+    Status updateSecondaryOutputs(
+            const std::vector<media::TrackSecondaryOutputInfo>& trackSecondaryOutputInfos) override;
 
 private:
     const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 3c1da4d..def7ca6 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -37,6 +37,7 @@
         "libmediametrics_headers",
     ],
     shared_libs: [
+        "framework-permission-aidl-cpp",
         "libaudioclient",
         "libbinder",
         "libcutils",
@@ -59,6 +60,7 @@
         "libbinder",
         "libcutils",
         "libutils",
+        "framework-permission-aidl-cpp",
     ],
     data: ["record_test_input_*.txt"],
 }
diff --git a/media/libaudioclient/tests/test_create_audiorecord.cpp b/media/libaudioclient/tests/test_create_audiorecord.cpp
index 57676c1..1cbcb71 100644
--- a/media/libaudioclient/tests/test_create_audiorecord.cpp
+++ b/media/libaudioclient/tests/test_create_audiorecord.cpp
@@ -19,7 +19,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryDealer.h>
 #include <binder/MemoryHeapBase.h>
@@ -33,7 +33,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 int testRecord(FILE *inputFile, int outputFileFd)
 {
@@ -41,16 +41,17 @@
     uint32_t testCount = 0;
     Vector<String16> args;
     int ret = 0;
-    // TODO b/182392769: use identity util
-    Identity identity;
-    identity.packageName = PACKAGE_NAME;
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource;
+    attributionSource.packageName = std::string(PACKAGE_NAME);
+    attributionSource.token = sp<BBinder>::make();
 
     if (inputFile == nullptr) {
         sp<AudioRecord> record = new AudioRecord(AUDIO_SOURCE_DEFAULT,
                                               0 /* sampleRate */,
                                               AUDIO_FORMAT_DEFAULT,
                                               AUDIO_CHANNEL_IN_MONO,
-                                              identity);
+                                              attributionSource);
         if (record == 0 || record->initCheck() != NO_ERROR) {
             write(outputFileFd, "Error creating AudioRecord\n",
                   sizeof("Error creating AudioRecord\n"));
@@ -96,7 +97,7 @@
         memset(&attributes, 0, sizeof(attributes));
         attributes.source = inputSource;
 
-        sp<AudioRecord> record = new AudioRecord(identity);
+        sp<AudioRecord> record = new AudioRecord(attributionSource);
 
         record->set(AUDIO_SOURCE_DEFAULT,
                    sampleRate,
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
index a54e22f..f30eb54 100644
--- a/media/libaudioprocessing/AudioMixerBase.cpp
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "AudioMixer"
 //#define LOG_NDEBUG 0
 
+#include <array>
 #include <sstream>
 #include <string.h>
 
@@ -1295,8 +1296,29 @@
 
 // Needs to derive a compile time constant (constexpr).  Could be targeted to go
 // to a MONOVOL mixtype based on MAX_NUM_VOLUMES, but that's an unnecessary complication.
-#define MIXTYPE_MONOVOL(mixtype) ((mixtype) == MIXTYPE_MULTI ? MIXTYPE_MULTI_MONOVOL : \
-        (mixtype) == MIXTYPE_MULTI_SAVEONLY ? MIXTYPE_MULTI_SAVEONLY_MONOVOL : (mixtype))
+
+constexpr int MIXTYPE_MONOVOL(int mixtype, int channels) {
+    if (channels <= FCC_2) {
+        return mixtype;
+    } else if (mixtype == MIXTYPE_MULTI) {
+        return MIXTYPE_MULTI_MONOVOL;
+    } else if (mixtype == MIXTYPE_MULTI_SAVEONLY) {
+        return MIXTYPE_MULTI_SAVEONLY_MONOVOL;
+    } else {
+        return mixtype;
+    }
+}
+
+// Helper to make a functional array from volumeRampMulti.
+template <int MIXTYPE, typename TO, typename TI, typename TV, typename TA, typename TAV,
+          std::size_t ... Is>
+static constexpr auto makeVRMArray(std::index_sequence<Is...>)
+{
+    using F = void(*)(TO*, size_t, const TI*, TA*, TV*, const TV*, TAV*, TAV);
+    return std::array<F, sizeof...(Is)>{
+            { &volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE, Is + 1), Is + 1, TO, TI, TV, TA, TAV> ...}
+        };
+}
 
 /* MIXTYPE     (see AudioMixerOps.h MIXTYPE_* enumeration)
  * TO: int32_t (Q4.27) or float
@@ -1308,40 +1330,26 @@
 static void volumeRampMulti(uint32_t channels, TO* out, size_t frameCount,
         const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
 {
-    switch (channels) {
-    case 1:
-        volumeRampMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
-    case 2:
-        volumeRampMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
-    case 3:
-        volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out,
-                frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
-    case 4:
-        volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out,
-                frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
-    case 5:
-        volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out,
-                frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
-    case 6:
-        volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out,
-                frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
-    case 7:
-        volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out,
-                frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
-    case 8:
-        volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out,
-                frameCount, in, aux, vol, volinc, vola, volainc);
-        break;
+    static constexpr auto volumeRampMultiArray =
+            makeVRMArray<MIXTYPE, TO, TI, TV, TA, TAV>(std::make_index_sequence<FCC_LIMIT>());
+    if (channels > 0 && channels <= volumeRampMultiArray.size()) {
+        volumeRampMultiArray[channels - 1](out, frameCount, in, aux, vol, volinc, vola, volainc);
+    } else {
+        ALOGE("%s: invalid channel count:%d", __func__, channels);
     }
 }
 
+// Helper to make a functional array from volumeMulti.
+template <int MIXTYPE, typename TO, typename TI, typename TV, typename TA, typename TAV,
+          std::size_t ... Is>
+static constexpr auto makeVMArray(std::index_sequence<Is...>)
+{
+    using F = void(*)(TO*, size_t, const TI*, TA*, const TV*, TAV);
+    return std::array<F, sizeof...(Is)>{
+            { &volumeMulti<MIXTYPE_MONOVOL(MIXTYPE, Is + 1), Is + 1, TO, TI, TV, TA, TAV> ... }
+        };
+}
+
 /* MIXTYPE     (see AudioMixerOps.h MIXTYPE_* enumeration)
  * TO: int32_t (Q4.27) or float
  * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
@@ -1352,31 +1360,12 @@
 static void volumeMulti(uint32_t channels, TO* out, size_t frameCount,
         const TI* in, TA* aux, const TV *vol, TAV vola)
 {
-    switch (channels) {
-    case 1:
-        volumeMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, vola);
-        break;
-    case 2:
-        volumeMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, vola);
-        break;
-    case 3:
-        volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out, frameCount, in, aux, vol, vola);
-        break;
-    case 4:
-        volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out, frameCount, in, aux, vol, vola);
-        break;
-    case 5:
-        volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out, frameCount, in, aux, vol, vola);
-        break;
-    case 6:
-        volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out, frameCount, in, aux, vol, vola);
-        break;
-    case 7:
-        volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out, frameCount, in, aux, vol, vola);
-        break;
-    case 8:
-        volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out, frameCount, in, aux, vol, vola);
-        break;
+    static constexpr auto volumeMultiArray =
+            makeVMArray<MIXTYPE, TO, TI, TV, TA, TAV>(std::make_index_sequence<FCC_LIMIT>());
+    if (channels > 0 && channels <= volumeMultiArray.size()) {
+        volumeMultiArray[channels - 1](out, frameCount, in, aux, vol, vola);
+    } else {
+        ALOGE("%s: invalid channel count:%d", __func__, channels);
     }
 }
 
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index 8d374c9..cd47dc6 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_AUDIO_MIXER_OPS_H
 #define ANDROID_AUDIO_MIXER_OPS_H
 
+#include <system/audio.h>
+
 namespace android {
 
 // Hack to make static_assert work in a constexpr
@@ -231,7 +233,7 @@
         typename TO, typename TI, typename TV,
         typename F>
 void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) {
-    static_assert(NCHAN > 0 && NCHAN <= 8);
+    static_assert(NCHAN > 0 && NCHAN <= FCC_LIMIT);
     static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL
             || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
             || MIXTYPE == MIXTYPE_STEREOEXPAND
@@ -291,6 +293,16 @@
     // NCHAN == 8
     proc(*out++, f(inp(), vol[0])); // side left
     proc(*out++, f(inp(), vol[1])); // side right
+    if constexpr (NCHAN > FCC_8) {
+        // Mutes to zero extended surround channels.
+        // 7.1.4 has the correct behavior.
+        // 22.2 has the behavior that FLC and FRC will be mixed instead
+        // of SL and SR and LFE will be center, not left.
+        for (int i = 8; i < NCHAN; ++i) {
+            // TODO: Consider using android::audio_utils::channels::kSideFromChannelIdx
+            proc(*out++, f(inp(), 0.f));
+        }
+    }
 }
 
 /*
diff --git a/media/libaudioprocessing/AudioResampler.cpp b/media/libaudioprocessing/AudioResampler.cpp
index c761b38..51673d7 100644
--- a/media/libaudioprocessing/AudioResampler.cpp
+++ b/media/libaudioprocessing/AudioResampler.cpp
@@ -268,7 +268,7 @@
         mPhaseFraction(0),
         mQuality(quality) {
 
-    const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8;
+    const int maxChannels = quality < DYN_LOW_QUALITY ? FCC_2 : FCC_LIMIT;
     if (inChannelCount < 1
             || inChannelCount > maxChannels) {
         LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels",
diff --git a/media/libaudioprocessing/AudioResamplerDyn.cpp b/media/libaudioprocessing/AudioResamplerDyn.cpp
index 1aacfd1..2292b19 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.cpp
+++ b/media/libaudioprocessing/AudioResamplerDyn.cpp
@@ -545,64 +545,76 @@
     // Note: A stride of 2 is achieved with non-SIMD processing.
     int stride = ((c.mHalfNumCoefs & 7) == 0) ? 16 : 2;
     LOG_ALWAYS_FATAL_IF(stride < 16, "Resampler stride must be 16 or more");
-    LOG_ALWAYS_FATAL_IF(mChannelCount < 1 || mChannelCount > 8,
-            "Resampler channels(%d) must be between 1 to 8", mChannelCount);
+    LOG_ALWAYS_FATAL_IF(mChannelCount < 1 || mChannelCount > FCC_LIMIT,
+            "Resampler channels(%d) must be between 1 to %d", mChannelCount, FCC_LIMIT);
     // stride 16 (falls back to stride 2 for machines that do not support NEON)
+
+
+// For now use a #define as a compiler generated function table requires renaming.
+#pragma push_macro("AUDIORESAMPLERDYN_CASE")
+#undef AUDIORESAMPLERDYN_CASE
+#define AUDIORESAMPLERDYN_CASE(CHANNEL, LOCKED) \
+    case CHANNEL: if constexpr (CHANNEL <= FCC_LIMIT) {\
+        mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<CHANNEL, LOCKED, 16>; \
+    } break
+
     if (locked) {
         switch (mChannelCount) {
-        case 1:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
-            break;
-        case 2:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
-            break;
-        case 3:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, true, 16>;
-            break;
-        case 4:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, true, 16>;
-            break;
-        case 5:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, true, 16>;
-            break;
-        case 6:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, true, 16>;
-            break;
-        case 7:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, true, 16>;
-            break;
-        case 8:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, true, 16>;
-            break;
+        AUDIORESAMPLERDYN_CASE(1, true);
+        AUDIORESAMPLERDYN_CASE(2, true);
+        AUDIORESAMPLERDYN_CASE(3, true);
+        AUDIORESAMPLERDYN_CASE(4, true);
+        AUDIORESAMPLERDYN_CASE(5, true);
+        AUDIORESAMPLERDYN_CASE(6, true);
+        AUDIORESAMPLERDYN_CASE(7, true);
+        AUDIORESAMPLERDYN_CASE(8, true);
+        AUDIORESAMPLERDYN_CASE(9, true);
+        AUDIORESAMPLERDYN_CASE(10, true);
+        AUDIORESAMPLERDYN_CASE(11, true);
+        AUDIORESAMPLERDYN_CASE(12, true);
+        AUDIORESAMPLERDYN_CASE(13, true);
+        AUDIORESAMPLERDYN_CASE(14, true);
+        AUDIORESAMPLERDYN_CASE(15, true);
+        AUDIORESAMPLERDYN_CASE(16, true);
+        AUDIORESAMPLERDYN_CASE(17, true);
+        AUDIORESAMPLERDYN_CASE(18, true);
+        AUDIORESAMPLERDYN_CASE(19, true);
+        AUDIORESAMPLERDYN_CASE(20, true);
+        AUDIORESAMPLERDYN_CASE(21, true);
+        AUDIORESAMPLERDYN_CASE(22, true);
+        AUDIORESAMPLERDYN_CASE(23, true);
+        AUDIORESAMPLERDYN_CASE(24, true);
         }
     } else {
         switch (mChannelCount) {
-        case 1:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
-            break;
-        case 2:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
-            break;
-        case 3:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, false, 16>;
-            break;
-        case 4:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, false, 16>;
-            break;
-        case 5:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, false, 16>;
-            break;
-        case 6:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, false, 16>;
-            break;
-        case 7:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, false, 16>;
-            break;
-        case 8:
-            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, false, 16>;
-            break;
+        AUDIORESAMPLERDYN_CASE(1, false);
+        AUDIORESAMPLERDYN_CASE(2, false);
+        AUDIORESAMPLERDYN_CASE(3, false);
+        AUDIORESAMPLERDYN_CASE(4, false);
+        AUDIORESAMPLERDYN_CASE(5, false);
+        AUDIORESAMPLERDYN_CASE(6, false);
+        AUDIORESAMPLERDYN_CASE(7, false);
+        AUDIORESAMPLERDYN_CASE(8, false);
+        AUDIORESAMPLERDYN_CASE(9, false);
+        AUDIORESAMPLERDYN_CASE(10, false);
+        AUDIORESAMPLERDYN_CASE(11, false);
+        AUDIORESAMPLERDYN_CASE(12, false);
+        AUDIORESAMPLERDYN_CASE(13, false);
+        AUDIORESAMPLERDYN_CASE(14, false);
+        AUDIORESAMPLERDYN_CASE(15, false);
+        AUDIORESAMPLERDYN_CASE(16, false);
+        AUDIORESAMPLERDYN_CASE(17, false);
+        AUDIORESAMPLERDYN_CASE(18, false);
+        AUDIORESAMPLERDYN_CASE(19, false);
+        AUDIORESAMPLERDYN_CASE(20, false);
+        AUDIORESAMPLERDYN_CASE(21, false);
+        AUDIORESAMPLERDYN_CASE(22, false);
+        AUDIORESAMPLERDYN_CASE(23, false);
+        AUDIORESAMPLERDYN_CASE(24, false);
         }
     }
+#pragma pop_macro("AUDIORESAMPLERDYN_CASE")
+
 #ifdef DEBUG_RESAMPLER
     printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
             mChannelCount, locked ? "locked" : "interpolated",
diff --git a/media/libaudioprocessing/include/media/AudioMixerBase.h b/media/libaudioprocessing/include/media/AudioMixerBase.h
index cf84b83..3419816 100644
--- a/media/libaudioprocessing/include/media/AudioMixerBase.h
+++ b/media/libaudioprocessing/include/media/AudioMixerBase.h
@@ -45,8 +45,7 @@
 {
 public:
     // Do not change these unless underlying code changes.
-    // This mixer has a hard-coded upper limit of 8 channels for output.
-    static constexpr uint32_t MAX_NUM_CHANNELS = FCC_8;
+    static constexpr uint32_t MAX_NUM_CHANNELS = FCC_LIMIT;
     static constexpr uint32_t MAX_NUM_VOLUMES = FCC_2; // stereo volume only
 
     static const uint16_t UNITY_GAIN_INT = 0x1000;
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index e96c041..b26d028 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -18,11 +18,11 @@
     ],
 }
 
-cc_library_shared {
+cc_library {
     name: "libdownmix",
-
+    host_supported: true,
     vendor: true,
-    srcs: ["EffectDownmix.c"],
+    srcs: ["EffectDownmix.cpp"],
 
     shared_libs: [
         "libaudioutils",
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.cpp
similarity index 77%
rename from media/libeffects/downmix/EffectDownmix.c
rename to media/libeffects/downmix/EffectDownmix.cpp
index 5ca5525..f500bc3 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.cpp
@@ -16,32 +16,72 @@
 
 #define LOG_TAG "EffectDownmix"
 //#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include <log/log.h>
 
 #include "EffectDownmix.h"
+#include <math.h>
 
 // Do not submit with DOWNMIX_TEST_CHANNEL_INDEX defined, strictly for testing
 //#define DOWNMIX_TEST_CHANNEL_INDEX 0
 // Do not submit with DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER defined, strictly for testing
 //#define DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER 0
 
-#define MINUS_3_DB_IN_FLOAT 0.70710678f // -3dB = 0.70710678f
-const audio_format_t gTargetFormat = AUDIO_FORMAT_PCM_FLOAT;
+#define MINUS_3_DB_IN_FLOAT M_SQRT1_2 // -3dB = 0.70710678
 
-// subset of possible audio_channel_mask_t values, and AUDIO_CHANNEL_OUT_* renamed to CHANNEL_MASK_*
 typedef enum {
-    CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD_BACK,
-    CHANNEL_MASK_QUAD_SIDE = AUDIO_CHANNEL_OUT_QUAD_SIDE,
-    CHANNEL_MASK_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1_BACK,
-    CHANNEL_MASK_5POINT1_SIDE = AUDIO_CHANNEL_OUT_5POINT1_SIDE,
-    CHANNEL_MASK_7POINT1 = AUDIO_CHANNEL_OUT_7POINT1,
-} downmix_input_channel_mask_t;
+    DOWNMIX_STATE_UNINITIALIZED,
+    DOWNMIX_STATE_INITIALIZED,
+    DOWNMIX_STATE_ACTIVE,
+} downmix_state_t;
+
+/* parameters for each downmixer */
+typedef struct {
+    downmix_state_t state;
+    downmix_type_t type;
+    bool apply_volume_correction;
+    uint8_t input_channel_count;
+} downmix_object_t;
+
+typedef struct downmix_module_s {
+    const struct effect_interface_s *itfe;
+    effect_config_t config;
+    downmix_object_t context;
+} downmix_module_t;
+
+
+// Audio Effect API
+static int32_t DownmixLib_Create(const effect_uuid_t *uuid,
+        int32_t sessionId,
+        int32_t ioId,
+        effect_handle_t *pHandle);
+static int32_t DownmixLib_Release(effect_handle_t handle);
+static int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid,
+        effect_descriptor_t *pDescriptor);
+static int32_t Downmix_Process(effect_handle_t self,
+        audio_buffer_t *inBuffer,
+        audio_buffer_t *outBuffer);
+static int32_t Downmix_Command(effect_handle_t self,
+        uint32_t cmdCode,
+        uint32_t cmdSize,
+        void *pCmdData,
+        uint32_t *replySize,
+        void *pReplyData);
+static int32_t Downmix_GetDescriptor(effect_handle_t self,
+        effect_descriptor_t *pDescriptor);
+
+// Internal methods
+static int Downmix_Init(downmix_module_t *pDwmModule);
+static int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init);
+static int Downmix_Reset(downmix_object_t *pDownmixer, bool init);
+static int Downmix_setParameter(
+        downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue);
+static int Downmix_getParameter(
+        downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue);
+static void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate);
+static void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate);
+static void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate);
+static bool Downmix_foldGeneric(
+        uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate);
 
 // effect_handle_t interface implementation for downmix effect
 const struct effect_interface_s gDownmixInterface = {
@@ -63,7 +103,6 @@
     .get_descriptor = DownmixLib_GetDescriptor,
 };
 
-
 // AOSP insert downmix UUID: 93f04452-e4fe-41cc-91f9-e475b6d1d69f
 static const effect_descriptor_t gDownmixDescriptor = {
         EFFECT_UIID_DOWNMIX__, //type
@@ -84,16 +123,8 @@
 // number of effects in this library
 const int kNbEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
 
-static LVM_FLOAT clamp_float(LVM_FLOAT a) {
-    if (a > 1.0f) {
-        return 1.0f;
-    }
-    else if (a < -1.0f) {
-        return -1.0f;
-    }
-    else {
-        return a;
-    }
+static inline float clamp_float(float value) {
+    return fmin(fmax(value, -1.f), 1.f);
 }
 
 /*----------------------------------------------------------------------------
@@ -103,7 +134,7 @@
 // strictly for testing, logs the indices of the channels for a given mask,
 // uses the same code as Downmix_foldGeneric()
 void Downmix_testIndexComputation(uint32_t mask) {
-    ALOGI("Testing index computation for 0x%" PRIx32 ":", mask);
+    ALOGI("Testing index computation for %#x:", mask);
     // check against unsupported channels
     if (mask & kUnsupported) {
         ALOGE("Unsupported channels (top or front left/right of center)");
@@ -162,29 +193,10 @@
         return false;
     }
     // check against unsupported channels
-    if (mask & kUnsupported) {
-        ALOGE("Unsupported channels (top or front left/right of center)");
+    if (mask & ~AUDIO_CHANNEL_OUT_22POINT2) {
+        ALOGE("Unsupported channels in %u", mask & ~AUDIO_CHANNEL_OUT_22POINT2);
         return false;
     }
-    // verify has FL/FR
-    if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) {
-        ALOGE("Front channels must be present");
-        return false;
-    }
-    // verify uses SIDE as a pair (ok if not using SIDE at all)
-    if ((mask & kSides) != 0) {
-        if ((mask & kSides) != kSides) {
-            ALOGE("Side channels must be used as a pair");
-            return false;
-        }
-    }
-    // verify uses BACK as a pair (ok if not using BACK at all)
-    if ((mask & kBacks) != 0) {
-        if ((mask & kBacks) != kBacks) {
-            ALOGE("Back channels must be used as a pair");
-            return false;
-        }
-    }
     return true;
 }
 
@@ -194,9 +206,9 @@
 
 /*--- Effect Library Interface Implementation ---*/
 
-int32_t DownmixLib_Create(const effect_uuid_t *uuid,
-        int32_t sessionId __unused,
-        int32_t ioId __unused,
+static int32_t DownmixLib_Create(const effect_uuid_t *uuid,
+        int32_t /* sessionId */,
+        int32_t /* ioId */,
         effect_handle_t *pHandle) {
     int ret;
     int i;
@@ -210,9 +222,9 @@
     ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should work:");
     Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
                     AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_CENTER);
-    Downmix_testIndexComputation(CHANNEL_MASK_QUAD_SIDE | CHANNEL_MASK_QUAD_BACK);
-    Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_SIDE | AUDIO_CHANNEL_OUT_BACK_CENTER);
-    Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_BACK | AUDIO_CHANNEL_OUT_BACK_CENTER);
+    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_QUAD_SIDE | AUDIO_CHANNEL_OUT_QUAD_BACK);
+    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_5POINT1_SIDE | AUDIO_CHANNEL_OUT_BACK_CENTER);
+    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_5POINT1_BACK | AUDIO_CHANNEL_OUT_BACK_CENTER);
     // shouldn't work (will log an error, won't display channel indices)
     ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should NOT work:");
     Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
@@ -240,7 +252,7 @@
         return -ENOENT;
     }
 
-    module = malloc(sizeof(downmix_module_t));
+    module = new downmix_module_t{};
 
     module->itfe = &gDownmixInterface;
 
@@ -260,8 +272,7 @@
     return 0;
 }
 
-
-int32_t DownmixLib_Release(effect_handle_t handle) {
+static int32_t DownmixLib_Release(effect_handle_t handle) {
     downmix_module_t *pDwmModule = (downmix_module_t *)handle;
 
     ALOGV("DownmixLib_Release() %p", handle);
@@ -271,12 +282,12 @@
 
     pDwmModule->context.state = DOWNMIX_STATE_UNINITIALIZED;
 
-    free(pDwmModule);
+    delete pDwmModule;
     return 0;
 }
 
-
-int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) {
+static int32_t DownmixLib_GetDescriptor(
+        const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) {
     ALOGV("DownmixLib_GetDescriptor()");
     int i;
 
@@ -289,7 +300,7 @@
         ALOGV("DownmixLib_GetDescriptor() i=%d", i);
         if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
             memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t));
-            ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %" PRIx32,
+            ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %#x",
                  i, gDescriptors[i]->uuid.timeLow);
             return 0;
         }
@@ -300,11 +311,11 @@
 
 /*--- Effect Control Interface Implementation ---*/
 
-static int Downmix_Process(effect_handle_t self,
+static int32_t Downmix_Process(effect_handle_t self,
         audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
 
     downmix_object_t *pDownmixer;
-    LVM_FLOAT *pSrc, *pDst;
+    float *pSrc, *pDst;
     downmix_module_t *pDwmModule = (downmix_module_t *)self;
 
     if (pDwmModule == NULL) {
@@ -327,8 +338,8 @@
         return -ENODATA;
     }
 
-    pSrc = (LVM_FLOAT *) inBuffer->s16;
-    pDst = (LVM_FLOAT *) outBuffer->s16;
+    pSrc = inBuffer->f32;
+    pDst = outBuffer->f32;
     size_t numFrames = outBuffer->frameCount;
 
     const bool accumulate =
@@ -362,29 +373,29 @@
           // bypass the optimized downmix routines for the common formats
           if (!Downmix_foldGeneric(
                   downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
-              ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
+              ALOGE("Multichannel configuration %#x is not supported",
                     downmixInputChannelMask);
               return -EINVAL;
           }
           break;
 #endif
         // optimize for the common formats
-        switch((downmix_input_channel_mask_t)downmixInputChannelMask) {
-        case CHANNEL_MASK_QUAD_BACK:
-        case CHANNEL_MASK_QUAD_SIDE:
+        switch (downmixInputChannelMask) {
+        case AUDIO_CHANNEL_OUT_QUAD_BACK:
+        case AUDIO_CHANNEL_OUT_QUAD_SIDE:
             Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate);
             break;
-        case CHANNEL_MASK_5POINT1_BACK:
-        case CHANNEL_MASK_5POINT1_SIDE:
+        case AUDIO_CHANNEL_OUT_5POINT1_BACK:
+        case AUDIO_CHANNEL_OUT_5POINT1_SIDE:
             Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate);
             break;
-        case CHANNEL_MASK_7POINT1:
+        case AUDIO_CHANNEL_OUT_7POINT1:
             Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate);
             break;
         default:
             if (!Downmix_foldGeneric(
                     downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
-                ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
+                ALOGE("Multichannel configuration %#x is not supported",
                       downmixInputChannelMask);
                 return -EINVAL;
             }
@@ -399,7 +410,7 @@
     return 0;
 }
 
-static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
+static int32_t Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
         void *pCmdData, uint32_t *replySize, void *pReplyData) {
 
     downmix_module_t *pDwmModule = (downmix_module_t *) self;
@@ -411,7 +422,7 @@
 
     pDownmixer = (downmix_object_t*) &pDwmModule->context;
 
-    ALOGV("Downmix_Command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize);
+    ALOGV("Downmix_Command command %u cmdSize %u", cmdCode, cmdSize);
 
     switch (cmdCode) {
     case EFFECT_CMD_INIT:
@@ -434,8 +445,8 @@
         Downmix_Reset(pDownmixer, false);
         break;
 
-    case EFFECT_CMD_GET_PARAM:
-        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %" PRIu32 ", pReplyData: %p",
+    case EFFECT_CMD_GET_PARAM: {
+        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %u, pReplyData: %p",
                 pCmdData, *replySize, pReplyData);
         if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
                 pReplyData == NULL || replySize == NULL ||
@@ -444,15 +455,15 @@
         }
         effect_param_t *rep = (effect_param_t *) pReplyData;
         memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t));
-        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %" PRId32 ", replySize %" PRIu32,
+        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %d, replySize %u",
                 *(int32_t *)rep->data, rep->vsize);
         rep->status = Downmix_getParameter(pDownmixer, *(int32_t *)rep->data, &rep->vsize,
                 rep->data + sizeof(int32_t));
         *replySize = sizeof(effect_param_t) + sizeof(int32_t) + rep->vsize;
         break;
-
-    case EFFECT_CMD_SET_PARAM:
-        ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %" PRIu32
+    }
+    case EFFECT_CMD_SET_PARAM: {
+        ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %u"
                 ", pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
         if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
                 || pReplyData == NULL || replySize == NULL || *replySize != (int)sizeof(int32_t)) {
@@ -466,6 +477,7 @@
         *(int *)pReplyData = Downmix_setParameter(pDownmixer, *(int32_t *)cmd->data,
                 cmd->vsize, cmd->data + sizeof(int32_t));
         break;
+    }
 
     case EFFECT_CMD_SET_PARAM_DEFERRED:
         //FIXME implement
@@ -506,7 +518,7 @@
             return -EINVAL;
         }
         // FIXME change type if playing on headset vs speaker
-        ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: 0x%08" PRIx32, *(uint32_t *)pCmdData);
+        ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: %#x", *(uint32_t *)pCmdData);
         break;
 
     case EFFECT_CMD_SET_VOLUME: {
@@ -526,7 +538,7 @@
         if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
             return -EINVAL;
         }
-        ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %" PRIu32, *(uint32_t *)pCmdData);
+        ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %u", *(uint32_t *)pCmdData);
         break;
 
     case EFFECT_CMD_SET_CONFIG_REVERSE:
@@ -535,15 +547,14 @@
         break;
 
     default:
-        ALOGW("Downmix_Command invalid command %" PRIu32, cmdCode);
+        ALOGW("Downmix_Command invalid command %u", cmdCode);
         return -EINVAL;
     }
 
     return 0;
 }
 
-
-int Downmix_GetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor)
+static int32_t Downmix_GetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor)
 {
     downmix_module_t *pDwnmxModule = (downmix_module_t *) self;
 
@@ -591,7 +602,7 @@
  *----------------------------------------------------------------------------
  */
 
-int Downmix_Init(downmix_module_t *pDwmModule) {
+static int Downmix_Init(downmix_module_t *pDwmModule) {
 
     ALOGV("Downmix_Init module %p", pDwmModule);
     int ret = 0;
@@ -599,7 +610,7 @@
     memset(&pDwmModule->context, 0, sizeof(downmix_object_t));
 
     pDwmModule->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
-    pDwmModule->config.inputCfg.format = gTargetFormat;
+    pDwmModule->config.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
     pDwmModule->config.inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
     pDwmModule->config.inputCfg.bufferProvider.getBuffer = NULL;
     pDwmModule->config.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -611,7 +622,7 @@
 
     // set a default value for the access mode, but should be overwritten by caller
     pDwmModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
-    pDwmModule->config.outputCfg.format = gTargetFormat;
+    pDwmModule->config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
     pDwmModule->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
     pDwmModule->config.outputCfg.bufferProvider.getBuffer = NULL;
     pDwmModule->config.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -651,15 +662,15 @@
  *----------------------------------------------------------------------------
  */
 
-int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init) {
+static int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init) {
 
     downmix_object_t *pDownmixer = &pDwmModule->context;
 
     // Check configuration compatibility with build options, and effect capabilities
     if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate
-        || pConfig->outputCfg.channels != DOWNMIX_OUTPUT_CHANNELS
-        || pConfig->inputCfg.format != gTargetFormat
-        || pConfig->outputCfg.format != gTargetFormat) {
+        || pConfig->outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
+        || pConfig->inputCfg.format != AUDIO_FORMAT_PCM_FLOAT
+        || pConfig->outputCfg.format != AUDIO_FORMAT_PCM_FLOAT) {
         ALOGE("Downmix_Configure error: invalid config");
         return -EINVAL;
     }
@@ -709,7 +720,7 @@
  *----------------------------------------------------------------------------
  */
 
-int Downmix_Reset(downmix_object_t *pDownmixer __unused, bool init __unused) {
+static int Downmix_Reset(downmix_object_t* /* pDownmixer */, bool /* init */) {
     // nothing to do here
     return 0;
 }
@@ -736,31 +747,32 @@
  *
  *----------------------------------------------------------------------------
  */
-int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) {
+static int Downmix_setParameter(
+        downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) {
 
     int16_t value16;
-    ALOGV("Downmix_setParameter, context %p, param %" PRId32 ", value16 %" PRId16 ", value32 %" PRId32,
+    ALOGV("Downmix_setParameter, context %p, param %d, value16 %d, value32 %d",
             pDownmixer, param, *(int16_t *)pValue, *(int32_t *)pValue);
 
     switch (param) {
 
       case DOWNMIX_PARAM_TYPE:
         if (size != sizeof(downmix_type_t)) {
-            ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %" PRIu32 ", should be %zu",
+            ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %u, should be %zu",
                     size, sizeof(downmix_type_t));
             return -EINVAL;
         }
         value16 = *(int16_t *)pValue;
-        ALOGV("set DOWNMIX_PARAM_TYPE, type %" PRId16, value16);
+        ALOGV("set DOWNMIX_PARAM_TYPE, type %d", value16);
         if (!((value16 > DOWNMIX_TYPE_INVALID) && (value16 <= DOWNMIX_TYPE_LAST))) {
-            ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %" PRId16, value16);
+            ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %d", value16);
             return -EINVAL;
         } else {
             pDownmixer->type = (downmix_type_t) value16;
         break;
 
       default:
-        ALOGE("Downmix_setParameter unknown parameter %" PRId32, param);
+        ALOGE("Downmix_setParameter unknown parameter %d", param);
         return -EINVAL;
     }
 }
@@ -792,24 +804,25 @@
  *
  *----------------------------------------------------------------------------
  */
-int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue) {
+static int Downmix_getParameter(
+        downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue) {
     int16_t *pValue16;
 
     switch (param) {
 
     case DOWNMIX_PARAM_TYPE:
       if (*pSize < sizeof(int16_t)) {
-          ALOGE("Downmix_getParameter invalid parameter size %" PRIu32 " for DOWNMIX_PARAM_TYPE", *pSize);
+          ALOGE("Downmix_getParameter invalid parameter size %u for DOWNMIX_PARAM_TYPE", *pSize);
           return -EINVAL;
       }
       pValue16 = (int16_t *)pValue;
       *pValue16 = (int16_t) pDownmixer->type;
       *pSize = sizeof(int16_t);
-      ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %" PRId16, *pValue16);
+      ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %d", *pValue16);
       break;
 
     default:
-      ALOGE("Downmix_getParameter unknown parameter %" PRId16, param);
+      ALOGE("Downmix_getParameter unknown parameter %d", param);
       return -EINVAL;
     }
 
@@ -834,7 +847,7 @@
  *
  *----------------------------------------------------------------------------
  */
-void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
     // sample at index 0 is FL
     // sample at index 1 is FR
     // sample at index 2 is RL
@@ -879,8 +892,8 @@
  *
  *----------------------------------------------------------------------------
  */
-void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
-    LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
+void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
+    float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
     // sample at index 0 is FL
     // sample at index 1 is FR
     // sample at index 2 is FC
@@ -941,8 +954,8 @@
  *
  *----------------------------------------------------------------------------
  */
-void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
-    LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
+void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
+    float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
     // sample at index 0 is FL
     // sample at index 1 is FR
     // sample at index 2 is FC
@@ -992,13 +1005,7 @@
  * Downmix_foldGeneric()
  *----------------------------------------------------------------------------
  * Purpose:
- * downmix to stereo a multichannel signal whose format is:
- *  - has FL/FR
- *  - if using AUDIO_CHANNEL_OUT_SIDE*, it contains both left and right
- *  - if using AUDIO_CHANNEL_OUT_BACK*, it contains both left and right
- *  - doesn't use any of the AUDIO_CHANNEL_OUT_TOP* channels
- *  - doesn't use any of the AUDIO_CHANNEL_OUT_FRONT_*_OF_CENTER channels
- * Only handles channel masks not enumerated in downmix_input_channel_mask_t
+ * downmix to stereo a multichannel signal of arbitrary channel position mask.
  *
  * Inputs:
  *  mask       the channel mask of pSrc
@@ -1015,93 +1022,106 @@
  *----------------------------------------------------------------------------
  */
 bool Downmix_foldGeneric(
-        uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+        uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
 
     if (!Downmix_validChannelMask(mask)) {
         return false;
     }
-
-    const bool hasSides = (mask & kSides) != 0;
-    const bool hasBacks = (mask & kBacks) != 0;
-
     const int numChan = audio_channel_count_from_out_mask(mask);
-    const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
-    const bool hasLFE =
-            ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
-    const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
-    // compute at what index each channel is: samples will be in the following order:
-    //   FL FR FC LFE BL BR BC SL SR
-    // when a channel is not present, its index is set to the same as the index of the preceding
-    // channel
-    const int indexFC  = hasFC    ? 2            : 1;        // front center
-    const int indexLFE = hasLFE   ? indexFC + 1  : indexFC;  // low frequency
-    const int indexBL  = hasBacks ? indexLFE + 1 : indexLFE; // back left
-    const int indexBR  = hasBacks ? indexBL + 1  : indexBL;  // back right
-    const int indexBC  = hasBC    ? indexBR + 1  : indexBR;  // back center
-    const int indexSL  = hasSides ? indexBC + 1  : indexBC;  // side left
-    const int indexSR  = hasSides ? indexSL + 1  : indexSL;  // side right
 
-    LVM_FLOAT lt, rt, centersLfeContrib;
-    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
-    // for every sample
-    if (accumulate) {
-        while (numFrames) {
-            // compute contribution of FC, BC and LFE
-            centersLfeContrib = 0;
-            if (hasFC)  { centersLfeContrib += pSrc[indexFC]; }
-            if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
-            if (hasBC)  { centersLfeContrib += pSrc[indexBC]; }
-            centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
-            // always has FL/FR
-            lt = pSrc[0];
-            rt = pSrc[1];
-            // mix in sides and backs
-            if (hasSides) {
-                lt += pSrc[indexSL];
-                rt += pSrc[indexSR];
-            }
-            if (hasBacks) {
-                lt += pSrc[indexBL];
-                rt += pSrc[indexBR];
-            }
-            lt += centersLfeContrib;
-            rt += centersLfeContrib;
-            // accumulate in destination
-            pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
-            pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
-            pSrc += numChan;
-            pDst += 2;
-            numFrames--;
+    // compute at what index each channel is: samples will be in the following order:
+    //   FL  FR  FC    LFE   BL  BR  BC    SL  SR
+    //
+    //  (transfer matrix)
+    //   FL  FR  FC    LFE   BL  BR  BC    SL  SR
+    //   0.5     0.353 0.353 0.5     0.353 0.5
+    //       0.5 0.353 0.353     0.5 0.353     0.5
+
+    // derive the indices for the transfer matrix columns that have non-zero values.
+    int indexFL = -1;
+    int indexFR = -1;
+    int indexFC = -1;
+    int indexLFE = -1;
+    int indexBL = -1;
+    int indexBR = -1;
+    int indexBC = -1;
+    int indexSL = -1;
+    int indexSR = -1;
+    int index = 0;
+    for (unsigned tmp = mask;
+         (tmp & (AUDIO_CHANNEL_OUT_7POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER)) != 0;
+         ++index) {
+        const unsigned lowestBit = tmp & -(signed)tmp;
+        switch (lowestBit) {
+        case AUDIO_CHANNEL_OUT_FRONT_LEFT:
+            indexFL = index;
+            break;
+        case AUDIO_CHANNEL_OUT_FRONT_RIGHT:
+            indexFR = index;
+            break;
+        case AUDIO_CHANNEL_OUT_FRONT_CENTER:
+            indexFC = index;
+            break;
+        case AUDIO_CHANNEL_OUT_LOW_FREQUENCY:
+            indexLFE = index;
+            break;
+        case AUDIO_CHANNEL_OUT_BACK_LEFT:
+            indexBL = index;
+            break;
+        case AUDIO_CHANNEL_OUT_BACK_RIGHT:
+            indexBR = index;
+            break;
+        case AUDIO_CHANNEL_OUT_BACK_CENTER:
+            indexBC = index;
+            break;
+        case AUDIO_CHANNEL_OUT_SIDE_LEFT:
+            indexSL = index;
+            break;
+        case AUDIO_CHANNEL_OUT_SIDE_RIGHT:
+            indexSR = index;
+            break;
         }
-    } else {
-        while (numFrames) {
-            // compute contribution of FC, BC and LFE
-            centersLfeContrib = 0;
-            if (hasFC)  { centersLfeContrib += pSrc[indexFC]; }
-            if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
-            if (hasBC)  { centersLfeContrib += pSrc[indexBC]; }
-            centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
-            // always has FL/FR
-            lt = pSrc[0];
-            rt = pSrc[1];
-            // mix in sides and backs
-            if (hasSides) {
-                lt += pSrc[indexSL];
-                rt += pSrc[indexSR];
-            }
-            if (hasBacks) {
-                lt += pSrc[indexBL];
-                rt += pSrc[indexBR];
-            }
-            lt += centersLfeContrib;
-            rt += centersLfeContrib;
-            // store in destination
-            pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
-            pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
-            pSrc += numChan;
-            pDst += 2;
-            numFrames--;
+        tmp ^= lowestBit;
+    }
+
+    // With good branch prediction, this should run reasonably fast.
+    // Also consider using a transfer matrix form.
+    while (numFrames) {
+        // compute contribution of FC, BC and LFE
+        float centersLfeContrib = 0;
+        if (indexFC >= 0) centersLfeContrib = pSrc[indexFC];
+        if (indexLFE >= 0) centersLfeContrib += pSrc[indexLFE];
+        if (indexBC >= 0) centersLfeContrib += pSrc[indexBC];
+        centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
+
+        float ch[2];
+        ch[0] = centersLfeContrib;
+        ch[1] = centersLfeContrib;
+
+        // mix in left / right channels
+        if (indexFL >= 0) ch[0] += pSrc[indexFL];
+        if (indexFR >= 0) ch[1] += pSrc[indexFR];
+
+        if (indexSL >= 0) ch[0] += pSrc[indexSL];
+        if (indexSR >= 0) ch[1] += pSrc[indexSR]; // note pair checks enforce this if indexSL != 0
+
+        if (indexBL >= 0) ch[0] += pSrc[indexBL];
+        if (indexBR >= 0) ch[1] += pSrc[indexBR]; // note pair checks enforce this if indexBL != 0
+
+        // scale to prevent overflow.
+        ch[0] *= 0.5f;
+        ch[1] *= 0.5f;
+
+        if (accumulate) {
+            ch[0] += pDst[0];
+            ch[1] += pDst[1];
         }
+
+        pDst[0] = clamp_float(ch[0]);
+        pDst[1] = clamp_float(ch[1]);
+        pSrc += numChan;
+        pDst += 2;
+        numFrames--;
     }
     return true;
 }
diff --git a/media/libeffects/downmix/EffectDownmix.h b/media/libeffects/downmix/EffectDownmix.h
index 679a855..1206520 100644
--- a/media/libeffects/downmix/EffectDownmix.h
+++ b/media/libeffects/downmix/EffectDownmix.h
@@ -18,88 +18,9 @@
 #define ANDROID_EFFECTDOWNMIX_H_
 
 #include <audio_effects/effect_downmix.h>
-#include <audio_utils/primitives.h>
 #include <system/audio.h>
 
-/*------------------------------------
- * definitions
- *------------------------------------
-*/
-
-#define DOWNMIX_OUTPUT_CHANNELS AUDIO_CHANNEL_OUT_STEREO
-#define LVM_FLOAT float
-
-typedef enum {
-    DOWNMIX_STATE_UNINITIALIZED,
-    DOWNMIX_STATE_INITIALIZED,
-    DOWNMIX_STATE_ACTIVE,
-} downmix_state_t;
-
-/* parameters for each downmixer */
-typedef struct {
-    downmix_state_t state;
-    downmix_type_t type;
-    bool apply_volume_correction;
-    uint8_t input_channel_count;
-} downmix_object_t;
-
-
-typedef struct downmix_module_s {
-    const struct effect_interface_s *itfe;
-    effect_config_t config;
-    downmix_object_t context;
-} downmix_module_t;
-
-const uint32_t kSides = AUDIO_CHANNEL_OUT_SIDE_LEFT | AUDIO_CHANNEL_OUT_SIDE_RIGHT;
-const uint32_t kBacks = AUDIO_CHANNEL_OUT_BACK_LEFT | AUDIO_CHANNEL_OUT_BACK_RIGHT;
-const uint32_t kUnsupported =
-        AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER | AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
-        AUDIO_CHANNEL_OUT_TOP_CENTER |
-        AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT |
-        AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER |
-        AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT |
-        AUDIO_CHANNEL_OUT_TOP_BACK_LEFT |
-        AUDIO_CHANNEL_OUT_TOP_BACK_CENTER |
-        AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT;
-
-/*------------------------------------
- * Effect API
- *------------------------------------
-*/
-int32_t DownmixLib_Create(const effect_uuid_t *uuid,
-        int32_t sessionId,
-        int32_t ioId,
-        effect_handle_t *pHandle);
-int32_t DownmixLib_Release(effect_handle_t handle);
-int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid,
-        effect_descriptor_t *pDescriptor);
-
-static int Downmix_Process(effect_handle_t self,
-        audio_buffer_t *inBuffer,
-        audio_buffer_t *outBuffer);
-static int Downmix_Command(effect_handle_t self,
-        uint32_t cmdCode,
-        uint32_t cmdSize,
-        void *pCmdData,
-        uint32_t *replySize,
-        void *pReplyData);
-static int Downmix_GetDescriptor(effect_handle_t self,
-        effect_descriptor_t *pDescriptor);
-
-
-/*------------------------------------
- * internal functions
- *------------------------------------
-*/
-int Downmix_Init(downmix_module_t *pDwmModule);
-int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init);
-int Downmix_Reset(downmix_object_t *pDownmixer, bool init);
-int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue);
-int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue);
-void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
-void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
-void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
-bool Downmix_foldGeneric(
-        uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
+// Use the following declaration to obtain the Downmix library information.
+// extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
 
 #endif /*ANDROID_EFFECTDOWNMIX_H_*/
diff --git a/media/libeffects/downmix/benchmark/Android.bp b/media/libeffects/downmix/benchmark/Android.bp
new file mode 100644
index 0000000..10f14e2
--- /dev/null
+++ b/media/libeffects/downmix/benchmark/Android.bp
@@ -0,0 +1,38 @@
+// Build testbench for downmix module.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_media_libeffects_downmix_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "frameworks_av_media_libeffects_downmix_license",
+    ],
+}
+
+cc_benchmark {
+    name: "downmix_benchmark",
+    host_supported: false,
+    vendor: true,
+    include_dirs: [
+        "frameworks/av/media/libeffects/downmix",
+    ],
+    header_libs: [
+        "libaudioeffects",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    static_libs: [
+        "libaudioutils",
+        "libdownmix",
+    ],
+    srcs: [
+        "downmix_benchmark.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
diff --git a/media/libeffects/downmix/benchmark/downmix_benchmark.cpp b/media/libeffects/downmix/benchmark/downmix_benchmark.cpp
new file mode 100644
index 0000000..ee169c2
--- /dev/null
+++ b/media/libeffects/downmix/benchmark/downmix_benchmark.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright 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.
+ */
+
+#include <random>
+#include <vector>
+
+#include <audio_effects/effect_downmix.h>
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/Statistics.h>
+#include <benchmark/benchmark.h>
+#include <log/log.h>
+#include <system/audio.h>
+
+#include "EffectDownmix.h"
+
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+
+static constexpr audio_channel_mask_t kChannelPositionMasks[] = {
+    AUDIO_CHANNEL_OUT_FRONT_LEFT,
+    AUDIO_CHANNEL_OUT_FRONT_CENTER,
+    AUDIO_CHANNEL_OUT_STEREO,
+    AUDIO_CHANNEL_OUT_2POINT1,
+    AUDIO_CHANNEL_OUT_2POINT0POINT2,
+    AUDIO_CHANNEL_OUT_QUAD,
+    AUDIO_CHANNEL_OUT_QUAD_BACK,
+    AUDIO_CHANNEL_OUT_QUAD_SIDE,
+    AUDIO_CHANNEL_OUT_SURROUND,
+    AUDIO_CHANNEL_OUT_2POINT1POINT2,
+    AUDIO_CHANNEL_OUT_3POINT0POINT2,
+    AUDIO_CHANNEL_OUT_PENTA,
+    AUDIO_CHANNEL_OUT_3POINT1POINT2,
+    AUDIO_CHANNEL_OUT_5POINT1,
+    AUDIO_CHANNEL_OUT_5POINT1_BACK,
+    AUDIO_CHANNEL_OUT_5POINT1_SIDE,
+    AUDIO_CHANNEL_OUT_6POINT1,
+    AUDIO_CHANNEL_OUT_5POINT1POINT2,
+    AUDIO_CHANNEL_OUT_7POINT1,
+    AUDIO_CHANNEL_OUT_5POINT1POINT4,
+    AUDIO_CHANNEL_OUT_7POINT1POINT2,
+    AUDIO_CHANNEL_OUT_7POINT1POINT4,
+    AUDIO_CHANNEL_OUT_13POINT_360RA,
+    AUDIO_CHANNEL_OUT_22POINT2,
+};
+
+static constexpr effect_uuid_t downmix_uuid = {
+    0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
+
+static constexpr size_t kFrameCount = 1000;
+
+/*
+Pixel 3XL
+downmix_benchmark:
+  #BM_Downmix/0     4723 ns    4708 ns       148694
+  #BM_Downmix/1     4717 ns    4702 ns       148873
+  #BM_Downmix/2     4803 ns    4788 ns       145893
+  #BM_Downmix/3     5056 ns    5041 ns       139110
+  #BM_Downmix/4     4710 ns    4696 ns       149625
+  #BM_Downmix/5     1514 ns    1509 ns       463694
+  #BM_Downmix/6     1513 ns    1509 ns       463451
+  #BM_Downmix/7     1516 ns    1511 ns       463899
+  #BM_Downmix/8     4445 ns    4431 ns       157831
+  #BM_Downmix/9     5081 ns    5065 ns       138412
+  #BM_Downmix/10    4354 ns    4341 ns       161247
+  #BM_Downmix/11    4411 ns    4397 ns       158893
+  #BM_Downmix/12    4434 ns    4420 ns       157992
+  #BM_Downmix/13    4845 ns    4830 ns       144873
+  #BM_Downmix/14    4851 ns    4835 ns       144954
+  #BM_Downmix/15    4884 ns    4870 ns       144233
+  #BM_Downmix/16    5832 ns    5813 ns       120565
+  #BM_Downmix/17    5241 ns    5224 ns       133927
+  #BM_Downmix/18    5044 ns    5028 ns       139131
+  #BM_Downmix/19    5244 ns    5227 ns       132315
+  #BM_Downmix/20    5943 ns    5923 ns       117759
+  #BM_Downmix/21    5990 ns    5971 ns       117263
+  #BM_Downmix/22    4468 ns    4454 ns       156689
+  #BM_Downmix/23    7306 ns    7286 ns        95911
+--
+downmix_benchmark: (generic fold)
+  #BM_Downmix/0     4722 ns    4707 ns       149847
+  #BM_Downmix/1     4714 ns    4698 ns       148748
+  #BM_Downmix/2     4794 ns    4779 ns       145661
+  #BM_Downmix/3     5053 ns    5035 ns       139172
+  #BM_Downmix/4     4695 ns    4678 ns       149762
+  #BM_Downmix/5     4381 ns    4368 ns       159675
+  #BM_Downmix/6     4387 ns    4373 ns       160267
+  #BM_Downmix/7     4732 ns    4717 ns       148514
+  #BM_Downmix/8     4430 ns    4415 ns       158133
+  #BM_Downmix/9     5101 ns    5084 ns       138353
+  #BM_Downmix/10    4356 ns    4343 ns       160821
+  #BM_Downmix/11    4397 ns    4383 ns       159995
+  #BM_Downmix/12    4438 ns    4424 ns       158117
+  #BM_Downmix/13    5243 ns    5226 ns       133863
+  #BM_Downmix/14    5259 ns    5242 ns       131855
+  #BM_Downmix/15    5245 ns    5228 ns       133686
+  #BM_Downmix/16    5829 ns    5809 ns       120543
+  #BM_Downmix/17    5245 ns    5228 ns       133533
+  #BM_Downmix/18    5935 ns    5916 ns       118282
+  #BM_Downmix/19    5263 ns    5245 ns       133657
+  #BM_Downmix/20    5998 ns    5978 ns       114693
+  #BM_Downmix/21    5989 ns    5969 ns       117450
+  #BM_Downmix/22    4442 ns    4431 ns       157913
+  #BM_Downmix/23    7309 ns    7290 ns        95797
+*/
+
+static void BM_Downmix(benchmark::State& state) {
+    const audio_channel_mask_t channelMask = kChannelPositionMasks[state.range(0)];
+    const size_t channelCount = audio_channel_count_from_out_mask(channelMask);
+    const int sampleRate = 48000;
+
+    // Initialize input buffer with deterministic pseudo-random values
+    std::minstd_rand gen(channelMask);
+    std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+    std::vector<float> input(kFrameCount * channelCount);
+    std::vector<float> output(kFrameCount * 2);
+    for (auto& in : input) {
+        in = dis(gen);
+    }
+    effect_handle_t effectHandle = nullptr;
+    if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
+            &downmix_uuid, 1, 1, &effectHandle);
+        status != 0) {
+        ALOGE("create_effect returned an error = %d\n", status);
+        return;
+    }
+
+    effect_config_t config{};
+    config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    config.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+    config.inputCfg.bufferProvider.getBuffer = nullptr;
+    config.inputCfg.bufferProvider.releaseBuffer = nullptr;
+    config.inputCfg.bufferProvider.cookie = nullptr;
+    config.inputCfg.mask = EFFECT_CONFIG_ALL;
+
+    config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+    config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+    config.outputCfg.bufferProvider.getBuffer = nullptr;
+    config.outputCfg.bufferProvider.releaseBuffer = nullptr;
+    config.outputCfg.bufferProvider.cookie = nullptr;
+    config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+    config.inputCfg.samplingRate = sampleRate;
+    config.inputCfg.channels = channelMask;
+
+    config.outputCfg.samplingRate = sampleRate;
+    config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; // output always stereo
+
+    int reply = 0;
+    uint32_t replySize = sizeof(reply);
+    if (int status = (*effectHandle)
+            ->command(effectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
+                    &config, &replySize, &reply);
+        status != 0) {
+        ALOGE("command returned an error = %d\n", status);
+        return;
+    }
+
+    if (int status = (*effectHandle)
+            ->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
+        status != 0) {
+        ALOGE("Command enable call returned error %d\n", reply);
+        return;
+    }
+
+    // Run the test
+    for (auto _ : state) {
+        benchmark::DoNotOptimize(input.data());
+        benchmark::DoNotOptimize(output.data());
+
+        audio_buffer_t inBuffer = {.frameCount = kFrameCount, .f32 = input.data()};
+        audio_buffer_t outBuffer = {.frameCount = kFrameCount, .f32 = output.data()};
+        (*effectHandle)->process(effectHandle, &inBuffer, &outBuffer);
+
+        benchmark::ClobberMemory();
+    }
+
+    state.SetComplexityN(state.range(0));
+
+    if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
+        ALOGE("release_effect returned an error = %d\n", status);
+        return;
+    }
+}
+
+static void DownmixArgs(benchmark::internal::Benchmark* b) {
+    for (int i = 0; i < (int)std::size(kChannelPositionMasks); i++) {
+        b->Args({i});
+    }
+}
+
+BENCHMARK(BM_Downmix)->Apply(DownmixArgs);
+
+BENCHMARK_MAIN();
diff --git a/media/libeffects/downmix/tests/Android.bp b/media/libeffects/downmix/tests/Android.bp
index 4077312..4940117 100644
--- a/media/libeffects/downmix/tests/Android.bp
+++ b/media/libeffects/downmix/tests/Android.bp
@@ -10,6 +10,43 @@
     ],
 }
 
+// This is a gtest unit test.
+//
+// Use "atest downmix_tests" to run.
+cc_test {
+    name:"downmix_tests",
+    gtest: true,
+    host_supported: true,
+    vendor: true,
+    include_dirs: [
+        "frameworks/av/media/libeffects/downmix",
+    ],
+    header_libs: [
+        "libaudioeffects",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    static_libs: [
+        "libaudioutils",
+        "libdownmix",
+    ],
+    srcs: [
+        "downmix_tests.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
+
+// This is a test application which generates downmixed files for regression
+// analysis.
+//
+// See build_and_run_all_unit_tests.sh for a test script that uses this
+// test application and outputs then compares files in a local directory
+// on device (/data/local/tmp/downmixtest/).
 cc_test {
     name:"downmixtest",
     host_supported: false,
diff --git a/media/libeffects/downmix/tests/downmix_tests.cpp b/media/libeffects/downmix/tests/downmix_tests.cpp
new file mode 100644
index 0000000..d4b7a3a
--- /dev/null
+++ b/media/libeffects/downmix/tests/downmix_tests.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+#include <vector>
+
+#include "EffectDownmix.h"
+
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/Statistics.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+static constexpr audio_channel_mask_t kChannelPositionMasks[] = {
+    AUDIO_CHANNEL_OUT_FRONT_LEFT, // Legacy: the downmix effect treats MONO as FRONT_LEFT only.
+                                  // The AudioMixer interprets MONO as a special case requiring
+                                  // channel replication, bypassing the downmix effect.
+    AUDIO_CHANNEL_OUT_FRONT_CENTER,
+    AUDIO_CHANNEL_OUT_STEREO,
+    AUDIO_CHANNEL_OUT_2POINT1,
+    AUDIO_CHANNEL_OUT_2POINT0POINT2,
+    AUDIO_CHANNEL_OUT_QUAD,
+    AUDIO_CHANNEL_OUT_QUAD_BACK,
+    AUDIO_CHANNEL_OUT_QUAD_SIDE,
+    AUDIO_CHANNEL_OUT_SURROUND,
+    AUDIO_CHANNEL_OUT_2POINT1POINT2,
+    AUDIO_CHANNEL_OUT_3POINT0POINT2,
+    AUDIO_CHANNEL_OUT_PENTA,
+    AUDIO_CHANNEL_OUT_3POINT1POINT2,
+    AUDIO_CHANNEL_OUT_5POINT1,
+    AUDIO_CHANNEL_OUT_5POINT1_BACK,
+    AUDIO_CHANNEL_OUT_5POINT1_SIDE,
+    AUDIO_CHANNEL_OUT_6POINT1,
+    AUDIO_CHANNEL_OUT_5POINT1POINT2,
+    AUDIO_CHANNEL_OUT_7POINT1,
+    AUDIO_CHANNEL_OUT_5POINT1POINT4,
+    AUDIO_CHANNEL_OUT_7POINT1POINT2,
+    AUDIO_CHANNEL_OUT_7POINT1POINT4,
+    AUDIO_CHANNEL_OUT_13POINT_360RA,
+    AUDIO_CHANNEL_OUT_22POINT2,
+};
+
+static constexpr audio_channel_mask_t kConsideredChannels =
+    (audio_channel_mask_t)(AUDIO_CHANNEL_OUT_7POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER);
+
+// Downmix doesn't change with sample rate
+static constexpr size_t kSampleRates[] = {
+    48000,
+};
+
+// Our near expectation is 16x the bit that doesn't fit the mantissa.
+// this works so long as we add values close in exponent with each other
+// realizing that errors accumulate as the sqrt of N (random walk, lln, etc).
+#define EXPECT_NEAR_EPSILON(e, v) EXPECT_NEAR((e), (v), \
+        abs((e) * std::numeric_limits<std::decay_t<decltype(e)>>::epsilon() * 8))
+
+template<typename T>
+static auto channelStatistics(const std::vector<T>& input, size_t channels) {
+    std::vector<android::audio_utils::Statistics<T>> result(channels);
+    const size_t frames = input.size() / channels;
+    if (frames > 0) {
+        const float *fptr = input.data();
+        for (size_t i = 0; i < frames; ++i) {
+            for (size_t j = 0; j < channels; ++j) {
+                result[j].add(*fptr++);
+            }
+        }
+    }
+    return result;
+}
+
+using DownmixParam = std::tuple<int /* sample rate */,  int /* channel mask */>;
+class DownmixTest : public ::testing::TestWithParam<DownmixParam> {
+public:
+    static constexpr effect_uuid_t downmix_uuid_ = {
+        0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
+    static constexpr size_t FRAME_LENGTH = 256;
+
+    void testBalance(int sampleRate, audio_channel_mask_t channelMask) {
+        using namespace ::android::audio_utils::channels;
+
+        size_t frames = 100;
+        unsigned outChannels = 2;
+        unsigned inChannels = audio_channel_count_from_out_mask(channelMask);
+        std::vector<float> input(frames * inChannels);
+        std::vector<float> output(frames * outChannels);
+
+        double savedPower[32][2]{};
+        for (unsigned i = 0, channel = channelMask; channel != 0; ++i) {
+            const int index = __builtin_ctz(channel);
+            ASSERT_LT(index, FCC_24);
+            const int pairIndex = pairIdxFromChannelIdx(index);
+            const AUDIO_GEOMETRY_SIDE side = sideFromChannelIdx(index);
+            const int channelBit = 1 << index;
+            channel &= ~channelBit;
+
+            // Generate a +1, -1 alternating stream in one channel, which has variance 1.
+            auto indata = input.data();
+            for (unsigned j = 0; j < frames; ++j) {
+                for (unsigned k = 0; k < inChannels; ++k) {
+                    *indata++ = (k == i) ? (j & 1 ? -1 : 1) : 0;
+                }
+            }
+            run(sampleRate, channelMask, input, output, frames);
+
+            auto stats = channelStatistics(output, 2 /* channels */);
+            // printf("power: %s %s\n", stats[0].toString().c_str(), stats[1].toString().c_str());
+            double power[2] = { stats[0].getVariance(), stats[1].getVariance() };
+
+            // Check symmetric power for pair channels on exchange of left/right position.
+            // to do this, we save previous power measurements.
+            if (pairIndex >= 0 && pairIndex < index) {
+                EXPECT_NEAR_EPSILON(power[0], savedPower[pairIndex][1]);
+                EXPECT_NEAR_EPSILON(power[1], savedPower[pairIndex][0]);
+            }
+            savedPower[index][0] = power[0];
+            savedPower[index][1] = power[1];
+
+            // Confirm exactly the mix amount prescribed by the existing downmix effect.
+            // For future changes to the downmix effect, the nearness needs to be relaxed
+            // to compare behavior S or earlier.
+            if ((channelBit & kConsideredChannels) == 0) {
+                // for channels not considered, expect 0 power for legacy downmix
+                EXPECT_EQ(0.f, power[0]);
+                EXPECT_EQ(0.f, power[1]);
+                continue;
+            }
+            constexpr float POWER_TOLERANCE = 0.01;  // for variance sum error.
+            switch (side) {
+            case AUDIO_GEOMETRY_SIDE_LEFT:
+                EXPECT_NEAR(0.25f, power[0], POWER_TOLERANCE);
+                EXPECT_EQ(0.f, power[1]);
+                break;
+            case AUDIO_GEOMETRY_SIDE_RIGHT:
+                EXPECT_EQ(0.f, power[0]);
+                EXPECT_NEAR(0.25f, power[1], POWER_TOLERANCE);
+                break;
+            case AUDIO_GEOMETRY_SIDE_CENTER:
+                EXPECT_NEAR(0.125f, power[0], POWER_TOLERANCE);
+                EXPECT_NEAR(0.125f, power[1], POWER_TOLERANCE);
+                EXPECT_NEAR_EPSILON(power[0], power[1]);
+                break;
+            }
+        }
+    }
+
+    void run(int sampleRate, audio_channel_mask_t channelMask,
+            std::vector<float>& input, std::vector<float>& output, size_t frames) {
+        reconfig(sampleRate, channelMask);
+
+        ASSERT_EQ(frames * inputChannelCount_, input.size());
+        ASSERT_EQ(frames * outputChannelCount_, output.size());
+
+        const int32_t sessionId = 0;
+        const int32_t ioId = 0;
+        int32_t err = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
+                &downmix_uuid_, sessionId, ioId,  &handle_);
+        ASSERT_EQ(0, err);
+
+        const struct effect_interface_s * const downmixApi = *handle_;
+        int32_t reply = 0;
+        uint32_t replySize = (uint32_t)sizeof(reply);
+        err = (downmixApi->command)(
+                handle_, EFFECT_CMD_SET_CONFIG,
+                sizeof(effect_config_t), &config_, &replySize, &reply);
+        ASSERT_EQ(0, err);
+        err = (downmixApi->command)(
+                handle_, EFFECT_CMD_ENABLE,
+                0, nullptr, &replySize, &reply);
+        ASSERT_EQ(0, err);
+
+        process(input, output, frames);
+        err = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(handle_);
+        ASSERT_EQ(0, err);
+    }
+
+private:
+    void reconfig(int sampleRate, audio_channel_mask_t channelMask) {
+        config_.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+        config_.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+        config_.inputCfg.bufferProvider.getBuffer = nullptr;
+        config_.inputCfg.bufferProvider.releaseBuffer = nullptr;
+        config_.inputCfg.bufferProvider.cookie = nullptr;
+        config_.inputCfg.mask = EFFECT_CONFIG_ALL;
+
+        config_.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+        config_.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+        config_.outputCfg.bufferProvider.getBuffer = nullptr;
+        config_.outputCfg.bufferProvider.releaseBuffer = nullptr;
+        config_.outputCfg.bufferProvider.cookie = nullptr;
+        config_.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+        config_.inputCfg.samplingRate = sampleRate;
+        config_.inputCfg.channels = channelMask;
+        inputChannelCount_ = audio_channel_count_from_out_mask(config_.inputCfg.channels);
+
+        config_.outputCfg.samplingRate = sampleRate;
+        config_.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; // output always stereo
+        outputChannelCount_ = audio_channel_count_from_out_mask(config_.outputCfg.channels);
+    }
+
+    void process(std::vector<float> &input, std::vector<float> &output, size_t frames) const {
+        const struct effect_interface_s * const downmixApi = *handle_;
+
+        for (size_t pos = 0; pos < frames;) {
+            const size_t transfer = std::min(frames - pos, FRAME_LENGTH);
+            audio_buffer_t inbuffer{.frameCount = transfer,
+                .f32 = input.data() + pos * inputChannelCount_};
+            audio_buffer_t outbuffer{.frameCount = transfer,
+                .f32 = output.data() + pos * outputChannelCount_};
+            const int32_t err = (downmixApi->process)(handle_, &inbuffer, &outbuffer);
+            ASSERT_EQ(0, err);
+            pos += transfer;
+        }
+    }
+
+    effect_handle_t handle_{};
+    effect_config_t config_{};
+    int outputChannelCount_{};
+    int inputChannelCount_{};
+};
+
+TEST_P(DownmixTest, basic) {
+    testBalance(kSampleRates[std::get<0>(GetParam())],
+            kChannelPositionMasks[std::get<1>(GetParam())]);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DownmixTestAll, DownmixTest,
+        ::testing::Combine(
+                ::testing::Range(0, (int)std::size(kSampleRates)),
+                ::testing::Range(0, (int)std::size(kChannelPositionMasks))
+                ));
+
+int main(int argc, /* const */ char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/media/libeffects/downmix/tests/downmixtest.cpp b/media/libeffects/downmix/tests/downmixtest.cpp
index 71f83e5..4076320 100644
--- a/media/libeffects/downmix/tests/downmixtest.cpp
+++ b/media/libeffects/downmix/tests/downmixtest.cpp
@@ -29,7 +29,6 @@
 #define MAX_NUM_CHANNELS 8
 
 struct downmix_cntxt_s {
-  effect_descriptor_t desc;
   effect_handle_t handle;
   effect_config_t config;
 
@@ -87,13 +86,12 @@
 }
 
 int32_t DownmixConfiureAndEnable(downmix_cntxt_s *pDescriptor) {
-  effect_handle_t *effectHandle = &pDescriptor->handle;
-  downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
-  const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
+  effect_handle_t effectHandle = pDescriptor->handle;
+  const struct effect_interface_s *Downmix_api = *effectHandle;
   int32_t err = 0;
   uint32_t replySize = (uint32_t)sizeof(err);
 
-  err = (Downmix_api->command)(*effectHandle, EFFECT_CMD_SET_CONFIG,
+  err = (Downmix_api->command)(effectHandle, EFFECT_CMD_SET_CONFIG,
                                sizeof(effect_config_t), &(pDescriptor->config),
                                &replySize, &err);
   if (err != 0) {
@@ -101,7 +99,7 @@
     return err;
   }
 
-  err = ((Downmix_api->command))(*effectHandle, EFFECT_CMD_ENABLE, 0, nullptr,
+  err = ((Downmix_api->command))(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr,
                                  &replySize, &err);
   if (err != 0) {
     ALOGE("Downmix command to enable effect returned an error %d", err);
@@ -112,9 +110,8 @@
 
 int32_t DownmixExecute(downmix_cntxt_s *pDescriptor, FILE *finp,
                        FILE *fout) {
-  effect_handle_t *effectHandle = &pDescriptor->handle;
-  downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
-  const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
+  effect_handle_t effectHandle = pDescriptor->handle;
+  const struct effect_interface_s *Downmix_api = *effectHandle;
 
   const int numFileChannels = pDescriptor->numFileChannels;
   const int numProcessChannels = pDescriptor->numProcessChannels;
@@ -150,7 +147,7 @@
     memcpy_to_float_from_i16(inFloat.data(), inS16.data(),
                              FRAME_LENGTH * numProcessChannels);
 
-    const int32_t err = (Downmix_api->process)(*effectHandle, pinbuf, poutbuf);
+    const int32_t err = (Downmix_api->process)(effectHandle, pinbuf, poutbuf);
     if (err != 0) {
       ALOGE("DownmixProcess returned an error %d", err);
       return -1;
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index f838892..1551e33 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -157,7 +157,7 @@
     if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
     const uint32_t channelCount = audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
 #ifdef SUPPORT_MC
-    if (channelCount < 1 || channelCount > FCC_8) return -EINVAL;
+    if (channelCount < 1 || channelCount > FCC_LIMIT) return -EINVAL;
 #else
     if (channelCount != FCC_2) return -EINVAL;
 #endif
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index e471c7b..e98d7d8 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -365,7 +365,7 @@
         "libaudioclient",
         "libmedia_codeclist",
         "libmedia_omx",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     export_shared_lib_headers: [
@@ -374,17 +374,17 @@
         "libandroidicu",
         //"libsonivox",
         "libmedia_omx",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     static_libs: [
         "resourcemanager_aidl_interface-ndk_platform",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     export_static_lib_headers: [
         "resourcemanager_aidl_interface-ndk_platform",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     export_include_dirs: [
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 0f189ee..07c0ac5 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -35,7 +35,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 enum {
     CREATE = IBinder::FIRST_CALL_TRANSACTION,
@@ -65,22 +65,22 @@
 
     virtual sp<IMediaPlayer> create(
             const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId,
-            const Identity& identity) {
+            const AttributionSourceState& attributionSource) {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
         data.writeStrongBinder(IInterface::asBinder(client));
         data.writeInt32(audioSessionId);
-        data.writeParcelable(identity);
+        data.writeParcelable(attributionSource);
 
         remote()->transact(CREATE, data, &reply);
         return interface_cast<IMediaPlayer>(reply.readStrongBinder());
     }
 
-    virtual sp<IMediaRecorder> createMediaRecorder(const Identity& identity)
+    virtual sp<IMediaRecorder> createMediaRecorder(const AttributionSourceState& attributionSource)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        data.writeParcelable(identity);
+        data.writeParcelable(attributionSource);
         remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
         return interface_cast<IMediaRecorder>(reply.readStrongBinder());
     }
@@ -131,23 +131,23 @@
             sp<IMediaPlayerClient> client =
                 interface_cast<IMediaPlayerClient>(data.readStrongBinder());
             audio_session_t audioSessionId = (audio_session_t) data.readInt32();
-            Identity identity;
-            status_t status = data.readParcelable(&identity);
+            AttributionSourceState attributionSource;
+            status_t status = data.readParcelable(&attributionSource);
             if (status != NO_ERROR) {
                 return status;
             }
-            sp<IMediaPlayer> player = create(client, audioSessionId, identity);
+            sp<IMediaPlayer> player = create(client, audioSessionId, attributionSource);
             reply->writeStrongBinder(IInterface::asBinder(player));
             return NO_ERROR;
         } break;
         case CREATE_MEDIA_RECORDER: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            Identity identity;
-            status_t status = data.readParcelable(&identity);
+            AttributionSourceState attributionSource;
+            status_t status = data.readParcelable(&attributionSource);
             if (status != NO_ERROR) {
                 return status;
             }
-            sp<IMediaRecorder> recorder = createMediaRecorder(identity);
+            sp<IMediaRecorder> recorder = createMediaRecorder(attributionSource);
             reply->writeStrongBinder(IInterface::asBinder(recorder));
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/include/media/IMediaPlayerService.h b/media/libmedia/include/media/IMediaPlayerService.h
index 243e9c7..6070673 100644
--- a/media/libmedia/include/media/IMediaPlayerService.h
+++ b/media/libmedia/include/media/IMediaPlayerService.h
@@ -27,7 +27,7 @@
 
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaMetadataRetriever.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <string>
 
@@ -48,12 +48,12 @@
     DECLARE_META_INTERFACE(MediaPlayerService);
 
     virtual sp<IMediaRecorder> createMediaRecorder(
-        const android::media::permission::Identity &identity) = 0;
+        const android::content::AttributionSourceState &attributionSource) = 0;
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
     virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client,
             audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE,
-            const android::media::permission::Identity& identity =
-                android::media::permission::Identity()) = 0;
+            const android::content::AttributionSourceState &attributionSource =
+                android::content::AttributionSourceState()) = 0;
     virtual sp<IMediaCodecList> getCodecList() const = 0;
 
     // Connects to a remote display.
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index b5325ce..2b7818d 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -21,7 +21,7 @@
 #include <media/AudioSystem.h>
 #include <media/MicrophoneInfo.h>
 #include <media/mediarecorder.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <system/audio.h>
 
@@ -34,8 +34,8 @@
 struct PersistentSurface;
 
 struct MediaRecorderBase {
-    explicit MediaRecorderBase(const media::permission::Identity &client)
-        : mClient(client) {}
+    explicit MediaRecorderBase(const android::content::AttributionSourceState &attributionSource)
+        : mAttributionSource(attributionSource) {}
     virtual ~MediaRecorderBase() {}
 
     virtual status_t init() = 0;
@@ -84,7 +84,7 @@
 
 protected:
 
-    media::permission::Identity mClient;
+    android::content::AttributionSourceState mAttributionSource;
 
 private:
     MediaRecorderBase(const MediaRecorderBase &);
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index fbba398..de4c7db 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -29,7 +29,7 @@
 #include <media/IMediaPlayer.h>
 #include <media/IMediaDeathNotifier.h>
 #include <media/IStreamSource.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
@@ -212,8 +212,8 @@
                     public virtual IMediaDeathNotifier
 {
 public:
-    explicit MediaPlayer(const android::media::permission::Identity& mIdentity =
-        android::media::permission::Identity());
+    explicit MediaPlayer(const android::content::AttributionSourceState& mAttributionSource =
+        android::content::AttributionSourceState());
     ~MediaPlayer();
             void            died();
             void            disconnect();
@@ -317,7 +317,7 @@
     float                       mSendLevel;
     struct sockaddr_in          mRetransmitEndpoint;
     bool                        mRetransmitEndpointValid;
-    const android::media::permission::Identity mIdentity;
+    const android::content::AttributionSourceState mAttributionSource;
 };
 
 }; // namespace android
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 96a3293..d54ff32 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -25,7 +25,7 @@
 #include <media/IMediaRecorderClient.h>
 #include <media/IMediaDeathNotifier.h>
 #include <media/MicrophoneInfo.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 namespace android {
 
@@ -227,7 +227,7 @@
                       public virtual IMediaDeathNotifier
 {
 public:
-    explicit MediaRecorder(const media::permission::Identity& identity);
+    explicit MediaRecorder(const android::content::AttributionSourceState& attributionSource);
     ~MediaRecorder();
 
     void        died();
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 7504787..1c9b9e4 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -40,9 +40,10 @@
 namespace android {
 
 using media::VolumeShaper;
-using media::permission::Identity;
+using content::AttributionSourceState;
 
-MediaPlayer::MediaPlayer(const Identity& identity) : mIdentity(identity)
+MediaPlayer::MediaPlayer(const AttributionSourceState& attributionSource)
+        : mAttributionSource(attributionSource)
 {
     ALOGV("constructor");
     mListener = NULL;
@@ -153,7 +154,7 @@
     if (url != NULL) {
         const sp<IMediaPlayerService> service(getMediaPlayerService());
         if (service != 0) {
-            sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
+            sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mAttributionSource));
             if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                 (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                 player.clear();
@@ -170,7 +171,7 @@
     status_t err = UNKNOWN_ERROR;
     const sp<IMediaPlayerService> service(getMediaPlayerService());
     if (service != 0) {
-        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
+        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mAttributionSource));
         if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
             (NO_ERROR != player->setDataSource(fd, offset, length))) {
             player.clear();
@@ -186,7 +187,7 @@
     status_t err = UNKNOWN_ERROR;
     const sp<IMediaPlayerService> service(getMediaPlayerService());
     if (service != 0) {
-        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
+        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mAttributionSource));
         if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
             (NO_ERROR != player->setDataSource(source))) {
             player.clear();
@@ -202,7 +203,7 @@
     status_t err = UNKNOWN_ERROR;
     const sp<IMediaPlayerService> service(getMediaPlayerService());
     if (service != 0) {
-        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
+        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mAttributionSource));
         if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
             (NO_ERROR != player->setDataSource(rtpParams))) {
             player.clear();
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index da2b190..cf12c36 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -33,7 +33,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 status_t MediaRecorder::setCamera(const sp<hardware::ICamera>& camera,
         const sp<ICameraRecordingProxy>& proxy)
@@ -760,13 +760,14 @@
     return INVALID_OPERATION;
 }
 
-MediaRecorder::MediaRecorder(const Identity &identity) : mSurfaceMediaSource(NULL)
+MediaRecorder::MediaRecorder(const AttributionSourceState &attributionSource)
+        : mSurfaceMediaSource(NULL)
 {
     ALOGV("constructor");
 
     const sp<IMediaPlayerService> service(getMediaPlayerService());
     if (service != NULL) {
-        mMediaRecorder = service->createMediaRecorder(identity);
+        mMediaRecorder = service->createMediaRecorder(attributionSource);
     }
     if (mMediaRecorder != NULL) {
         mCurrentState = MEDIA_RECORDER_IDLE;
diff --git a/media/libmediaformatshaper/CodecSeeding.cpp b/media/libmediaformatshaper/CodecSeeding.cpp
index cc241f4..d2ad7ac 100644
--- a/media/libmediaformatshaper/CodecSeeding.cpp
+++ b/media/libmediaformatshaper/CodecSeeding.cpp
@@ -53,6 +53,7 @@
       {true, "vq-target-bpp-720p", "2.25"},
       {true, "vq-target-bpp-540p", "2.65"},
       {true, "vq-target-bpp-480p", "3.00"},
+      {true, "vq-target-bpp-320x240", "0"},
       {true, "vq-target-qpmax", "-1"},
       {true, "vq-target-qpmax-1080p", "45"},
       {true, "vq-target-qpmax-720p", "43"},
@@ -69,6 +70,7 @@
       {true, "vq-target-bpp-720p", "1.80"},
       {true, "vq-target-bpp-540p", "2.10"},
       {true, "vq-target-bpp-480p", "2.30"},
+      {true, "vq-target-bpp-320x240", "0"},
       {true, "vq-target-qpmax", "-1"},
       {true, "vq-target-qpmax-1080p", "45"},
       {true, "vq-target-qpmax-720p", "44"},
diff --git a/media/libmediaformatshaper/VQApply.cpp b/media/libmediaformatshaper/VQApply.cpp
index 585ec6c..694182d 100644
--- a/media/libmediaformatshaper/VQApply.cpp
+++ b/media/libmediaformatshaper/VQApply.cpp
@@ -63,13 +63,36 @@
         return 0;
     }
 
+    // only proceed if we're in the handheld category.
+    // We embed this information within the codec record when we build up features
+    // and pass them in from MediaCodec; it's the easiest place to store it
+    //
+    // TODO: make a #define for ' _vq_eligible.device' here and in MediaCodec.cpp
+    //
+    int32_t isVQEligible = 0;
+    (void) codec->getFeatureValue("_vq_eligible.device", &isVQEligible);
+    ALOGD("minquality:  are we eligible: %d", isVQEligible);
+    if (!isVQEligible) {
+        ALOGD("minquality: not an eligible device class");
+        return 0;
+    }
+
     if (codec->supportedMinimumQuality() > 0) {
         // allow the codec provided minimum quality behavior to work at it
         ALOGD("minquality: codec claims to implement minquality=%d",
               codec->supportedMinimumQuality());
+
+        // tell the underlying codec to do its thing; we won't try to second guess.
+        // default to 1, aka S_HANDHELD;
+        int32_t qualityTarget = 1;
+        (void) codec->getFeatureValue("_quality.target", &qualityTarget);
+        AMediaFormat_setInt32(inFormat, "android._encoding-quality-level", qualityTarget);
         return 0;
     }
 
+    // let the codec know that we'll be enforcing the minimum quality standards
+    AMediaFormat_setInt32(inFormat, "android._encoding-quality-level", 0);
+
     //
     // consider any and all tools available
     // -- qp
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index a8350ea..d597a4d 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -308,6 +308,17 @@
     switch (uid) {
     case AID_RADIO:     // telephony subsystem, RIL
         return false;
+    default:
+        // Some isolated processes can access the audio system; see
+        // AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead
+        // of also allowing access to the MediaMetrics service, it's simpler to just disable it for
+        // now.
+        // TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or
+        // make this disabling specific to that process.
+        if (uid >= AID_ISOLATED_START && uid <= AID_ISOLATED_END) {
+            return false;
+        }
+        break;
     }
 
     int enabled = property_get_int32(Item::EnabledProperty, -1);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 287317d..f55678d 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -35,7 +35,7 @@
         "android.hardware.media.c2@1.0",
         "android.hardware.media.omx@1.0",
         "av-types-aidl-cpp",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
         "libbase",
         "libactivitymanager_aidl",
@@ -76,12 +76,12 @@
         "libstagefright_nuplayer",
         "libstagefright_rtsp",
         "libstagefright_timedtext",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     export_shared_lib_headers: [
         "libmedia",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     include_dirs: [
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index dc4aea5..d278a01 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -95,7 +95,7 @@
 using android::NOT_ENOUGH_DATA;
 using android::Parcel;
 using android::media::VolumeShaper;
-using android::media::permission::Identity;
+using android::content::AttributionSourceState;
 
 // Max number of entries in the filter.
 const int kMaxFilterSize = 64;  // I pulled that out of thin air.
@@ -455,21 +455,22 @@
     ALOGV("MediaPlayerService destroyed");
 }
 
-sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(const Identity& identity)
+sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(
+        const AttributionSourceState& attributionSource)
 {
-    // TODO b/182392769: use identity util
-    Identity verifiedIdentity = identity;
-    verifiedIdentity.uid = VALUE_OR_FATAL(
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState verifiedAttributionSource = attributionSource;
+    verifiedAttributionSource.uid = VALUE_OR_FATAL(
       legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
-    verifiedIdentity.pid = VALUE_OR_FATAL(
+    verifiedAttributionSource.pid = VALUE_OR_FATAL(
         legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
     sp<MediaRecorderClient> recorder =
-        new MediaRecorderClient(this, verifiedIdentity);
+        new MediaRecorderClient(this, verifiedAttributionSource);
     wp<MediaRecorderClient> w = recorder;
     Mutex::Autolock lock(mLock);
     mMediaRecorderClients.add(w);
     ALOGV("Create new media recorder client from pid %s",
-        verifiedIdentity.toString().c_str());
+        verifiedAttributionSource.toString().c_str());
     return recorder;
 }
 
@@ -489,21 +490,21 @@
 }
 
 sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
-        audio_session_t audioSessionId, const Identity& identity)
+        audio_session_t audioSessionId, const AttributionSourceState& attributionSource)
 {
     int32_t connId = android_atomic_inc(&mNextConnId);
-    // TODO b/182392769: use identity util
-    Identity verifiedIdentity = identity;
-    verifiedIdentity.pid = VALUE_OR_FATAL(
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState verifiedAttributionSource = attributionSource;
+    verifiedAttributionSource.pid = VALUE_OR_FATAL(
         legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
-    verifiedIdentity.uid = VALUE_OR_FATAL(
+    verifiedAttributionSource.uid = VALUE_OR_FATAL(
         legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
 
     sp<Client> c = new Client(
-            this, verifiedIdentity, connId, client, audioSessionId);
+            this, verifiedAttributionSource, connId, client, audioSessionId);
 
     ALOGV("Create new client(%d) from %s, ", connId,
-        verifiedIdentity.toString().c_str());
+        verifiedAttributionSource.toString().c_str());
 
     wp<Client> w = c;
     {
@@ -556,8 +557,8 @@
     char buffer[SIZE];
     String8 result;
     result.append(" Client\n");
-    snprintf(buffer, 255, "  Identity(%s), connId(%d), status(%d), looping(%s)\n",
-        mIdentity.toString().c_str(), mConnId, mStatus, mLoop?"true": "false");
+    snprintf(buffer, 255, "  AttributionSource(%s), connId(%d), status(%d), looping(%s)\n",
+        mAttributionSource.toString().c_str(), mConnId, mStatus, mLoop?"true": "false");
     result.append(buffer);
 
     sp<MediaPlayerBase> p;
@@ -621,7 +622,8 @@
             for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
                 sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
                 if (c != 0) {
-                    snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mIdentity.pid);
+                    snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n",
+                            c->mAttributionSource.pid);
                     result.append(buffer);
                     write(fd, result.string(), result.size());
                     result = "\n";
@@ -744,10 +746,10 @@
 }
 
 MediaPlayerService::Client::Client(
-        const sp<MediaPlayerService>& service, const Identity& identity,
+        const sp<MediaPlayerService>& service, const AttributionSourceState& attributionSource,
         int32_t connId, const sp<IMediaPlayerClient>& client,
         audio_session_t audioSessionId)
-        : mIdentity(identity)
+        : mAttributionSource(attributionSource)
 {
     ALOGV("Client(%d) constructor", connId);
     mConnId = connId;
@@ -768,7 +770,8 @@
 
 MediaPlayerService::Client::~Client()
 {
-    ALOGV("Client(%d) destructor identity = %s", mConnId, mIdentity.toString().c_str());
+    ALOGV("Client(%d) destructor AttributionSource = %s", mConnId,
+            mAttributionSource.toString().c_str());
     mAudioOutput.clear();
     wp<Client> client(this);
     disconnect();
@@ -781,7 +784,8 @@
 
 void MediaPlayerService::Client::disconnect()
 {
-    ALOGV("disconnect(%d) from identity %s", mConnId, mIdentity.toString().c_str());
+    ALOGV("disconnect(%d) from AttributionSource %s", mConnId,
+            mAttributionSource.toString().c_str());
     // grab local reference and clear main reference to prevent future
     // access to object
     sp<MediaPlayerBase> p;
@@ -822,11 +826,11 @@
     }
     if (p == NULL) {
         p = MediaPlayerFactory::createPlayer(playerType, mListener,
-            VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mIdentity.pid)));
+            VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAttributionSource.pid)));
     }
 
     if (p != NULL) {
-        p->setUID(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mIdentity.uid)));
+        p->setUID(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAttributionSource.uid)));
     }
 
     return p;
@@ -934,7 +938,7 @@
     mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
 
     if (!p->hardwareOutput()) {
-        mAudioOutput = new AudioOutput(mAudioSessionId, mIdentity,
+        mAudioOutput = new AudioOutput(mAudioSessionId, mAttributionSource,
                 mAudioAttributes, mAudioDeviceUpdatedListener);
         static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
     }
@@ -1784,8 +1788,9 @@
 
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
-MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, const Identity& identity,
-        const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
+MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId,
+        const AttributionSourceState& attributionSource, const audio_attributes_t* attr,
+        const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
     : mCallback(NULL),
       mCallbackCookie(NULL),
       mCallbackData(NULL),
@@ -1797,7 +1802,7 @@
       mMsecsPerFrame(0),
       mFrameSize(0),
       mSessionId(sessionId),
-      mIdentity(identity),
+      mAttributionSource(attributionSource),
       mSendLevel(0.0),
       mAuxEffectId(0),
       mFlags(AUDIO_OUTPUT_FLAG_NONE),
@@ -2193,7 +2198,7 @@
                     mSessionId,
                     AudioTrack::TRANSFER_CALLBACK,
                     offloadInfo,
-                    mIdentity,
+                    mAttributionSource,
                     mAttributes,
                     doNotReconnect,
                     1.0f,  // default value for maxRequiredSpeed
@@ -2220,7 +2225,7 @@
                     mSessionId,
                     AudioTrack::TRANSFER_DEFAULT,
                     NULL, // offload info
-                    mIdentity,
+                    mAttributionSource,
                     mAttributes,
                     doNotReconnect,
                     targetSpeed,
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 35a65d3..98091be 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -33,12 +33,14 @@
 #include <media/MediaPlayerInterface.h>
 #include <media/Metadata.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <system/audio.h>
 
 namespace android {
 
+using content::AttributionSourceState;
+
 class AudioTrack;
 struct AVSyncSettings;
 class DeathNotifier;
@@ -80,7 +82,7 @@
      public:
                                 AudioOutput(
                                         audio_session_t sessionId,
-                                        const media::permission::Identity& identity,
+                                        const AttributionSourceState& attributionSource,
                                         const audio_attributes_t * attr,
                                         const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
         virtual                 ~AudioOutput();
@@ -169,7 +171,7 @@
         float                   mMsecsPerFrame;
         size_t                  mFrameSize;
         audio_session_t         mSessionId;
-        media::permission::Identity mIdentity;
+        AttributionSourceState  mAttributionSource;
         float                   mSendLevel;
         int                     mAuxEffectId;
         audio_output_flags_t    mFlags;
@@ -231,13 +233,13 @@
     static  void                instantiate();
 
     // IMediaPlayerService interface
-    virtual sp<IMediaRecorder>  createMediaRecorder(const media::permission::Identity &identity);
+    virtual sp<IMediaRecorder> createMediaRecorder(const AttributionSourceState &attributionSource);
     void    removeMediaRecorderClient(const wp<MediaRecorderClient>& client);
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever();
 
     virtual sp<IMediaPlayer>    create(const sp<IMediaPlayerClient>& client,
                                        audio_session_t audioSessionId,
-                                       const media::permission::Identity& identity);
+                                       const AttributionSourceState& attributionSource);
 
     virtual sp<IMediaCodecList> getCodecList() const;
 
@@ -380,7 +382,7 @@
                 void            notify(int msg, int ext1, int ext2, const Parcel *obj);
 
                 pid_t           pid() const {
-                    return VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mIdentity.pid));
+                    return VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAttributionSource.pid));
                 }
         virtual status_t        dump(int fd, const Vector<String16>& args);
 
@@ -411,7 +413,7 @@
 
         friend class MediaPlayerService;
                                 Client( const sp<MediaPlayerService>& service,
-                                        const media::permission::Identity& identity,
+                                        const AttributionSourceState& attributionSource,
                                         int32_t connId,
                                         const sp<IMediaPlayerClient>& client,
                                         audio_session_t audioSessionId);
@@ -458,7 +460,7 @@
                     sp<MediaPlayerService>        mService;
                     sp<IMediaPlayerClient>        mClient;
                     sp<AudioOutput>               mAudioOutput;
-                    const media::permission::Identity mIdentity;
+                    const AttributionSourceState  mAttributionSource;
                     status_t                      mStatus;
                     bool                          mLoop;
                     int32_t                       mConnId;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index e2c8f8f..a914006 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -126,8 +126,9 @@
     }
 
     if ((as == AUDIO_SOURCE_FM_TUNER
-            && !(captureAudioOutputAllowed(mIdentity) || captureTunerAudioInputAllowed(mIdentity)))
-            || !recordingAllowed(mIdentity)) {
+            && !(captureAudioOutputAllowed(mAttributionSource)
+                    || captureTunerAudioInputAllowed(mAttributionSource)))
+            || !recordingAllowed(mAttributionSource, (audio_source_t)as)) {
         return PERMISSION_DENIED;
     }
     Mutex::Autolock lock(mLock);
@@ -377,12 +378,12 @@
 }
 
 MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service,
-        const Identity& identity)
+        const AttributionSourceState& attributionSource)
 {
     ALOGV("Client constructor");
-    // identity already validated in createMediaRecorder
-    mIdentity = identity;
-    mRecorder = new StagefrightRecorder(identity);
+    // attribution source already validated in createMediaRecorder
+    mAttributionSource = attributionSource;
+    mRecorder = new StagefrightRecorder(attributionSource);
     mMediaPlayerService = service;
 }
 
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 24c6ee1..dcb9f82 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -22,7 +22,7 @@
 
 #include <media/AudioSystem.h>
 #include <media/IMediaRecorder.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <vector>
 
@@ -94,13 +94,13 @@
 
                            MediaRecorderClient(
                                    const sp<MediaPlayerService>& service,
-                                   const media::permission::Identity& identity);
+                                   const content::AttributionSourceState& attributionSource);
     virtual                ~MediaRecorderClient();
 
     std::vector<DeathNotifier> mDeathNotifiers;
     sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedNotifier;
 
-    media::permission::Identity mIdentity;
+    content::AttributionSourceState mAttributionSource;
     mutable Mutex          mLock;
     MediaRecorderBase      *mRecorder;
     sp<MediaPlayerService> mMediaPlayerService;
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 6dc3e3f..2aabd53 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -233,7 +233,7 @@
 
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
         const AString &componentName = matchingCodecs[i];
-        sp<ImageDecoder> decoder = new ImageDecoder(componentName, trackMeta, source);
+        sp<MediaImageDecoder> decoder = new MediaImageDecoder(componentName, trackMeta, source);
         int64_t frameTimeUs = thumbnail ? -1 : 0;
         if (decoder->init(frameTimeUs, 0 /*option*/, colorFormat) == OK) {
             sp<IMemory> frame = decoder->extractFrame(rect);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index ce642f3..bffd7b3 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -116,8 +116,8 @@
 }
 
 
-StagefrightRecorder::StagefrightRecorder(const Identity& clientIdentity)
-    : MediaRecorderBase(clientIdentity),
+StagefrightRecorder::StagefrightRecorder(const AttributionSourceState& client)
+    : MediaRecorderBase(client),
       mWriter(NULL),
       mOutputFd(-1),
       mAudioSource((audio_source_t)AUDIO_SOURCE_CNT), // initialize with invalid value
@@ -159,7 +159,7 @@
 
     // we run as part of the media player service; what we really want to
     // know is the app which requested the recording.
-    mMetricsItem->setUid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mClient.uid)));
+    mMetricsItem->setUid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAttributionSource.uid)));
 
     mMetricsItem->setCString(kRecorderLogSessionId, mLogSessionId.c_str());
 
@@ -1144,7 +1144,8 @@
 
 status_t StagefrightRecorder::setClientName(const String16& clientName) {
 
-    mClient.packageName = VALUE_OR_RETURN_STATUS(legacy2aidl_String16_string(clientName));
+    mAttributionSource.packageName = VALUE_OR_RETURN_STATUS(
+            legacy2aidl_String16_string(clientName));
 
     return OK;
 }
@@ -1355,7 +1356,7 @@
     sp<AudioSource> audioSource =
         new AudioSource(
                 &attr,
-                mClient,
+                mAttributionSource,
                 sourceSampleRate,
                 mAudioChannels,
                 mSampleRate,
@@ -1880,10 +1881,10 @@
     Size videoSize;
     videoSize.width = mVideoWidth;
     videoSize.height = mVideoHeight;
-    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(mClient.uid));
-    pid_t pid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(mClient.pid));
+    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(mAttributionSource.uid));
+    pid_t pid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(mAttributionSource.pid));
     String16 clientName = VALUE_OR_RETURN_STATUS(
-        aidl2legacy_string_view_String16(mClient.packageName.value_or("")));
+        aidl2legacy_string_view_String16(mAttributionSource.packageName.value_or("")));
     if (mCaptureFpsEnable) {
         if (!(mCaptureFps > 0.)) {
             ALOGE("Invalid mCaptureFps value: %lf", mCaptureFps);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 59a080e..d6de47f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -26,12 +26,12 @@
 #include <system/audio.h>
 
 #include <media/hardware/MetadataBufferType.h>
-#include <android/media/permission/Identity.h>
-
-using namespace android::media::permission;
+#include <android/content/AttributionSourceState.h>
 
 namespace android {
 
+using content::AttributionSourceState;
+
 class Camera;
 class ICameraRecordingProxy;
 class CameraSource;
@@ -45,7 +45,7 @@
 struct ALooper;
 
 struct StagefrightRecorder : public MediaRecorderBase {
-    explicit StagefrightRecorder(const Identity& clientIdentity);
+    explicit StagefrightRecorder(const AttributionSourceState& attributionSource);
     virtual ~StagefrightRecorder();
     virtual status_t init();
     virtual status_t setLogSessionId(const String8 &id);
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
index 5b16911..92236ea 100644
--- a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
@@ -73,7 +73,7 @@
         "libstagefright",
         "libstagefright_foundation",
         "libutils",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
     ],
 
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp b/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp
index 6dea53d..162c187 100644
--- a/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp
@@ -59,10 +59,11 @@
     }
 
     void SetUp() override {
-        // TODO b/182392769: use identity util
-        Identity identity;
-        identity.packageName = std::string(LOG_TAG);
-        mStfRecorder = new StagefrightRecorder(identity);
+        // TODO b/182392769: use attribution source util
+        AttributionSourceState attributionSource;
+        attributionSource.packageName = std::string(LOG_TAG);
+        attributionSource.token = sp<BBinder>::make();
+        mStfRecorder = new StagefrightRecorder(attributionSource);
         ASSERT_NE(mStfRecorder, nullptr) << "Failed to create the instance of recorder";
 
         mOutputAudioFp = fopen(OUTPUT_FILE_NAME_AUDIO, "wb");
diff --git a/media/libmediatranscoding/TranscodingThermalPolicy.cpp b/media/libmediatranscoding/TranscodingThermalPolicy.cpp
index 9984abe..88f445c 100644
--- a/media/libmediatranscoding/TranscodingThermalPolicy.cpp
+++ b/media/libmediatranscoding/TranscodingThermalPolicy.cpp
@@ -17,6 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "TranscodingThermalPolicy"
 
+#include <media/TranscodingDefs.h>
 #include <media/TranscodingThermalPolicy.h>
 #include <media/TranscodingUidPolicy.h>
 #include <utils/Log.h>
diff --git a/media/libmediatranscoding/TranscodingUidPolicy.cpp b/media/libmediatranscoding/TranscodingUidPolicy.cpp
index 0a1ffbc..f33c54c 100644
--- a/media/libmediatranscoding/TranscodingUidPolicy.cpp
+++ b/media/libmediatranscoding/TranscodingUidPolicy.cpp
@@ -21,6 +21,7 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <inttypes.h>
+#include <media/TranscodingDefs.h>
 #include <media/TranscodingUidPolicy.h>
 #include <utils/Log.h>
 
diff --git a/media/libmediatranscoding/include/media/TranscodingDefs.h b/media/libmediatranscoding/include/media/TranscodingDefs.h
index 8e02dd2..55e5ad5 100644
--- a/media/libmediatranscoding/include/media/TranscodingDefs.h
+++ b/media/libmediatranscoding/include/media/TranscodingDefs.h
@@ -20,6 +20,9 @@
 #include <aidl/android/media/ITranscodingClientCallback.h>
 #include <aidl/android/media/TranscodingRequestParcel.h>
 
+// Transcoding uses some APIs available on API31+.
+#define __TRANSCODING_MIN_API__ 31
+
 namespace android {
 
 using ClientIdType = uintptr_t;
diff --git a/media/libmediatranscoding/include/media/TranscodingRequest.h b/media/libmediatranscoding/include/media/TranscodingRequest.h
index d38fc59..b66ccf8 100644
--- a/media/libmediatranscoding/include/media/TranscodingRequest.h
+++ b/media/libmediatranscoding/include/media/TranscodingRequest.h
@@ -24,9 +24,6 @@
 
 using ::aidl::android::media::TranscodingRequestParcel;
 
-// TODO: replace __ANDROID_API_FUTURE__with 31 when it's official (b/178144708)
-#define __TRANSCODING_MIN_API__ __ANDROID_API_FUTURE__
-
 // Helper class for duplicating a TranscodingRequestParcel
 class TranscodingRequest : public TranscodingRequestParcel {
 public:
diff --git a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
index dcb22df..4dde5a6 100644
--- a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
+++ b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
@@ -28,9 +28,6 @@
 #include <unordered_map>
 #include <unordered_set>
 
-// TODO: replace __ANDROID_API_FUTURE__with 31 when it's official (b/178144708)
-#define __TRANSCODING_MIN_API__ __ANDROID_API_FUTURE__
-
 struct AActivityManager_UidImportanceListener;
 
 namespace android {
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index b43efcb..7272a74 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -268,8 +268,7 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
-// TODO: replace __ANDROID_API_FUTURE__with 31 when it's official (b/178144708)
-#define __TRANSCODING_MIN_API__ __ANDROID_API_FUTURE__
+#define __TRANSCODING_MIN_API__ 31
 
     AMediaCodec* encoder;
     if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index d6e36b9..a052a70 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -338,7 +338,7 @@
         "android.hardware.cas.native@1.0",
         "android.hardware.drm@1.0",
         "android.hardware.media.omx@1.0",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
     ],
 
@@ -352,7 +352,7 @@
         "libogg",
         "libwebm",
         "libstagefright_id3",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libmediandk_format",
         "libmedia_ndkformatpriv",
     ],
@@ -370,7 +370,7 @@
         "libhidlmemory",
         "libmedia",
         "android.hidl.allocator@1.0",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     export_include_dirs: [
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 89fe56f..b6acdc8 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -34,7 +34,7 @@
 
 namespace android {
 
-using android::media::permission::Identity;
+using content::AttributionSourceState;
 
 static void AudioRecordCallbackFunction(int event, void *user, void *info) {
     AudioSource *source = (AudioSource *) user;
@@ -54,13 +54,13 @@
 }
 
 AudioSource::AudioSource(
-    const audio_attributes_t *attr, const Identity& identity,
+    const audio_attributes_t *attr, const AttributionSourceState& attributionSource,
     uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
     audio_port_handle_t selectedDeviceId,
     audio_microphone_direction_t selectedMicDirection,
     float selectedMicFieldDimension)
 {
-  set(attr, identity, sampleRate, channelCount, outSampleRate, selectedDeviceId,
+  set(attr, attributionSource, sampleRate, channelCount, outSampleRate, selectedDeviceId,
       selectedMicDirection, selectedMicFieldDimension);
 }
 
@@ -71,17 +71,18 @@
         audio_microphone_direction_t selectedMicDirection,
         float selectedMicFieldDimension)
 {
-  // TODO b/182392769: use identity util
-  Identity identity;
-  identity.packageName = VALUE_OR_FATAL(legacy2aidl_String16_string(opPackageName));
-  identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
-  identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
-  set(attr, identity, sampleRate, channelCount, outSampleRate, selectedDeviceId,
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource;
+    attributionSource.packageName = VALUE_OR_FATAL(legacy2aidl_String16_string(opPackageName));
+    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
+    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
+    attributionSource.token = sp<BBinder>::make();
+    set(attr, attributionSource, sampleRate, channelCount, outSampleRate, selectedDeviceId,
       selectedMicDirection, selectedMicFieldDimension);
 }
 
 void AudioSource::set(
-   const audio_attributes_t *attr, const Identity& identity,
+   const audio_attributes_t *attr, const AttributionSourceState& attributionSource,
         uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
         audio_port_handle_t selectedDeviceId,
         audio_microphone_direction_t selectedMicDirection,
@@ -126,7 +127,7 @@
     mRecord = new AudioRecord(
         AUDIO_SOURCE_DEFAULT, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
         audio_channel_in_mask_from_count(channelCount),
-        identity,
+        attributionSource,
         (size_t) (bufCount * frameCount),
         AudioRecordCallbackFunction,
         this,
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index b1aa7a9..95afa62 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -149,7 +149,8 @@
     int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid) {
 
     if (camera == 0) {
-        mCamera = Camera::connect(cameraId, clientName, clientUid, clientPid);
+        mCamera = Camera::connect(cameraId, clientName, clientUid, clientPid,
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__);
         if (mCamera == 0) return -EBUSY;
         mCameraFlags &= ~FLAGS_HOT_CAMERA;
     } else {
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 0fd4ef2..efd4070 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -744,7 +744,7 @@
 
 ////////////////////////////////////////////////////////////////////////
 
-ImageDecoder::ImageDecoder(
+MediaImageDecoder::MediaImageDecoder(
         const AString &componentName,
         const sp<MetaData> &trackMeta,
         const sp<IMediaSource> &source)
@@ -760,7 +760,7 @@
       mTargetTiles(0) {
 }
 
-sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
+sp<AMessage> MediaImageDecoder::onGetFormatAndSeekOptions(
         int64_t frameTimeUs, int /*seekMode*/,
         MediaSource::ReadOptions *options, sp<Surface> * /*window*/) {
     sp<MetaData> overrideMeta;
@@ -836,7 +836,7 @@
     return videoFormat;
 }
 
-status_t ImageDecoder::onExtractRect(FrameRect *rect) {
+status_t MediaImageDecoder::onExtractRect(FrameRect *rect) {
     // TODO:
     // This callback is for verifying whether we can decode the rect,
     // and if so, set up the internal variables for decoding.
@@ -875,7 +875,7 @@
     return OK;
 }
 
-status_t ImageDecoder::onOutputReceived(
+status_t MediaImageDecoder::onOutputReceived(
         const sp<MediaCodecBuffer> &videoFrameBuffer,
         const sp<AMessage> &outputFormat, int64_t /*timeUs*/, bool *done) {
     if (outputFormat == NULL) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 57bdba0..c03236a 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -29,7 +29,10 @@
 #include <C2Buffer.h>
 
 #include "include/SoftwareRenderer.h"
+#include "PlaybackDurationAccumulator.h"
 
+#include <android/binder_manager.h>
+#include <android/content/pm/IPackageManagerNative.h>
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
@@ -39,6 +42,7 @@
 #include <android/binder_manager.h>
 #include <android/dlext.h>
 #include <binder/IMemory.h>
+#include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 #include <cutils/properties.h>
 #include <gui/BufferQueue.h>
@@ -92,6 +96,7 @@
 // NB: these are matched with public Java API constants defined
 // in frameworks/base/media/java/android/media/MediaCodec.java
 // These must be kept synchronized with the constants there.
+static const char *kCodecLogSessionId = "android.media.mediacodec.log-session-id";
 static const char *kCodecCodec = "android.media.mediacodec.codec";  /* e.g. OMX.google.aac.decoder */
 static const char *kCodecMime = "android.media.mediacodec.mime";    /* e.g. audio/mime */
 static const char *kCodecMode = "android.media.mediacodec.mode";    /* audio, video */
@@ -107,6 +112,16 @@
 static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate";
 static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate";
 static const char *kCodecPriority = "android.media.mediacodec.priority";
+
+// Min/Max QP before shaping
+static const char *kCodecOriginalVideoQPIMin = "android.media.mediacodec.original-video-qp-i-min";
+static const char *kCodecOriginalVideoQPIMax = "android.media.mediacodec.original-video-qp-i-max";
+static const char *kCodecOriginalVideoQPPMin = "android.media.mediacodec.original-video-qp-p-min";
+static const char *kCodecOriginalVideoQPPMax = "android.media.mediacodec.original-video-qp-p-max";
+static const char *kCodecOriginalVideoQPBMin = "android.media.mediacodec.original-video-qp-b-min";
+static const char *kCodecOriginalVideoQPBMax = "android.media.mediacodec.original-video-qp-b-max";
+
+// Min/Max QP after shaping
 static const char *kCodecRequestedVideoQPIMin = "android.media.mediacodec.video-qp-i-min";
 static const char *kCodecRequestedVideoQPIMax = "android.media.mediacodec.video-qp-i-max";
 static const char *kCodecRequestedVideoQPPMin = "android.media.mediacodec.video-qp-p-min";
@@ -152,8 +167,12 @@
 static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg";      /* in us */
 static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n";
 static const char *kCodecRecentLatencyHist = "android.media.mediacodec.recent.hist";    /* in us */
+static const char *kCodecPlaybackDurationSec =
+        "android.media.mediacodec.playback-duration-sec"; /* in sec */
 
-static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped";    /* 0/1 */
+/* -1: shaper disabled
+   >=0: number of fields changed */
+static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped";
 
 // XXX suppress until we get our representation right
 static bool kEmitHistogram = false;
@@ -740,6 +759,8 @@
       mHaveInputSurface(false),
       mHavePendingInputBuffers(false),
       mCpuBoostRequested(false),
+      mPlaybackDurationAccumulator(new PlaybackDurationAccumulator()),
+      mIsSurfaceToScreen(false),
       mLatencyUnknown(0),
       mBytesEncoded(0),
       mEarliestEncodedPtsUs(INT64_MAX),
@@ -846,6 +867,10 @@
     if (mLatencyUnknown > 0) {
         mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown);
     }
+    int64_t playbackDurationSec = mPlaybackDurationAccumulator->getDurationInSeconds();
+    if (playbackDurationSec > 0) {
+        mediametrics_setInt64(mMetricsHandle, kCodecPlaybackDurationSec, playbackDurationSec);
+    }
     if (mLifetimeStartNs > 0) {
         nsecs_t lifetime = systemTime(SYSTEM_TIME_MONOTONIC) - mLifetimeStartNs;
         lifetime = lifetime / (1000 * 1000);    // emitted in ms, truncated not rounded
@@ -954,6 +979,10 @@
             return "BufferDecoded";
         case TunnelPeekState::kBufferRendered:
             return "BufferRendered";
+        case TunnelPeekState::kDisabledQueued:
+            return "DisabledQueued";
+        case TunnelPeekState::kEnabledQueued:
+            return "EnabledQueued";
         default:
             return default_string;
     }
@@ -964,25 +993,61 @@
     if (!msg->findInt32("tunnel-peek", &tunnelPeek)){
         return;
     }
+
+    TunnelPeekState previousState = mTunnelPeekState;
     if(tunnelPeek == 0){
-        if (mTunnelPeekState == TunnelPeekState::kEnabledNoBuffer) {
-            mTunnelPeekState = TunnelPeekState::kDisabledNoBuffer;
-            ALOGV("TunnelPeekState: %s -> %s",
-                  asString(TunnelPeekState::kEnabledNoBuffer),
-                  asString(TunnelPeekState::kDisabledNoBuffer));
-            return;
+        switch (mTunnelPeekState) {
+            case TunnelPeekState::kEnabledNoBuffer:
+                mTunnelPeekState = TunnelPeekState::kDisabledNoBuffer;
+                break;
+            case TunnelPeekState::kEnabledQueued:
+                mTunnelPeekState = TunnelPeekState::kDisabledQueued;
+                break;
+            default:
+                ALOGV("Ignoring tunnel-peek=%d for %s", tunnelPeek, asString(mTunnelPeekState));
+                return;
         }
     } else {
-        if (mTunnelPeekState == TunnelPeekState::kDisabledNoBuffer) {
-            mTunnelPeekState = TunnelPeekState::kEnabledNoBuffer;
-            ALOGV("TunnelPeekState: %s -> %s",
-                  asString(TunnelPeekState::kDisabledNoBuffer),
-                  asString(TunnelPeekState::kEnabledNoBuffer));
-            return;
+        switch (mTunnelPeekState) {
+            case TunnelPeekState::kDisabledNoBuffer:
+                mTunnelPeekState = TunnelPeekState::kEnabledNoBuffer;
+                break;
+            case TunnelPeekState::kDisabledQueued:
+                mTunnelPeekState = TunnelPeekState::kEnabledQueued;
+                break;
+            case TunnelPeekState::kBufferDecoded:
+                msg->setInt32("android._trigger-tunnel-peek", 1);
+                mTunnelPeekState = TunnelPeekState::kBufferRendered;
+                break;
+            default:
+                ALOGV("Ignoring tunnel-peek=%d for %s", tunnelPeek, asString(mTunnelPeekState));
+                return;
         }
     }
 
-    ALOGV("Ignoring tunnel-peek=%d for %s", tunnelPeek, asString(mTunnelPeekState));
+    ALOGV("TunnelPeekState: %s -> %s", asString(previousState), asString(mTunnelPeekState));
+}
+
+void MediaCodec::updatePlaybackDuration(const sp<AMessage> &msg) {
+    int what = 0;
+    msg->findInt32("what", &what);
+    if (msg->what() != kWhatCodecNotify && what != kWhatOutputFramesRendered) {
+        static bool logged = false;
+        if (!logged) {
+            logged = true;
+            ALOGE("updatePlaybackDuration: expected kWhatOuputFramesRendered (%d)", msg->what());
+        }
+        return;
+    }
+    // Playback duration only counts if the buffers are going to the screen.
+    if (!mIsSurfaceToScreen) {
+        return;
+    }
+    int64_t renderTimeNs;
+    size_t index = 0;
+    while (msg->findInt64(AStringPrintf("%zu-system-nano", index++).c_str(), &renderTimeNs)) {
+        mPlaybackDurationAccumulator->processRenderTime(renderTimeNs);
+    }
 }
 
 bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor)
@@ -1460,6 +1525,8 @@
     }
 
     if (mIsVideo) {
+        // TODO: validity check log-session-id: it should be a 32-hex-digit.
+        format->findString("log-session-id", &mLogSessionId);
         format->findInt32("width", &mVideoWidth);
         format->findInt32("height", &mVideoHeight);
         if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
@@ -1467,6 +1534,7 @@
         }
 
         if (mMetricsHandle != 0) {
+            mediametrics_setCString(mMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
             mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth);
             mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight);
             mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees);
@@ -1498,30 +1566,6 @@
             if (format->findInt32("priority", &priority)) {
                 mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
             }
-            int32_t qpIMin = -1;
-            if (format->findInt32("video-qp-i-min", &qpIMin)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
-            }
-            int32_t qpIMax = -1;
-            if (format->findInt32("video-qp-i-max", &qpIMax)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax);
-            }
-            int32_t qpPMin = -1;
-            if (format->findInt32("video-qp-p-min", &qpPMin)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin);
-            }
-            int32_t qpPMax = -1;
-            if (format->findInt32("video-qp-p-max", &qpPMax)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax);
-            }
-             int32_t qpBMin = -1;
-            if (format->findInt32("video-qp-b-min", &qpBMin)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin);
-            }
-            int32_t qpBMax = -1;
-            if (format->findInt32("video-qp-b-max", &qpBMax)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax);
-            }
         }
 
         // Prevent possible integer overflow in downstream code.
@@ -1549,6 +1593,9 @@
                                                  enableMediaFormatShapingDefault);
         if (!enableShaping) {
             ALOGI("format shaping disabled, property '%s'", enableMediaFormatShapingProperty);
+            if (mMetricsHandle != 0) {
+                mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, -1);
+            }
         } else {
             (void) shapeMediaFormat(format, flags);
             // XXX: do we want to do this regardless of shaping enablement?
@@ -1556,6 +1603,34 @@
         }
     }
 
+    // push min/max QP to MediaMetrics after shaping
+    if (mIsVideo && mMetricsHandle != 0) {
+        int32_t qpIMin = -1;
+        if (format->findInt32("video-qp-i-min", &qpIMin)) {
+            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
+        }
+        int32_t qpIMax = -1;
+        if (format->findInt32("video-qp-i-max", &qpIMax)) {
+            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax);
+        }
+        int32_t qpPMin = -1;
+        if (format->findInt32("video-qp-p-min", &qpPMin)) {
+            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin);
+        }
+        int32_t qpPMax = -1;
+        if (format->findInt32("video-qp-p-max", &qpPMax)) {
+            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax);
+        }
+        int32_t qpBMin = -1;
+        if (format->findInt32("video-qp-b-min", &qpBMin)) {
+            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin);
+        }
+        int32_t qpBMax = -1;
+        if (format->findInt32("video-qp-b-max", &qpBMax)) {
+            mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax);
+        }
+    }
+
     updateLowLatency(format);
 
     msg->setMessage("format", format);
@@ -1625,6 +1700,7 @@
 //
 
 static android::mediaformatshaper::FormatShaperOps_t *sShaperOps = NULL;
+static bool sIsHandheld = true;
 
 static bool connectFormatShaper() {
     static std::once_flag sCheckOnce;
@@ -1698,6 +1774,64 @@
         ALOGV("connectFormatShaper: loaded libraries: %" PRId64 " us",
               (loading_finished - loading_started)/1000);
 
+
+        // we also want to know whether this is a handheld device
+        // start with assumption that the device is handheld.
+        sIsHandheld = true;
+        sp<IServiceManager> serviceMgr = defaultServiceManager();
+        sp<content::pm::IPackageManagerNative> packageMgr;
+        if (serviceMgr.get() != nullptr) {
+            sp<IBinder> binder = serviceMgr->waitForService(String16("package_native"));
+            packageMgr = interface_cast<content::pm::IPackageManagerNative>(binder);
+        }
+        // if we didn't get serviceMgr, we'll leave packageMgr as default null
+        if (packageMgr != nullptr) {
+
+            // MUST have these
+            static const String16 featuresNeeded[] = {
+                String16("android.hardware.touchscreen")
+            };
+            // these must be present to be a handheld
+            for (::android::String16 required : featuresNeeded) {
+                bool hasFeature = false;
+                binder::Status status = packageMgr->hasSystemFeature(required, 0, &hasFeature);
+                if (!status.isOk()) {
+                    ALOGE("%s: hasSystemFeature failed: %s",
+                        __func__, status.exceptionMessage().c_str());
+                    continue;
+                }
+                ALOGV("feature %s says %d", String8(required).c_str(), hasFeature);
+                if (!hasFeature) {
+                    ALOGV("... which means we are not handheld");
+                    sIsHandheld = false;
+                    break;
+                }
+            }
+
+            // MUST NOT have these
+            static const String16 featuresDisallowed[] = {
+                String16("android.hardware.type.automotive"),
+                String16("android.hardware.type.television"),
+                String16("android.hardware.type.watch")
+            };
+            // any of these present -- we aren't a handheld
+            for (::android::String16 forbidden : featuresDisallowed) {
+                bool hasFeature = false;
+                binder::Status status = packageMgr->hasSystemFeature(forbidden, 0, &hasFeature);
+                if (!status.isOk()) {
+                    ALOGE("%s: hasSystemFeature failed: %s",
+                        __func__, status.exceptionMessage().c_str());
+                    continue;
+                }
+                ALOGV("feature %s says %d", String8(forbidden).c_str(), hasFeature);
+                if (hasFeature) {
+                    ALOGV("... which means we are not handheld");
+                    sIsHandheld = false;
+                    break;
+                }
+            }
+        }
+
     });
 
     return true;
@@ -1776,6 +1910,18 @@
             }
         }
     }
+
+    // we also carry in the codec description whether we are on a handheld device.
+    // this info is eventually used by both the Codec and the C2 machinery to inform
+    // the underlying codec whether to do any shaping.
+    //
+    if (sIsHandheld) {
+        // set if we are indeed a handheld device (or in future 'any eligible device'
+        // missing on devices that aren't eligible for minimum quality enforcement.
+        (void)(sShaperOps->setFeature)(shaperHandle, "_vq_eligible.device", 1);
+        // strictly speaking, it's a tuning, but those are strings and feature stores int
+        (void)(sShaperOps->setFeature)(shaperHandle, "_quality.target", 1 /* S_HANDHELD */);
+    }
 }
 
 status_t MediaCodec::setupFormatShaper(AString mediaType) {
@@ -1816,6 +1962,16 @@
 // Format Shaping
 //      Mapping and Manipulation of encoding parameters
 //
+//      All of these decisions are pushed into the shaper instead of here within MediaCodec.
+//      this includes decisions based on whether the codec implements minimum quality bars
+//      itself or needs to be shaped outside of the codec.
+//      This keeps all those decisions in one place.
+//      It also means that we push some extra decision information (is this a handheld device
+//      or one that is otherwise eligible for minimum quality manipulation, which generational
+//      quality target is in force, etc).  This allows those values to be cached in the
+//      per-codec structures that are done 1 time within a process instead of for each
+//      codec instantiation.
+//
 
 status_t MediaCodec::shapeMediaFormat(
             const sp<AMessage> &format,
@@ -1875,14 +2031,40 @@
         sp<AMessage> deltas = updatedFormat->changesFrom(format, false /* deep */);
         size_t changeCount = deltas->countEntries();
         ALOGD("shapeMediaFormat: deltas(%zu): %s", changeCount, deltas->debugString(2).c_str());
+        if (mMetricsHandle != 0) {
+            mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount);
+        }
         if (changeCount > 0) {
             if (mMetricsHandle != 0) {
-                mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount);
                 // save some old properties before we fold in the new ones
                 int32_t bitrate;
                 if (format->findInt32(KEY_BIT_RATE, &bitrate)) {
                     mediametrics_setInt32(mMetricsHandle, kCodecOriginalBitrate, bitrate);
                 }
+                int32_t qpIMin = -1;
+                if (format->findInt32("original-video-qp-i-min", &qpIMin)) {
+                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMin, qpIMin);
+                }
+                int32_t qpIMax = -1;
+                if (format->findInt32("original-video-qp-i-max", &qpIMax)) {
+                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMax, qpIMax);
+                }
+                int32_t qpPMin = -1;
+                if (format->findInt32("original-video-qp-p-min", &qpPMin)) {
+                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMin, qpPMin);
+                }
+                int32_t qpPMax = -1;
+                if (format->findInt32("original-video-qp-p-max", &qpPMax)) {
+                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMax, qpPMax);
+                }
+                 int32_t qpBMin = -1;
+                if (format->findInt32("original-video-qp-b-min", &qpBMin)) {
+                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMin, qpBMin);
+                }
+                int32_t qpBMax = -1;
+                if (format->findInt32("original-video-qp-b-max", &qpBMax)) {
+                    mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMax, qpBMax);
+                }
             }
             // NB: for any field in both format and deltas, the deltas copy wins
             format->extend(deltas);
@@ -3199,6 +3381,7 @@
                     ALOGV("TunnelPeekState: %s -> %s",
                           asString(previousState),
                           asString(TunnelPeekState::kBufferRendered));
+                    updatePlaybackDuration(msg);
                     // check that we have a notification set
                     if (mOnFrameRenderedNotification != NULL) {
                         sp<AMessage> notify = mOnFrameRenderedNotification->dup();
@@ -3213,25 +3396,32 @@
                     if (mState != STARTED) {
                         break;
                     }
+                    TunnelPeekState previousState = mTunnelPeekState;
                     switch(mTunnelPeekState) {
                         case TunnelPeekState::kDisabledNoBuffer:
+                        case TunnelPeekState::kDisabledQueued:
                             mTunnelPeekState = TunnelPeekState::kBufferDecoded;
+                            ALOGV("First tunnel frame ready");
                             ALOGV("TunnelPeekState: %s -> %s",
-                                  asString(TunnelPeekState::kDisabledNoBuffer),
-                                  asString(TunnelPeekState::kBufferDecoded));
+                                  asString(previousState),
+                                  asString(mTunnelPeekState));
                             break;
                         case TunnelPeekState::kEnabledNoBuffer:
-                            mTunnelPeekState = TunnelPeekState::kBufferDecoded;
-                            ALOGV("TunnelPeekState: %s -> %s",
-                                  asString(TunnelPeekState::kEnabledNoBuffer),
-                                  asString(TunnelPeekState::kBufferDecoded));
+                        case TunnelPeekState::kEnabledQueued:
                             {
                                 sp<AMessage> parameters = new AMessage();
                                 parameters->setInt32("android._trigger-tunnel-peek", 1);
                                 mCodec->signalSetParameters(parameters);
                             }
+                            mTunnelPeekState = TunnelPeekState::kBufferRendered;
+                            ALOGV("First tunnel frame ready");
+                            ALOGV("TunnelPeekState: %s -> %s",
+                                  asString(previousState),
+                                  asString(mTunnelPeekState));
                             break;
                         default:
+                            ALOGV("Ignoring first tunnel frame ready, TunnelPeekState: %s",
+                                  asString(mTunnelPeekState));
                             break;
                     }
 
@@ -4696,6 +4886,28 @@
         buffer->meta()->setInt32("csd", true);
     }
 
+    if (mTunneled) {
+        TunnelPeekState previousState = mTunnelPeekState;
+        switch(mTunnelPeekState){
+            case TunnelPeekState::kEnabledNoBuffer:
+                buffer->meta()->setInt32("tunnel-first-frame", 1);
+                mTunnelPeekState = TunnelPeekState::kEnabledQueued;
+                ALOGV("TunnelPeekState: %s -> %s",
+                        asString(previousState),
+                        asString(mTunnelPeekState));
+                break;
+            case TunnelPeekState::kDisabledNoBuffer:
+                buffer->meta()->setInt32("tunnel-first-frame", 1);
+                mTunnelPeekState = TunnelPeekState::kDisabledQueued;
+                ALOGV("TunnelPeekState: %s -> %s",
+                        asString(previousState),
+                        asString(mTunnelPeekState));
+                break;
+            default:
+                break;
+        }
+    }
+
     status_t err = OK;
     if (hasCryptoOrDescrambler() && !c2Buffer && !memory) {
         AString *errorDetailMsg;
@@ -4905,6 +5117,10 @@
             return ALREADY_EXISTS;
         }
 
+        // in case we don't connect, ensure that we don't signal the surface is
+        // connected to the screen
+        mIsSurfaceToScreen = false;
+
         err = nativeWindowConnect(surface.get(), "connectToSurface");
         if (err == OK) {
             // Require a fresh set of buffers after each connect by using a unique generation
@@ -4930,6 +5146,10 @@
             if (!mAllowFrameDroppingBySurface) {
                 disableLegacyBufferDropPostQ(surface);
             }
+            // keep track whether or not the buffers of the connected surface go to the screen
+            int result = 0;
+            surface->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &result);
+            mIsSurfaceToScreen = result != 0;
         }
     }
     // do not return ALREADY_EXISTS unless surfaces are the same
@@ -4947,6 +5167,7 @@
         }
         // assume disconnected even on error
         mSurface.clear();
+        mIsSurfaceToScreen = false;
     }
     return err;
 }
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index a5c3ba6..6893324 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -307,8 +307,16 @@
 
     sp<MetaData> meta = mImpl->getMetaData();
 
+    if (meta == nullptr) {
+        //extractor did not publish file metadata
+        return -EINVAL;
+    }
+
     const char *mime;
-    CHECK(meta->findCString(kKeyMIMEType, &mime));
+    if (!meta->findCString(kKeyMIMEType, &mime)) {
+        // no mime type maps to invalid
+        return -EINVAL;
+    }
     *format = new AMessage();
     (*format)->setString("mime", mime);
 
@@ -354,6 +362,11 @@
 
     sp<MetaData> meta = mImpl->getMetaData();
 
+    if (meta == nullptr) {
+        //extractor did not publish file metadata
+        return -EINVAL;
+    }
+
     int64_t exifOffset, exifSize;
     if (meta->findInt64(kKeyExifOffset, &exifOffset)
      && meta->findInt64(kKeyExifSize, &exifSize)) {
diff --git a/media/libstagefright/PlaybackDurationAccumulator.h b/media/libstagefright/PlaybackDurationAccumulator.h
new file mode 100644
index 0000000..cb5f0c4
--- /dev/null
+++ b/media/libstagefright/PlaybackDurationAccumulator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef PLAYBACK_DURATION_ACCUMULATOR_H_
+
+namespace android {
+
+// Accumulates playback duration by processing render times of individual frames and by ignoring
+// frames rendered during inactive playbacks such as seeking, pausing, or re-buffering.
+class PlaybackDurationAccumulator {
+private:
+    // Controls the maximum delta between render times before considering the playback is not
+    // active and has stalled.
+    static const int64_t MAX_PRESENTATION_DURATION_NS = 500 * 1000 * 1000;
+
+public:
+    PlaybackDurationAccumulator() {
+        mPlaybackDurationNs = 0;
+        mPreviousRenderTimeNs = 0;
+    }
+
+    // Process a render time expressed in nanoseconds.
+    void processRenderTime(int64_t newRenderTimeNs) {
+        // If we detect wrap-around or out of order frames, just ignore the duration for this
+        // and the next frame.
+        if (newRenderTimeNs < mPreviousRenderTimeNs) {
+            mPreviousRenderTimeNs = 0;
+        }
+        if (mPreviousRenderTimeNs > 0) {
+            int64_t presentationDurationNs = newRenderTimeNs - mPreviousRenderTimeNs;
+            if (presentationDurationNs < MAX_PRESENTATION_DURATION_NS) {
+                mPlaybackDurationNs += presentationDurationNs;
+            }
+        }
+        mPreviousRenderTimeNs = newRenderTimeNs;
+    }
+
+    int64_t getDurationInSeconds() {
+        return mPlaybackDurationNs / 1000 / 1000 / 1000; // Nanoseconds to seconds.
+    }
+
+private:
+    // The playback duration accumulated so far.
+    int64_t mPlaybackDurationNs;
+    // The previous render time used to compute the next presentation duration.
+    int64_t mPreviousRenderTimeNs;
+};
+
+}
+
+#endif
+
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index a15a988..a4e3425 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -183,7 +183,7 @@
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="c2.android.av1.decoder" type="video/av01" variant="!slow-cpu">
-            <Limit name="size" min="2x2" max="1920x1080" />
+            <Limit name="size" min="2x2" max="2048x2048" />
             <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
             <Limit name="block-count" range="1-16384" />
@@ -237,7 +237,7 @@
             <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
             <Limit name="bitrate" range="500-512000" />
             <Limit name="complexity" range="0-10"  default="5" />
-            <Feature name="bitrate-modes" value="CBR" />
+            <Feature name="bitrate-modes" value="CBR,VBR" />
         </MediaCodec>
         <MediaCodec name="c2.android.h263.encoder" type="video/3gpp">
             <Alias name="OMX.google.h263.encoder" />
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 6bb7b37..c2114b3 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -54,13 +54,11 @@
 
 AMessage::AMessage(void)
     : mWhat(0),
-      mTarget(0),
-      mNumItems(0) {
+      mTarget(0) {
 }
 
 AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
-    : mWhat(what),
-      mNumItems(0) {
+    : mWhat(what) {
     setTarget(handler);
 }
 
@@ -89,13 +87,13 @@
 }
 
 void AMessage::clear() {
-    for (size_t i = 0; i < mNumItems; ++i) {
-        Item *item = &mItems[i];
-        delete[] item->mName;
-        item->mName = NULL;
-        freeItemValue(item);
+    // Item needs to be handled delicately
+    for (Item &item : mItems) {
+        delete[] item.mName;
+        item.mName = NULL;
+        freeItemValue(&item);
     }
-    mNumItems = 0;
+    mItems.clear();
 }
 
 void AMessage::freeItemValue(Item *item) {
@@ -157,7 +155,7 @@
     size_t memchecks = 0;
 #endif
     size_t i = 0;
-    for (; i < mNumItems; i++) {
+    for (; i < mItems.size(); i++) {
         if (len != mItems[i].mNameLength) {
             continue;
         }
@@ -172,7 +170,7 @@
     {
         Mutex::Autolock _l(gLock);
         ++gFindItemCalls;
-        gAverageNumItems += mNumItems;
+        gAverageNumItems += mItems.size();
         gAverageNumMemChecks += memchecks;
         gAverageNumChecks += i;
         reportStats();
@@ -188,20 +186,26 @@
     memcpy((void*)mName, name, len + 1);
 }
 
+AMessage::Item::Item(const char *name, size_t len)
+    : mType(kTypeInt32) {
+    // mName and mNameLength are initialized by setName
+    setName(name, len);
+}
+
 AMessage::Item *AMessage::allocateItem(const char *name) {
     size_t len = strlen(name);
     size_t i = findItemIndex(name, len);
     Item *item;
 
-    if (i < mNumItems) {
+    if (i < mItems.size()) {
         item = &mItems[i];
         freeItemValue(item);
     } else {
-        CHECK(mNumItems < kMaxNumItems);
-        i = mNumItems++;
+        CHECK(mItems.size() < kMaxNumItems);
+        i = mItems.size();
+        // place a 'blank' item at the end - this is of type kTypeInt32
+        mItems.emplace_back(name, len);
         item = &mItems[i];
-        item->mType = kTypeInt32;
-        item->setName(name, len);
     }
 
     return item;
@@ -210,7 +214,7 @@
 const AMessage::Item *AMessage::findItem(
         const char *name, Type type) const {
     size_t i = findItemIndex(name, strlen(name));
-    if (i < mNumItems) {
+    if (i < mItems.size()) {
         const Item *item = &mItems[i];
         return item->mType == type ? item : NULL;
 
@@ -220,7 +224,7 @@
 
 bool AMessage::findAsFloat(const char *name, float *value) const {
     size_t i = findItemIndex(name, strlen(name));
-    if (i < mNumItems) {
+    if (i < mItems.size()) {
         const Item *item = &mItems[i];
         switch (item->mType) {
             case kTypeFloat:
@@ -247,7 +251,7 @@
 
 bool AMessage::findAsInt64(const char *name, int64_t *value) const {
     size_t i = findItemIndex(name, strlen(name));
-    if (i < mNumItems) {
+    if (i < mItems.size()) {
         const Item *item = &mItems[i];
         switch (item->mType) {
             case kTypeInt64:
@@ -265,15 +269,16 @@
 
 bool AMessage::contains(const char *name) const {
     size_t i = findItemIndex(name, strlen(name));
-    return i < mNumItems;
+    return i < mItems.size();
 }
 
 #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME)                             \
 void AMessage::set##NAME(const char *name, TYPENAME value) {            \
     Item *item = allocateItem(name);                                    \
-                                                                        \
-    item->mType = kType##NAME;                                          \
-    item->u.FIELDNAME = value;                                          \
+    if (item) {                                                         \
+        item->mType = kType##NAME;                                      \
+        item->u.FIELDNAME = value;                                      \
+    }                                                                   \
 }                                                                       \
                                                                         \
 /* NOLINT added to avoid incorrect warning/fix from clang.tidy */       \
@@ -298,8 +303,10 @@
 void AMessage::setString(
         const char *name, const char *s, ssize_t len) {
     Item *item = allocateItem(name);
-    item->mType = kTypeString;
-    item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
+    if (item) {
+        item->mType = kTypeString;
+        item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
+    }
 }
 
 void AMessage::setString(
@@ -310,10 +317,12 @@
 void AMessage::setObjectInternal(
         const char *name, const sp<RefBase> &obj, Type type) {
     Item *item = allocateItem(name);
-    item->mType = type;
+    if (item) {
+        item->mType = type;
 
-    if (obj != NULL) { obj->incStrong(this); }
-    item->u.refValue = obj.get();
+        if (obj != NULL) { obj->incStrong(this); }
+        item->u.refValue = obj.get();
+    }
 }
 
 void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
@@ -326,22 +335,26 @@
 
 void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
     Item *item = allocateItem(name);
-    item->mType = kTypeMessage;
+    if (item) {
+        item->mType = kTypeMessage;
 
-    if (obj != NULL) { obj->incStrong(this); }
-    item->u.refValue = obj.get();
+        if (obj != NULL) { obj->incStrong(this); }
+        item->u.refValue = obj.get();
+    }
 }
 
 void AMessage::setRect(
         const char *name,
         int32_t left, int32_t top, int32_t right, int32_t bottom) {
     Item *item = allocateItem(name);
-    item->mType = kTypeRect;
+    if (item) {
+        item->mType = kTypeRect;
 
-    item->u.rectValue.mLeft = left;
-    item->u.rectValue.mTop = top;
-    item->u.rectValue.mRight = right;
-    item->u.rectValue.mBottom = bottom;
+        item->u.rectValue.mLeft = left;
+        item->u.rectValue.mTop = top;
+        item->u.rectValue.mRight = right;
+        item->u.rectValue.mBottom = bottom;
+    }
 }
 
 bool AMessage::findString(const char *name, AString *value) const {
@@ -466,18 +479,18 @@
 
 sp<AMessage> AMessage::dup() const {
     sp<AMessage> msg = new AMessage(mWhat, mHandler.promote());
-    msg->mNumItems = mNumItems;
+    msg->mItems = mItems;
 
 #ifdef DUMP_STATS
     {
         Mutex::Autolock _l(gLock);
         ++gDupCalls;
-        gAverageDupItems += mNumItems;
+        gAverageDupItems += mItems.size();
         reportStats();
     }
 #endif
 
-    for (size_t i = 0; i < mNumItems; ++i) {
+    for (size_t i = 0; i < mItems.size(); ++i) {
         const Item *from = &mItems[i];
         Item *to = &msg->mItems[i];
 
@@ -560,7 +573,7 @@
     }
     s.append(") = {\n");
 
-    for (size_t i = 0; i < mNumItems; ++i) {
+    for (size_t i = 0; i < mItems.size(); ++i) {
         const Item &item = mItems[i];
 
         switch (item.mType) {
@@ -653,19 +666,20 @@
     sp<AMessage> msg = new AMessage();
     msg->setWhat(what);
 
-    msg->mNumItems = static_cast<size_t>(parcel.readInt32());
-    if (msg->mNumItems > kMaxNumItems) {
+    size_t numItems = static_cast<size_t>(parcel.readInt32());
+    if (numItems > kMaxNumItems) {
         ALOGE("Too large number of items clipped.");
-        msg->mNumItems = kMaxNumItems;
+        numItems = kMaxNumItems;
     }
+    msg->mItems.resize(numItems);
 
-    for (size_t i = 0; i < msg->mNumItems; ++i) {
+    for (size_t i = 0; i < msg->mItems.size(); ++i) {
         Item *item = &msg->mItems[i];
 
         const char *name = parcel.readCString();
         if (name == NULL) {
             ALOGE("Failed reading name for an item. Parsing aborted.");
-            msg->mNumItems = i;
+            msg->mItems.resize(i);
             break;
         }
 
@@ -709,7 +723,7 @@
                 if (stringValue == NULL) {
                     ALOGE("Failed reading string value from a parcel. "
                         "Parsing aborted.");
-                    msg->mNumItems = i;
+                    msg->mItems.resize(i);
                     continue;
                     // The loop will terminate subsequently.
                 } else {
@@ -754,11 +768,9 @@
 
 void AMessage::writeToParcel(Parcel *parcel) const {
     parcel->writeInt32(static_cast<int32_t>(mWhat));
-    parcel->writeInt32(static_cast<int32_t>(mNumItems));
+    parcel->writeInt32(static_cast<int32_t>(mItems.size()));
 
-    for (size_t i = 0; i < mNumItems; ++i) {
-        const Item &item = mItems[i];
-
+    for (const Item &item : mItems) {
         parcel->writeCString(item.mName);
         parcel->writeInt32(static_cast<int32_t>(item.mType));
 
@@ -828,8 +840,7 @@
         diff->setTarget(mHandler.promote());
     }
 
-    for (size_t i = 0; i < mNumItems; ++i) {
-        const Item &item = mItems[i];
+    for (const Item &item : mItems) {
         const Item *oitem = other->findItem(item.mName, item.mType);
         switch (item.mType) {
             case kTypeInt32:
@@ -936,11 +947,11 @@
 }
 
 size_t AMessage::countEntries() const {
-    return mNumItems;
+    return mItems.size();
 }
 
 const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
-    if (index >= mNumItems) {
+    if (index >= mItems.size()) {
         *type = kTypeInt32;
 
         return NULL;
@@ -953,7 +964,7 @@
 
 AMessage::ItemData AMessage::getEntryAt(size_t index) const {
     ItemData it;
-    if (index < mNumItems) {
+    if (index < mItems.size()) {
         switch (mItems[index].mType) {
             case kTypeInt32:    it.set(mItems[index].u.int32Value); break;
             case kTypeInt64:    it.set(mItems[index].u.int64Value); break;
@@ -986,7 +997,7 @@
 }
 
 status_t AMessage::setEntryNameAt(size_t index, const char *name) {
-    if (index >= mNumItems) {
+    if (index >= mItems.size()) {
         return BAD_INDEX;
     }
     if (name == nullptr) {
@@ -996,7 +1007,7 @@
         return OK; // name has not changed
     }
     size_t len = strlen(name);
-    if (findItemIndex(name, len) < mNumItems) {
+    if (findItemIndex(name, len) < mItems.size()) {
         return ALREADY_EXISTS;
     }
     delete[] mItems[index].mName;
@@ -1011,7 +1022,7 @@
     sp<AMessage> msgValue;
     sp<ABuffer> bufValue;
 
-    if (index >= mNumItems) {
+    if (index >= mItems.size()) {
         return BAD_INDEX;
     }
     if (!item.used()) {
@@ -1060,21 +1071,22 @@
 }
 
 status_t AMessage::removeEntryAt(size_t index) {
-    if (index >= mNumItems) {
+    if (index >= mItems.size()) {
         return BAD_INDEX;
     }
     // delete entry data and objects
-    --mNumItems;
     delete[] mItems[index].mName;
     mItems[index].mName = nullptr;
     freeItemValue(&mItems[index]);
 
     // swap entry with last entry and clear last entry's data
-    if (index < mNumItems) {
-        mItems[index] = mItems[mNumItems];
-        mItems[mNumItems].mName = nullptr;
-        mItems[mNumItems].mType = kTypeInt32;
+    size_t lastIndex = mItems.size() - 1;
+    if (index < lastIndex) {
+        mItems[index] = mItems[lastIndex];
+        mItems[lastIndex].mName = nullptr;
+        mItems[lastIndex].mType = kTypeInt32;
     }
+    mItems.pop_back();
     return OK;
 }
 
@@ -1083,7 +1095,7 @@
         return BAD_VALUE;
     }
     size_t index = findEntryByName(name);
-    if (index >= mNumItems) {
+    if (index >= mItems.size()) {
         return BAD_INDEX;
     }
     return removeEntryAt(index);
@@ -1093,7 +1105,7 @@
     if (item.used()) {
         Item *it = allocateItem(name);
         if (it != nullptr) {
-            setEntryAt(it - mItems, item);
+            setEntryAt(it - &mItems[0], item);
         }
     }
 }
@@ -1108,11 +1120,11 @@
         return;
     }
 
-    for (size_t ix = 0; ix < other->mNumItems; ++ix) {
+    for (size_t ix = 0; ix < other->mItems.size(); ++ix) {
         Item *it = allocateItem(other->mItems[ix].mName);
         if (it != nullptr) {
             ItemData data = other->getEntryAt(ix);
-            setEntryAt(it - mItems, data);
+            setEntryAt(it - &mItems[0], data);
         }
     }
 }
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
index 98d6147..960212a 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
@@ -24,6 +24,8 @@
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 
+#include <vector>
+
 namespace android {
 
 struct ABuffer;
@@ -95,6 +97,7 @@
 
     void setTarget(const sp<const AHandler> &handler);
 
+    // removes all items
     void clear();
 
     void setInt32(const char *name, int32_t value);
@@ -302,16 +305,39 @@
         size_t      mNameLength;
         Type mType;
         void setName(const char *name, size_t len);
+        Item() : mName(nullptr), mNameLength(0), mType(kTypeInt32) { }
+        Item(const char *name, size_t length);
     };
 
     enum {
-        kMaxNumItems = 64
+        kMaxNumItems = 256
     };
-    Item mItems[kMaxNumItems];
-    size_t mNumItems;
+    std::vector<Item> mItems;
 
+    /**
+     * Allocates an item with the given key |name|. If the key already exists, the corresponding
+     * item value is freed. Otherwise a new item is added.
+     *
+     * This method currently asserts if the number of elements would exceed the max number of
+     * elements allowed (kMaxNumItems). This is a security precaution to avoid arbitrarily large
+     * AMessage structures.
+     *
+     * @todo(b/192153245) Either revisit this security precaution, or change the behavior to
+     *      silently ignore keys added after the max number of elements are reached.
+     *
+     * @note All previously returned Item* pointers are deemed invalid after this call. (E.g. from
+     *       allocateItem or findItem)
+     *
+     * @param name the key for the requested item.
+     *
+     * @return Item* a pointer to the item.
+     */
     Item *allocateItem(const char *name);
+
+    /** Frees the value for the item. */
     void freeItemValue(Item *item);
+
+    /** Finds an item with given key |name| and |type|. Returns nullptr if item is not found. */
     const Item *findItem(const char *name, Type type) const;
 
     void setObjectInternal(
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index bca7f01..d59e4f5 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -146,8 +146,8 @@
     status_t captureSurface();
 };
 
-struct ImageDecoder : public FrameDecoder {
-    ImageDecoder(
+struct MediaImageDecoder : public FrameDecoder {
+   MediaImageDecoder(
             const AString &componentName,
             const sp<MetaData> &trackMeta,
             const sp<IMediaSource> &source);
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index d1dcdb5..43d50f1 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -31,6 +31,8 @@
 
 namespace android {
 
+using content::AttributionSourceState;
+
 class AudioRecord;
 
 struct AudioSource : public MediaSource, public MediaBufferObserver {
@@ -38,7 +40,7 @@
     // _not_ a bitmask of audio_channels_t constants.
     AudioSource(
         const audio_attributes_t *attr,
-        const media::permission::Identity& identity,
+        const AttributionSourceState& attributionSource,
         uint32_t sampleRate,
         uint32_t channels,
         uint32_t outSampleRate = 0,
@@ -145,7 +147,7 @@
 
     void set(
         const audio_attributes_t *attr,
-        const media::permission::Identity& identity,
+        const AttributionSourceState& attributionSource,
         uint32_t sampleRate,
         uint32_t channels,
         uint32_t outSampleRate = 0,
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 3517bae..d372140 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -58,6 +58,7 @@
 struct PersistentSurface;
 class SoftwareRenderer;
 class Surface;
+class PlaybackDurationAccumulator;
 namespace hardware {
 namespace cas {
 namespace native {
@@ -376,15 +377,23 @@
     // This type is used to track the tunnel mode video peek state machine:
     //
     // DisabledNoBuffer -> EnabledNoBuffer  when tunnel-peek = true
+    // DisabledQueued   -> EnabledQueued    when tunnel-peek = true
+    // DisabledNoBuffer -> DisabledQueued   when first frame queued
     // EnabledNoBuffer  -> DisabledNoBuffer when tunnel-peek = false
+    // EnabledQueued    -> DisabledQueued   when tunnel-peek = false
+    // EnabledNoBuffer  -> EnabledQueued    when first frame queued
     // DisabledNoBuffer -> BufferDecoded    when kWhatFirstTunnelFrameReady
+    // DisabledQueued   -> BufferDecoded    when kWhatFirstTunnelFrameReady
     // EnabledNoBuffer  -> BufferDecoded    when kWhatFirstTunnelFrameReady
+    // EnabledQueued    -> BufferDecoded    when kWhatFirstTunnelFrameReady
     // BufferDecoded    -> BufferRendered   when kWhatFrameRendered
     // <all states>     -> EnabledNoBuffer  when flush
     // <all states>     -> EnabledNoBuffer  when stop then configure then start
     enum struct TunnelPeekState {
         kDisabledNoBuffer,
         kEnabledNoBuffer,
+        kDisabledQueued,
+        kEnabledQueued,
         kBufferDecoded,
         kBufferRendered,
     };
@@ -418,6 +427,7 @@
     void updateLowLatency(const sp<AMessage> &msg);
     constexpr const char *asString(TunnelPeekState state, const char *default_string="?");
     void updateTunnelPeek(const sp<AMessage> &msg);
+    void updatePlaybackDuration(const sp<AMessage> &msg);
 
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
@@ -429,6 +439,7 @@
     sp<ResourceManagerServiceProxy> mResourceManagerProxy;
 
     bool mIsVideo;
+    AString mLogSessionId;
     int32_t mVideoWidth;
     int32_t mVideoHeight;
     int32_t mRotationDegrees;
@@ -485,6 +496,9 @@
 
     std::shared_ptr<BufferChannelBase> mBufferChannel;
 
+    PlaybackDurationAccumulator * mPlaybackDurationAccumulator;
+    bool mIsSurfaceToScreen;
+
     MediaCodec(
             const sp<ALooper> &looper, pid_t pid, uid_t uid,
             std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr,
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 6371769..4237e8c 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -557,12 +557,14 @@
 }
 
 constexpr int32_t BITRATE_MODE_CBR = 2;
+constexpr int32_t BITRATE_MODE_CBR_FD = 3;
 constexpr int32_t BITRATE_MODE_CQ = 0;
 constexpr int32_t BITRATE_MODE_VBR = 1;
 
 inline static const char *asString_BitrateMode(int32_t i, const char *def = "??") {
     switch (i) {
         case BITRATE_MODE_CBR:  return "CBR";
+        case BITRATE_MODE_CBR_FD: return "CBR_FD";
         case BITRATE_MODE_CQ:   return "CQ";
         case BITRATE_MODE_VBR:  return "VBR";
         default:                return def;
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index 92b2b09..e1cc5ec 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -45,6 +45,7 @@
       mAccessUnitDamaged(false),
       mFirstIFrameProvided(false),
       mLastIFrameProvidedAtMs(0),
+      mLastRtpTimeJitterDataUs(0),
       mWidth(0),
       mHeight(0) {
 }
@@ -123,45 +124,65 @@
     sp<ABuffer> buffer = *queue->begin();
     buffer->meta()->setObject("source", source);
 
+    /**
+     * RFC3550 calculates the interarrival jitter time for 'ALL packets'.
+     * But that is not useful as an ingredient of buffering time.
+     * Instead, we calculates the time only for all 'NAL units'.
+     */
     int64_t rtpTime = findRTPTime(firstRTPTime, buffer);
+    int64_t nowTimeUs = ALooper::GetNowUs();
+    if (rtpTime != mLastRtpTimeJitterDataUs) {
+        source->putBaseJitterData(rtpTime, nowTimeUs);
+        mLastRtpTimeJitterDataUs = rtpTime;
+    }
+    source->putInterArrivalJitterData(rtpTime, nowTimeUs);
 
     const int64_t startTimeMs = source->mFirstSysTime / 1000;
-    const int64_t nowTimeMs = ALooper::GetNowUs() / 1000;
-    const int64_t staticJbTimeMs = source->getStaticJitterTimeMs();
-    const int64_t dynamicJbTimeMs = source->getDynamicJitterTimeMs();
+    const int64_t nowTimeMs = nowTimeUs / 1000;
+    const int32_t staticJitterTimeMs = source->getStaticJitterTimeMs();
+    const int32_t baseJitterTimeMs = source->getBaseJitterTimeMs();
+    const int32_t dynamicJitterTimeMs = source->getInterArrivalJitterTimeMs();
     const int64_t clockRate = source->mClockRate;
 
     int64_t playedTimeMs = nowTimeMs - startTimeMs;
     int64_t playedTimeRtp = source->mFirstRtpTime + MsToRtp(playedTimeMs, clockRate);
 
     /**
-     * Based on experience in real commercial network services,
+     * Based on experiences in real commercial network services,
      * 300 ms is a maximum heuristic jitter buffer time for video RTP service.
      */
 
     /**
-     * The static(base) jitter is a kind of expected propagation time that we desire.
-     * We can drop packets if it doesn't meet our standards.
-     * If it gets shorter we can get faster response but can lose packets.
+     * The base jitter is an expected additional propagation time.
+     * We can drop packets if the time doesn't meet our standards.
+     * If it gets shorter, we can get faster response but should drop delayed packets.
      * Expecting range : 50ms ~ 1000ms (But 300 ms would be practical upper bound)
      */
-    const int64_t baseJbTimeRtp = MsToRtp(staticJbTimeMs, clockRate);
+    const int32_t baseJbTimeMs = std::min(std::max(staticJitterTimeMs, baseJitterTimeMs), 300);
     /**
      * Dynamic jitter is a variance of interarrival time as defined in the 6.4.1 of RFC 3550.
-     * We can regard this as a tolerance of every moments.
+     * We can regard this as a tolerance of every data putting moments.
      * Expecting range : 0ms ~ 150ms (Not to over 300 ms practically)
      */
-    const int64_t dynamicJbTimeRtp =                        // Max 150
-            std::min(MsToRtp(dynamicJbTimeMs, clockRate), MsToRtp(150, clockRate));
-    const int64_t jitterTimeRtp = baseJbTimeRtp + dynamicJbTimeRtp; // Total jitter time
+    const int32_t dynamicJbTimeMs = std::min(dynamicJitterTimeMs, 150);
+    const int64_t dynamicJbTimeRtp = MsToRtp(dynamicJbTimeMs, clockRate);
+    /* Fundamental jitter time */
+    const int32_t jitterTimeMs = baseJbTimeMs;
+    const int64_t jitterTimeRtp = MsToRtp(jitterTimeMs, clockRate);
 
+    // Till (T), this assembler waits unconditionally to collect current NAL unit
     int64_t expiredTimeRtp = rtpTime + jitterTimeRtp;       // When does this buffer expire ? (T)
     int64_t diffTimeRtp = playedTimeRtp - expiredTimeRtp;
     bool isExpired = (diffTimeRtp >= 0);                    // It's expired if T is passed away
-    bool isFirstLineBroken = (diffTimeRtp > jitterTimeRtp); // (T + jitter) is a standard tolerance
 
-    int64_t finalMargin = dynamicJbTimeRtp * JITTER_MULTIPLE;
-    bool isSecondLineBroken = (diffTimeRtp > jitterTimeRtp + finalMargin); // The Maginot line
+    // From (T), this assembler tries to complete the NAL till (T + try)
+    int32_t tryJbTimeMs = baseJitterTimeMs / 2 + dynamicJbTimeMs;
+    int64_t tryJbTimeRtp = MsToRtp(tryJbTimeMs, clockRate);
+    bool isFirstLineBroken = (diffTimeRtp > tryJbTimeRtp);
+
+    // After (T + try), it gives last chance till (T + try + a) with warning messages.
+    int64_t alpha = dynamicJbTimeRtp * JITTER_MULTIPLE;     // Use Dyn as 'a'
+    bool isSecondLineBroken = (diffTimeRtp > (tryJbTimeRtp + alpha));   // The Maginot line
 
     if (mShowQueue && mShowQueueCnt < 20) {
         showCurrentQueue(queue);
@@ -179,20 +200,20 @@
 
     if (isFirstLineBroken) {
         if (isSecondLineBroken) {
-            ALOGW("buffer too late ... \t Diff in Jb=%lld \t "
+            int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
+            ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
                     "Seq# %d \t ExpSeq# %d \t"
-                    "JitterMs %lld + (%lld * %.3f)",
-                    (long long)(diffTimeRtp),
+                    "JitterMs %d + (%d + %d * %.3f)",
+                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                     buffer->int32Data(), mNextExpectedSeqNo,
-                    (long long)staticJbTimeMs, (long long)dynamicJbTimeMs, JITTER_MULTIPLE + 1);
+                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
             printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
             printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
 
             mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
         }  else {
-            ALOGW("=== WARNING === buffer arrived after %lld + %lld = %lld ms === WARNING === ",
-                    (long long)staticJbTimeMs, (long long)dynamicJbTimeMs,
-                    (long long)RtpToMs(jitterTimeRtp, clockRate));
+            ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
+                    jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
         }
     }
 
diff --git a/media/libstagefright/rtsp/AAVCAssembler.h b/media/libstagefright/rtsp/AAVCAssembler.h
index 954086c..8d19773 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.h
+++ b/media/libstagefright/rtsp/AAVCAssembler.h
@@ -48,6 +48,7 @@
     bool mAccessUnitDamaged;
     bool mFirstIFrameProvided;
     uint64_t mLastIFrameProvidedAtMs;
+    int64_t mLastRtpTimeJitterDataUs;
     int32_t mWidth;
     int32_t mHeight;
     List<sp<ABuffer> > mNALUnits;
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index cd60203..d32e85d 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -52,6 +52,7 @@
       mAccessUnitDamaged(false),
       mFirstIFrameProvided(false),
       mLastIFrameProvidedAtMs(0),
+      mLastRtpTimeJitterDataUs(0),
       mWidth(0),
       mHeight(0) {
 
@@ -133,45 +134,65 @@
     sp<ABuffer> buffer = *queue->begin();
     buffer->meta()->setObject("source", source);
 
+    /**
+     * RFC3550 calculates the interarrival jitter time for 'ALL packets'.
+     * But that is not useful as an ingredient of buffering time.
+     * Instead, we calculates the time only for all 'NAL units'.
+     */
     int64_t rtpTime = findRTPTime(firstRTPTime, buffer);
+    int64_t nowTimeUs = ALooper::GetNowUs();
+    if (rtpTime != mLastRtpTimeJitterDataUs) {
+        source->putBaseJitterData(rtpTime, nowTimeUs);
+        mLastRtpTimeJitterDataUs = rtpTime;
+    }
+    source->putInterArrivalJitterData(rtpTime, nowTimeUs);
 
     const int64_t startTimeMs = source->mFirstSysTime / 1000;
-    const int64_t nowTimeMs = ALooper::GetNowUs() / 1000;
-    const int64_t staticJbTimeMs = source->getStaticJitterTimeMs();
-    const int64_t dynamicJbTimeMs = source->getDynamicJitterTimeMs();
+    const int64_t nowTimeMs = nowTimeUs / 1000;
+    const int32_t staticJitterTimeMs = source->getStaticJitterTimeMs();
+    const int32_t baseJitterTimeMs = source->getBaseJitterTimeMs();
+    const int32_t dynamicJitterTimeMs = source->getInterArrivalJitterTimeMs();
     const int64_t clockRate = source->mClockRate;
 
     int64_t playedTimeMs = nowTimeMs - startTimeMs;
     int64_t playedTimeRtp = source->mFirstRtpTime + MsToRtp(playedTimeMs, clockRate);
 
     /**
-     * Based on experience in real commercial network services,
+     * Based on experiences in real commercial network services,
      * 300 ms is a maximum heuristic jitter buffer time for video RTP service.
      */
 
     /**
-     * The static(base) jitter is a kind of expected propagation time that we desire.
-     * We can drop packets if it doesn't meet our standards.
-     * If it gets shorter we can get faster response but can lose packets.
+     * The base jitter is an expected additional propagation time.
+     * We can drop packets if the time doesn't meet our standards.
+     * If it gets shorter, we can get faster response but should drop delayed packets.
      * Expecting range : 50ms ~ 1000ms (But 300 ms would be practical upper bound)
      */
-    const int64_t baseJbTimeRtp = MsToRtp(staticJbTimeMs, clockRate);
+    const int32_t baseJbTimeMs = std::min(std::max(staticJitterTimeMs, baseJitterTimeMs), 300);
     /**
      * Dynamic jitter is a variance of interarrival time as defined in the 6.4.1 of RFC 3550.
-     * We can regard this as a tolerance of every moments.
+     * We can regard this as a tolerance of every data putting moments.
      * Expecting range : 0ms ~ 150ms (Not to over 300 ms practically)
      */
-    const int64_t dynamicJbTimeRtp =                        // Max 150
-            std::min(MsToRtp(dynamicJbTimeMs, clockRate), MsToRtp(150, clockRate));
-    const int64_t jitterTimeRtp = baseJbTimeRtp + dynamicJbTimeRtp; // Total jitter time
+    const int32_t dynamicJbTimeMs = std::min(dynamicJitterTimeMs, 150);
+    const int64_t dynamicJbTimeRtp = MsToRtp(dynamicJbTimeMs, clockRate);
+    /* Fundamental jitter time */
+    const int32_t jitterTimeMs = baseJbTimeMs;
+    const int64_t jitterTimeRtp = MsToRtp(jitterTimeMs, clockRate);
 
+    // Till (T), this assembler waits unconditionally to collect current NAL unit
     int64_t expiredTimeRtp = rtpTime + jitterTimeRtp;       // When does this buffer expire ? (T)
     int64_t diffTimeRtp = playedTimeRtp - expiredTimeRtp;
     bool isExpired = (diffTimeRtp >= 0);                    // It's expired if T is passed away
-    bool isFirstLineBroken = (diffTimeRtp > jitterTimeRtp); // (T + jitter) is a standard tolerance
 
-    int64_t finalMargin = dynamicJbTimeRtp * JITTER_MULTIPLE;
-    bool isSecondLineBroken = (diffTimeRtp > jitterTimeRtp + finalMargin); // The Maginot line
+    // From (T), this assembler tries to complete the NAL till (T + try)
+    int32_t tryJbTimeMs = baseJitterTimeMs / 2 + dynamicJbTimeMs;
+    int64_t tryJbTimeRtp = MsToRtp(tryJbTimeMs, clockRate);
+    bool isFirstLineBroken = (diffTimeRtp > tryJbTimeRtp);
+
+    // After (T + try), it gives last chance till (T + try + a) with warning messages.
+    int64_t alpha = dynamicJbTimeRtp * JITTER_MULTIPLE;     // Use Dyn as 'a'
+    bool isSecondLineBroken = (diffTimeRtp > (tryJbTimeRtp + alpha));   // The Maginot line
 
     if (mShowQueueCnt < 20) {
         showCurrentQueue(queue);
@@ -189,20 +210,20 @@
 
     if (isFirstLineBroken) {
         if (isSecondLineBroken) {
-            ALOGW("buffer too late ... \t Diff in Jb=%lld \t "
+            int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
+            ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
                     "Seq# %d \t ExpSeq# %d \t"
-                    "JitterMs %lld + (%lld * %.3f)",
-                    (long long)(diffTimeRtp),
+                    "JitterMs %d + (%d + %d * %.3f)",
+                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                     buffer->int32Data(), mNextExpectedSeqNo,
-                    (long long)staticJbTimeMs, (long long)dynamicJbTimeMs, JITTER_MULTIPLE + 1);
+                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
             printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
             printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
 
             mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
         }  else {
-            ALOGW("=== WARNING === buffer arrived after %lld + %lld = %lld ms === WARNING === ",
-                    (long long)staticJbTimeMs, (long long)dynamicJbTimeMs,
-                    (long long)RtpToMs(jitterTimeRtp, clockRate));
+            ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
+                    jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
         }
     }
 
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.h b/media/libstagefright/rtsp/AHEVCAssembler.h
index e64b661..68777a7 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.h
+++ b/media/libstagefright/rtsp/AHEVCAssembler.h
@@ -49,6 +49,7 @@
     bool mAccessUnitDamaged;
     bool mFirstIFrameProvided;
     uint64_t mLastIFrameProvidedAtMs;
+    int64_t mLastRtpTimeJitterDataUs;
     int32_t mWidth;
     int32_t mHeight;
     List<sp<ABuffer> > mNALUnits;
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 9509377..33c85a7 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -723,7 +723,6 @@
     buffer->setInt32Data(u16at(&data[2]));
     buffer->setRange(payloadOffset, size - payloadOffset);
 
-    source->putDynamicJitterData(rtpTime, s->mLastPollTimeUs);
     source->processRTPPacket(buffer);
 
     return OK;
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 402dc27..8787d65 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -146,6 +146,7 @@
         mFirstSsrc = ssrc;
         ALOGD("first-rtp arrived: first-rtp-time=%u, sys-time=%lld, seq-num=%u, ssrc=%d",
                 mFirstRtpTime, (long long)mFirstSysTime, mHighestSeqNumber, mFirstSsrc);
+        mJitterCalc->init(mFirstRtpTime, mFirstSysTime, 0, mStaticJbTimeMs * 1000);
         mQueue.push_back(buffer);
         return true;
     }
@@ -331,7 +332,7 @@
     data[18] = (mHighestSeqNumber >> 8) & 0xff;
     data[19] = mHighestSeqNumber & 0xff;
 
-    uint32_t jitterTime = getDynamicJitterTimeMs() * mClockRate / 1000;
+    uint32_t jitterTime = 0;
     data[20] = jitterTime >> 24;    // Interarrival jitter
     data[21] = (jitterTime >> 16) & 0xff;
     data[22] = (jitterTime >> 8) & 0xff;
@@ -518,20 +519,28 @@
     mIssueFIRRequests = enable;
 }
 
-uint32_t ARTPSource::getStaticJitterTimeMs() {
+int32_t ARTPSource::getStaticJitterTimeMs() {
     return mStaticJbTimeMs;
 }
 
-uint32_t ARTPSource::getDynamicJitterTimeMs() {
-    return mJitterCalc->getJitterMs();
+int32_t ARTPSource::getBaseJitterTimeMs() {
+    return mJitterCalc->getBaseJitterMs();
+}
+
+int32_t ARTPSource::getInterArrivalJitterTimeMs() {
+    return mJitterCalc->getInterArrivalJitterMs();
 }
 
 void ARTPSource::setStaticJitterTimeMs(const uint32_t jbTimeMs) {
     mStaticJbTimeMs = jbTimeMs;
 }
 
-void ARTPSource::putDynamicJitterData(uint32_t timeStamp, int64_t arrivalTime) {
-    mJitterCalc->putData(timeStamp, arrivalTime);
+void ARTPSource::putBaseJitterData(uint32_t timeStamp, int64_t arrivalTime) {
+    mJitterCalc->putBaseData(timeStamp, arrivalTime);
+}
+
+void ARTPSource::putInterArrivalJitterData(uint32_t timeStamp, int64_t arrivalTime) {
+    mJitterCalc->putInterArrivalData(timeStamp, arrivalTime);
 }
 
 bool ARTPSource::isNeedToEarlyNotify() {
diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/ARTPSource.h
index 56011d3..0edff23 100644
--- a/media/libstagefright/rtsp/ARTPSource.h
+++ b/media/libstagefright/rtsp/ARTPSource.h
@@ -70,10 +70,12 @@
     void setSelfID(const uint32_t selfID);
     void setPeriodicFIR(bool enable);
 
-    uint32_t getStaticJitterTimeMs();
-    uint32_t getDynamicJitterTimeMs();
+    int32_t getStaticJitterTimeMs();
+    int32_t getBaseJitterTimeMs();
+    int32_t getInterArrivalJitterTimeMs();
     void setStaticJitterTimeMs(const uint32_t jbTimeMs);
-    void putDynamicJitterData(uint32_t timeStamp, int64_t arrivalTime);
+    void putBaseJitterData(uint32_t timeStamp, int64_t arrivalTime);
+    void putInterArrivalJitterData(uint32_t timeStamp, int64_t arrivalTime);
 
     bool isNeedToEarlyNotify();
     void notifyPktInfo(int32_t bitrate, bool isRegular);
@@ -104,7 +106,7 @@
     List<sp<ABuffer> > mQueue;
     sp<ARTPAssembler> mAssembler;
 
-    uint32_t mStaticJbTimeMs;
+    int32_t mStaticJbTimeMs;
     sp<JitterCalc> mJitterCalc;
 
     typedef struct infoNACK {
diff --git a/media/libstagefright/rtsp/JitterCalculator.cpp b/media/libstagefright/rtsp/JitterCalculator.cpp
index 466171c..93b5a83 100644
--- a/media/libstagefright/rtsp/JitterCalculator.cpp
+++ b/media/libstagefright/rtsp/JitterCalculator.cpp
@@ -25,45 +25,63 @@
 
 JitterCalc::JitterCalc(int32_t clockRate)
     : mClockRate(clockRate) {
-    init();
+    init(0, 0, 0, 0);
 }
 
-void JitterCalc::init() {
-    mJitterValueUs = 0;
-    mLastTimeStamp = 0;
-    mLastArrivalTimeUs = 0;
+void JitterCalc::init(uint32_t rtpTime, int64_t arrivalTimeUs, int32_t base, int32_t inter) {
+    mFirstTimeStamp = rtpTime;
+    mLastTimeStamp = rtpTime;
+    mFirstArrivalTimeUs = arrivalTimeUs;
+    mLastArrivalTimeUs = arrivalTimeUs;
+
+    mBaseJitterUs = base;
+    mInterArrivalJitterUs = inter;
 }
 
-void JitterCalc::putData(int64_t rtpTime, int64_t arrivalTimeUs) {
-    if (mLastTimeStamp == 0) {
-        mLastTimeStamp = rtpTime;
-        mLastArrivalTimeUs = arrivalTimeUs;
-    }
-
+void JitterCalc::putBaseData(int64_t rtpTime, int64_t arrivalTimeUs) {
+    // A RTP time wraps around after UINT32_MAX. We must consider this case.
     const int64_t UINT32_MSB = 0x80000000;
+    int64_t overflowMask = (mFirstTimeStamp & UINT32_MSB & ~rtpTime) << 1;
+    int64_t tempRtpTime = overflowMask | rtpTime;
+
+    // Base jitter implementation can be various
+    int64_t scheduledTimeUs = (tempRtpTime - (int64_t)mFirstTimeStamp) * 1000000ll / mClockRate;
+    int64_t elapsedTimeUs = arrivalTimeUs - mFirstArrivalTimeUs;
+    int64_t correctionTimeUs = elapsedTimeUs - scheduledTimeUs; // additional propagation delay;
+    mBaseJitterUs = (mBaseJitterUs * 15 + correctionTimeUs) / 16;
+    ALOGV("BaseJitterUs : %lld \t\t correctionTimeUs : %lld",
+            (long long)mBaseJitterUs, (long long)correctionTimeUs);
+}
+
+void JitterCalc::putInterArrivalData(int64_t rtpTime, int64_t arrivalTimeUs) {
+    const int64_t UINT32_MSB = 0x80000000;
+    int64_t tempRtpTime = rtpTime;
     int64_t tempLastTimeStamp = mLastTimeStamp;
+
     // A RTP time wraps around after UINT32_MAX. We must consider this case.
     int64_t overflowMask = (mLastTimeStamp ^ rtpTime) & UINT32_MSB;
-    rtpTime |= ((overflowMask & ~rtpTime) << 1);
+    tempRtpTime |= ((overflowMask & ~rtpTime) << 1);
     tempLastTimeStamp |= ((overflowMask & ~mLastTimeStamp) << 1);
-    ALOGV("Raw stamp \t\t now %llx \t\t last %llx",
-            (long long)rtpTime, (long long)tempLastTimeStamp);
-
-    int64_t diffTimeStampUs = abs(rtpTime - tempLastTimeStamp) * 1000000ll / mClockRate;
-    int64_t diffArrivalUs = abs(arrivalTimeUs - mLastArrivalTimeUs);
-    ALOGV("diffTimeStampus %lld \t\t diffArrivalUs %lld",
-            (long long)diffTimeStampUs, (long long)diffArrivalUs);
 
     // 6.4.1 of RFC3550 defines this interarrival jitter value.
-    mJitterValueUs = (mJitterValueUs * 15 + abs(diffTimeStampUs - diffArrivalUs)) / 16;
-    ALOGV("JitterUs %lld", (long long)mJitterValueUs);
+    int64_t diffTimeStampUs = abs(tempRtpTime - tempLastTimeStamp) * 1000000ll / mClockRate;
+    int64_t diffArrivalUs = arrivalTimeUs - mLastArrivalTimeUs; // Can't be minus
+    ALOGV("diffTimeStampUs %lld \t\t diffArrivalUs %lld",
+            (long long)diffTimeStampUs, (long long)diffArrivalUs);
+
+    int64_t varianceUs = diffArrivalUs - diffTimeStampUs;
+    mInterArrivalJitterUs = (mInterArrivalJitterUs * 15 + abs(varianceUs)) / 16;
 
     mLastTimeStamp = (uint32_t)rtpTime;
     mLastArrivalTimeUs = arrivalTimeUs;
 }
 
-uint32_t JitterCalc::getJitterMs() {
-    return mJitterValueUs / 1000;
+int32_t JitterCalc::getBaseJitterMs() {
+    return mBaseJitterUs / 1000;
+}
+
+int32_t JitterCalc::getInterArrivalJitterMs() {
+    return mInterArrivalJitterUs / 1000;
 }
 
 }   // namespace android
diff --git a/media/libstagefright/rtsp/JitterCalculator.h b/media/libstagefright/rtsp/JitterCalculator.h
index 03e43ff..ff36f1f 100644
--- a/media/libstagefright/rtsp/JitterCalculator.h
+++ b/media/libstagefright/rtsp/JitterCalculator.h
@@ -28,15 +28,22 @@
     // Time Stamp per Second
     const int32_t mClockRate;
 
-    uint32_t mJitterValueUs;
+    uint32_t mFirstTimeStamp;
     uint32_t mLastTimeStamp;
+    int64_t mFirstArrivalTimeUs;
     int64_t mLastArrivalTimeUs;
 
-    void init();
+    int32_t mBaseJitterUs;
+    int32_t mInterArrivalJitterUs;
+
 public:
     JitterCalc(int32_t clockRate);
-    void putData(int64_t rtpTime, int64_t arrivalTime);
-    uint32_t getJitterMs();
+
+    void init(uint32_t rtpTime, int64_t arrivalTimeUs, int32_t base, int32_t inter);
+    void putInterArrivalData(int64_t rtpTime, int64_t arrivalTime);
+    void putBaseData(int64_t rtpTime, int64_t arrivalTimeUs);
+    int32_t getBaseJitterMs();
+    int32_t getInterArrivalJitterMs();
 };
 
 }   // namespace android
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
index a628c70..c251479 100644
--- a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
@@ -42,7 +42,7 @@
     if (isVideoDecoder) {
         decoder = new VideoFrameDecoder(componentName, trackMeta, source);
     } else {
-        decoder = new ImageDecoder(componentName, trackMeta, source);
+        decoder = new MediaImageDecoder(componentName, trackMeta, source);
     }
 
     while (fdp.remaining_bytes()) {
@@ -80,4 +80,3 @@
 }
 
 }  // namespace android
-
diff --git a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
index 969c6e1..97d1160 100644
--- a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
@@ -17,7 +17,7 @@
 //          dylan.katz@leviathansecurity.com
 
 #include <android-base/file.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <ctype.h>
 #include <media/mediarecorder.h>
 #include <media/stagefright/MPEG4Writer.h>
@@ -40,7 +40,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 std::string getFourCC(FuzzedDataProvider *fdp) {
     std::string fourCC = fdp->ConsumeRandomLengthString(4);
@@ -166,11 +166,12 @@
     StandardWriters writerType = dataProvider.ConsumeEnum<StandardWriters>();
     sp<MediaWriter> writer = createWriter(tf.fd, writerType, fileMeta);
 
-    Identity i;
-    i.packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
-    i.uid = dataProvider.ConsumeIntegral<int32_t>();
-    i.pid = dataProvider.ConsumeIntegral<int32_t>();
-    sp<MediaRecorder> mr = new MediaRecorder(i);
+    AttributionSourceState attributionSource;
+    attributionSource.packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
+    attributionSource.uid = dataProvider.ConsumeIntegral<int32_t>();
+    attributionSource.pid = dataProvider.ConsumeIntegral<int32_t>();
+    attributionSource.token = sp<BBinder>::make();
+    sp<MediaRecorder> mr = new MediaRecorder(attributionSource);
     writer->setListener(mr);
 
     uint8_t baseOpLen = operations.size();
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 3ceacfe..32a22ba 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -40,7 +40,7 @@
         "libstagefright_foundation",
         "libutils",
         "liblog",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     header_libs: [
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index a9617ec..e25658f 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -52,9 +52,12 @@
         "frameworks/av/services/mediaresourcemanager",
     ],
 
-    // mediaserver has only been verified on 32-bit, see b/126502613
-    // use "prefer32" to *only* enable 64-bit builds on 64-bit-only lunch
-    // targets, which allows them to reach 'boot_complete'.
+    // By default mediaserver runs in 32-bit to save memory, except
+    // on 64-bit-only lunch targets.
+    // ****************************************************************
+    // TO ENABLE 64-BIT MEDIASERVER ON MIXED 32/64-BIT DEVICES, COMMENT
+    // OUT THE FOLLOWING LINE:
+    // ****************************************************************
     compile_multilib: "prefer32",
 
     init_rc: ["mediaserver.rc"],
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 9665c58..5be8ef5 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -608,6 +608,32 @@
     return NULL;
 }
 
+bool MtpDevice::setDevicePropValueStr(MtpProperty* property) {
+    if (property == nullptr)
+        return false;
+
+    std::lock_guard<std::mutex> lg(mMutex);
+
+    if (property->getDataType() != MTP_TYPE_STR) {
+        return false;
+    }
+
+    mRequest.reset();
+    mRequest.setParameter(1, property->getPropertyCode());
+
+    mData.reset();
+    mData.putString(property->getCurrentValue().str);
+
+   if (sendRequest(MTP_OPERATION_SET_DEVICE_PROP_VALUE) && sendData()) {
+        MtpResponseCode ret = readResponse();
+        if (ret != MTP_RESPONSE_OK) {
+            ALOGW("%s: Response=0x%04X\n", __func__, ret);
+            return false;
+        }
+    }
+    return true;
+}
+
 MtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
     std::lock_guard<std::mutex> lg(mMutex);
 
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 01bc3db..b1b30e4 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -112,6 +112,7 @@
     MtpObjectPropertyList*  getObjectPropsSupported(MtpObjectFormat format);
 
     MtpProperty*            getDevicePropDesc(MtpDeviceProperty code);
+    bool                    setDevicePropValueStr(MtpProperty* property);
     MtpProperty*            getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
 
     // Reads value of |property| for |handle|. Returns true on success.
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index c8b4a03..2ffd775 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -74,6 +74,7 @@
 
 MtpFfsHandle::MtpFfsHandle(int controlFd) {
     mControl.reset(controlFd);
+    mBatchCancel = android::base::GetBoolProperty("sys.usb.mtp.batchcancel", false);
 }
 
 MtpFfsHandle::~MtpFfsHandle() {}
@@ -370,7 +371,7 @@
 }
 
 int MtpFfsHandle::cancelEvents(struct iocb **iocb, struct io_event *events, unsigned start,
-        unsigned end) {
+        unsigned end, bool is_batch_cancel) {
     // Some manpages for io_cancel are out of date and incorrect.
     // io_cancel will return -EINPROGRESS on success and does
     // not place the event in the given memory. We have to use
@@ -386,6 +387,10 @@
         } else {
             num_events++;
         }
+        if (is_batch_cancel && num_events == 1) {
+            num_events = end - start;
+            break;
+        }
     }
     if (num_events != end - start) {
         ret = -1;
@@ -495,7 +500,8 @@
                 num_events += this_events;
 
                 if (event_ret == -1) {
-                    cancelEvents(mIobuf[i].iocb.data(), ioevs, num_events, mIobuf[i].actual);
+                    cancelEvents(mIobuf[i].iocb.data(), ioevs, num_events, mIobuf[i].actual,
+                            mBatchCancel);
                     return -1;
                 }
                 ret += event_ret;
@@ -512,7 +518,8 @@
                 }
             }
             if (short_packet) {
-                if (cancelEvents(mIobuf[i].iocb.data(), ioevs, short_i, mIobuf[i].actual)) {
+                if (cancelEvents(mIobuf[i].iocb.data(), ioevs, short_i, mIobuf[i].actual,
+                        mBatchCancel)) {
                     write_error = true;
                 }
             }
@@ -613,7 +620,7 @@
                         &num_events) != ret) {
                 error = true;
                 cancelEvents(mIobuf[(i-1)%NUM_IO_BUFS].iocb.data(), ioevs, num_events,
-                        mIobuf[(i-1)%NUM_IO_BUFS].actual);
+                        mIobuf[(i-1)%NUM_IO_BUFS].actual, false);
             }
             has_write = false;
         }
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index fe343f7..e552e03 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -17,6 +17,7 @@
 #ifndef _MTP_FFS_HANDLE_H
 #define _MTP_FFS_HANDLE_H
 
+#include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 #include <linux/aio_abi.h>
 #include <mutex>
@@ -57,6 +58,7 @@
     static int getPacketSize(int ffs_fd);
 
     bool mCanceled;
+    bool mBatchCancel;
 
     android::base::unique_fd mControl;
     // "in" from the host's perspective => sink for mtp server
@@ -76,7 +78,8 @@
     int iobufSubmit(struct io_buffer *buf, int fd, unsigned length, bool read);
 
     // Cancel submitted requests from start to end in the given array. Return 0 or -1.
-    int cancelEvents(struct iocb **iocb, struct io_event *events, unsigned start, unsigned end);
+    int cancelEvents(struct iocb **iocb, struct io_event *events, unsigned start, unsigned end,
+		     bool is_batch_cancel);
 
     // Wait for at minimum the given number of events. Returns the amount of data in the returned
     // events. Increments counter by the number of events returned.
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
index 3b298a9..f069a83 100644
--- a/media/mtp/MtpPacket.cpp
+++ b/media/mtp/MtpPacket.cpp
@@ -157,7 +157,7 @@
                             request->endpoint,
                             request->buffer,
                             request->buffer_length,
-                            1000);
+                            5000);
     request->actual_length = result;
     return result;
 }
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index 5c02a0d..98a2ad3 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -240,6 +240,16 @@
         mCurrentValue.str = NULL;
 }
 
+void MtpProperty::setCurrentValue(const char* string) {
+    free(mCurrentValue.str);
+    if (string) {
+        MtpStringBuffer buffer(string);
+        mCurrentValue.str = strdup(buffer);
+    }
+    else
+        mCurrentValue.str = NULL;
+}
+
 void MtpProperty::setCurrentValue(MtpDataPacket& packet) {
     free(mCurrentValue.str);
     mCurrentValue.str = NULL;
diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h
index bfd5f7f..36d7360 100644
--- a/media/mtp/MtpProperty.h
+++ b/media/mtp/MtpProperty.h
@@ -91,6 +91,7 @@
 
     void                setDefaultValue(const uint16_t* string);
     void                setCurrentValue(const uint16_t* string);
+    void                setCurrentValue(const char* string);
     void                setCurrentValue(MtpDataPacket& packet);
     const MtpPropertyValue& getCurrentValue() { return mCurrentValue; }
 
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index becbe6e..6fcf119 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -794,18 +794,28 @@
     struct stat sstat;
     uint64_t finalsize;
     bool transcode = android::base::GetBoolProperty("sys.fuse.transcode_mtp", false);
+    bool filePathAccess = true;
     ALOGD("Mtp transcode = %d", transcode);
-    mfr.fd = mDatabase->openFilePath(filePath, transcode);
-    // Doing this here because we want to update fileLength only for this case and leave the
-    // regular path as unchanged as possible.
-    if (mfr.fd >= 0) {
+
+    // For performance reasons, only attempt a ContentResolver open when transcode is required.
+    // This is fine as long as we don't transcode by default on the device. If we suddenly
+    // transcode by default, we'll need to ensure that MTP doesn't transcode by default and we
+    // might need to make a binder call to avoid transcoding or come up with a better strategy.
+    if (transcode) {
+        mfr.fd = mDatabase->openFilePath(filePath, true);
         fstat(mfr.fd, &sstat);
         finalsize = sstat.st_size;
         fileLength = finalsize;
-    } else {
-        ALOGW("Mtp open via IMtpDatabase failed for %s. Falling back to the original",
-                filePath);
+        if (mfr.fd < 0) {
+            ALOGW("Mtp open via IMtpDatabase failed for %s. Falling back to the original",
+                  filePath);
+            filePathAccess = true;
+        } else {
+            filePathAccess = false;
+        }
+    }
 
+    if (filePathAccess) {
         mfr.fd = open(filePath, O_RDONLY);
         if (mfr.fd < 0) {
             return MTP_RESPONSE_GENERAL_ERROR;
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 9e48c1f..bfe73d5 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -46,12 +46,11 @@
         "libbinder",
         "libcutils",
         "liblog",
-        "libpermission",
         "libutils",
         "libhidlbase",
+        "libpermission",
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hidl.token@1.0-utils",
-        "media_permission-aidl-cpp",
     ],
     export_static_lib_headers: [
         "libbatterystats_aidl",
@@ -71,7 +70,7 @@
     ],
 
     export_shared_lib_headers: [
-        "media_permission-aidl-cpp"
+        "libpermission",
     ],
 
     include_dirs: [
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index e3931b1..9c7b863 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -25,7 +25,7 @@
 #include <system/audio-hal-enums.h>
 #include <media/AidlConversion.h>
 #include <media/AidlConversionUtil.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <iterator>
 #include <algorithm>
@@ -40,7 +40,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO");
 static const String16 sModifyPhoneState("android.permission.MODIFY_PHONE_STATE");
@@ -67,7 +67,7 @@
     return packages[0];
 }
 
-static int32_t getOpForSource(audio_source_t source) {
+int32_t getOpForSource(audio_source_t source) {
   switch (source) {
     case AUDIO_SOURCE_HOTWORD:
       return AppOpsManager::OP_RECORD_AUDIO_HOTWORD;
@@ -81,92 +81,101 @@
   }
 }
 
-static bool checkRecordingInternal(const Identity& identity, const String16& msg,
-        bool start, audio_source_t source) {
+std::optional<AttributionSourceState> resolveAttributionSource(
+        const AttributionSourceState& callerAttributionSource) {
+    AttributionSourceState nextAttributionSource = callerAttributionSource;
+
+    if (!nextAttributionSource.packageName.has_value()) {
+        nextAttributionSource = AttributionSourceState(nextAttributionSource);
+        PermissionController permissionController;
+        const uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(nextAttributionSource.uid));
+        nextAttributionSource.packageName = VALUE_OR_FATAL(legacy2aidl_String16_string(
+                resolveCallingPackage(permissionController, VALUE_OR_FATAL(
+                aidl2legacy_string_view_String16(nextAttributionSource.packageName.value_or(""))),
+                uid)));
+        if (!nextAttributionSource.packageName.has_value()) {
+            return std::nullopt;
+        }
+    }
+
+    AttributionSourceState myAttributionSource;
+    myAttributionSource.uid = VALUE_OR_FATAL(android::legacy2aidl_uid_t_int32_t(getuid()));
+    myAttributionSource.pid = VALUE_OR_FATAL(android::legacy2aidl_pid_t_int32_t(getpid()));
+    myAttributionSource.token = sp<BBinder>::make();
+    myAttributionSource.next.push_back(nextAttributionSource);
+
+    return std::optional<AttributionSourceState>{myAttributionSource};
+}
+
+static bool checkRecordingInternal(const AttributionSourceState& attributionSource,
+        const String16& msg, bool start, audio_source_t source) {
     // Okay to not track in app ops as audio server or media server is us and if
     // device is rooted security model is considered compromised.
     // system_server loses its RECORD_AUDIO permission when a secondary
     // user is active, but it is a core system service so let it through.
     // TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
     if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return true;
 
     // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
-    // may open a record track on behalf of a client.  Note that pid may be a tid.
+    // may open a record track on behalf of a client. Note that pid may be a tid.
     // IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
-    PermissionController permissionController;
-    const bool ok = permissionController.checkPermission(sAndroidPermissionRecordAudio,
-            identity.pid, identity.uid);
-    if (!ok) {
-        ALOGE("Request requires %s", String8(sAndroidPermissionRecordAudio).c_str());
+    const std::optional<AttributionSourceState> resolvedAttributionSource =
+            resolveAttributionSource(attributionSource);
+    if (!resolvedAttributionSource.has_value()) {
         return false;
     }
 
-    String16 resolvedOpPackageName = resolveCallingPackage(
-            permissionController, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
-                identity.packageName.value_or(""))), uid);
-    if (resolvedOpPackageName.size() == 0) {
-        return false;
-    }
+    const int32_t attributedOpCode = getOpForSource(source);
 
-
-    AppOpsManager appOps;
-    const int32_t op = getOpForSource(source);
+    permission::PermissionChecker permissionChecker;
+    bool permitted = false;
     if (start) {
-        if (int32_t mode = appOps.startOpNoThrow(op, identity.uid,
-            resolvedOpPackageName, /*startIfModeDefault*/ false,
-            VALUE_OR_FATAL(aidl2legacy_optional_string_view_optional_String16(
-                identity.attributionTag)), msg) == AppOpsManager::MODE_ERRORED) {
-            ALOGE("Request start for \"%s\" (uid %d) denied by app op: %d, mode: %d",
-                String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
-            return false;
-        }
+        permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
+                sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
+                attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
     } else {
-        if (int32_t mode = appOps.checkOp(op, uid,
-            resolvedOpPackageName) == AppOpsManager::MODE_ERRORED) {
-            ALOGE("Request check for \"%s\" (uid %d) denied by app op: %d, mode: %d",
-                String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
-            return false;
-        }
+        permitted = (permissionChecker.checkPermissionForPreflightFromDatasource(
+                sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
+                attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
     }
 
-    return true;
+    return permitted;
 }
 
-bool recordingAllowed(const Identity& identity) {
-    return checkRecordingInternal(identity, String16(), /*start*/ false, AUDIO_SOURCE_DEFAULT);
+bool recordingAllowed(const AttributionSourceState& attributionSource, audio_source_t source) {
+    return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source);
 }
 
-bool startRecording(const Identity& identity, const String16& msg, audio_source_t source) {
-     return checkRecordingInternal(identity, msg, /*start*/ true, source);
+bool startRecording(const AttributionSourceState& attributionSource, const String16& msg,
+        audio_source_t source) {
+    return checkRecordingInternal(attributionSource, msg, /*start*/ true, source);
 }
 
-void finishRecording(const Identity& identity, audio_source_t source) {
+void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source) {
     // Okay to not track in app ops as audio server is us and if
     // device is rooted security model is considered compromised.
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    if (isAudioServerOrRootUid(uid)) return;
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return;
 
-    PermissionController permissionController;
-    String16 resolvedOpPackageName = resolveCallingPackage(
-            permissionController,
-            VALUE_OR_FATAL(aidl2legacy_string_view_String16(identity.packageName.value_or(""))),
-            VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)));
-    if (resolvedOpPackageName.size() == 0) {
+    // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
+    // may open a record track on behalf of a client. Note that pid may be a tid.
+    // IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
+    const std::optional<AttributionSourceState> resolvedAttributionSource =
+            resolveAttributionSource(attributionSource);
+    if (!resolvedAttributionSource.has_value()) {
         return;
     }
 
-    AppOpsManager appOps;
-
-    const int32_t op = getOpForSource(source);
-    appOps.finishOp(op, identity.uid, resolvedOpPackageName,
-        VALUE_OR_FATAL(aidl2legacy_optional_string_view_optional_String16(
-            identity.attributionTag)));
+    const int32_t attributedOpCode = getOpForSource(source);
+    permission::PermissionChecker permissionChecker;
+    permissionChecker.finishDataDeliveryFromDatasource(attributedOpCode,
+            resolvedAttributionSource.value());
 }
 
-bool captureAudioOutputAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool captureAudioOutputAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
     if (isAudioServerOrRootUid(uid)) return true;
     static const String16 sCaptureAudioOutput("android.permission.CAPTURE_AUDIO_OUTPUT");
     bool ok = PermissionCache::checkPermission(sCaptureAudioOutput, pid, uid);
@@ -174,9 +183,9 @@
     return ok;
 }
 
-bool captureMediaOutputAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool captureMediaOutputAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
     if (isAudioServerOrRootUid(uid)) return true;
     static const String16 sCaptureMediaOutput("android.permission.CAPTURE_MEDIA_OUTPUT");
     bool ok = PermissionCache::checkPermission(sCaptureMediaOutput, pid, uid);
@@ -184,9 +193,9 @@
     return ok;
 }
 
-bool captureTunerAudioInputAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool captureTunerAudioInputAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
     if (isAudioServerOrRootUid(uid)) return true;
     static const String16 sCaptureTunerAudioInput("android.permission.CAPTURE_TUNER_AUDIO_INPUT");
     bool ok = PermissionCache::checkPermission(sCaptureTunerAudioInput, pid, uid);
@@ -194,9 +203,9 @@
     return ok;
 }
 
-bool captureVoiceCommunicationOutputAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool captureVoiceCommunicationOutputAllowed(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 sCaptureVoiceCommOutput(
         "android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT");
@@ -205,15 +214,18 @@
     return ok;
 }
 
-bool captureHotwordAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool captureHotwordAllowed(const AttributionSourceState& attributionSource) {
     // CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
-    bool ok = recordingAllowed(identity);
+    bool ok = recordingAllowed(attributionSource);
 
     if (ok) {
         static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD");
-        ok = PermissionCache::checkPermission(sCaptureHotwordAllowed, pid, uid);
+        // Use PermissionChecker, which includes some logic for allowing the isolated
+        // HotwordDetectionService to hold certain permissions.
+        permission::PermissionChecker permissionChecker;
+        ok = (permissionChecker.checkPermissionForPreflight(
+                sCaptureHotwordAllowed, attributionSource, String16(),
+                AppOpsManager::OP_NONE) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
     }
     if (!ok) ALOGV("android.permission.CAPTURE_AUDIO_HOTWORD");
     return ok;
@@ -230,12 +242,12 @@
 }
 
 bool modifyAudioRoutingAllowed() {
-    return modifyAudioRoutingAllowed(getCallingIdentity());
+    return modifyAudioRoutingAllowed(getCallingAttributionSource());
 }
 
-bool modifyAudioRoutingAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool modifyAudioRoutingAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
     if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
     // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
     bool ok = PermissionCache::checkPermission(sModifyAudioRouting, pid, uid);
@@ -245,12 +257,12 @@
 }
 
 bool modifyDefaultAudioEffectsAllowed() {
-    return modifyDefaultAudioEffectsAllowed(getCallingIdentity());
+    return modifyDefaultAudioEffectsAllowed(getCallingAttributionSource());
 }
 
-bool modifyDefaultAudioEffectsAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool modifyDefaultAudioEffectsAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
     if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
 
     static const String16 sModifyDefaultAudioEffectsAllowed(
@@ -271,18 +283,18 @@
     return ok;
 }
 
-bool modifyPhoneStateAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool modifyPhoneStateAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
     bool ok = PermissionCache::checkPermission(sModifyPhoneState, pid, uid);
     ALOGE_IF(!ok, "Request requires %s", String8(sModifyPhoneState).c_str());
     return ok;
 }
 
 // privileged behavior needed by Dialer, Settings, SetupWizard and CellBroadcastReceiver
-bool bypassInterruptionPolicyAllowed(const Identity& identity) {
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
-    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
+bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource) {
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
     static const String16 sWriteSecureSettings("android.permission.WRITE_SECURE_SETTINGS");
     bool ok = PermissionCache::checkPermission(sModifyPhoneState, pid, uid)
         || PermissionCache::checkPermission(sWriteSecureSettings, pid, uid)
@@ -292,11 +304,14 @@
     return ok;
 }
 
-Identity getCallingIdentity() {
-  Identity identity = Identity();
-  identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
-  identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
-  return identity;
+AttributionSourceState getCallingAttributionSource() {
+    AttributionSourceState attributionSource = AttributionSourceState();
+    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(
+            IPCThreadState::self()->getCallingPid()));
+    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
+            IPCThreadState::self()->getCallingUid()));
+    attributionSource.token = sp<BBinder>::make();
+  return attributionSource;
 }
 
 void purgePermissionCache() {
diff --git a/media/utils/fuzzers/Android.bp b/media/utils/fuzzers/Android.bp
index b245834..c1698dc 100644
--- a/media/utils/fuzzers/Android.bp
+++ b/media/utils/fuzzers/Android.bp
@@ -16,7 +16,8 @@
         "liblog",
         "libmediautils",
         "libutils",
-        "media_permission-aidl-cpp",
+        "libbinder",
+        "framework-permission-aidl-cpp",
     ],
 
     cflags: [
diff --git a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
index 2f9e780..6e52512 100644
--- a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
+++ b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
@@ -17,16 +17,16 @@
 #include <fcntl.h>
 
 #include <functional>
-#include  <type_traits>
+#include <type_traits>
 
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include "fuzzer/FuzzedDataProvider.h"
 #include "mediautils/ServiceUtilities.h"
 
 static constexpr int kMaxOperations = 50;
 static constexpr int kMaxStringLen = 256;
 
-using android::media::permission::Identity;
+using android::content::AttributionSourceState;
 
 const std::vector<std::function<void(FuzzedDataProvider*, android::MediaPackageManager)>>
     operations = {
@@ -54,10 +54,11 @@
     std::string packageNameStr = data_provider.ConsumeRandomLengthString(kMaxStringLen);
     std::string msgStr = data_provider.ConsumeRandomLengthString(kMaxStringLen);
     android::String16 msgStr16(packageNameStr.c_str());
-    Identity identity;
-    identity.packageName = packageNameStr;
-    identity.uid = uid;
-    identity.pid = pid;
+    AttributionSourceState attributionSource;
+    attributionSource.packageName = packageNameStr;
+    attributionSource.uid = uid;
+    attributionSource.pid = pid;
+    attributionSource.token = android::sp<android::BBinder>::make();
 
     // There is not state here, and order is not significant,
     // so we can simply call all of the target functions
@@ -65,14 +66,14 @@
     android::isAudioServerUid(uid);
     android::isAudioServerOrSystemServerUid(uid);
     android::isAudioServerOrMediaServerUid(uid);
-    android::recordingAllowed(identity);
-    android::startRecording(identity, msgStr16, source);
-    android::finishRecording(identity, source);
-    android::captureAudioOutputAllowed(identity);
-    android::captureMediaOutputAllowed(identity);
-    android::captureHotwordAllowed(identity);
-    android::modifyPhoneStateAllowed(identity);
-    android::bypassInterruptionPolicyAllowed(identity);
+    android::recordingAllowed(attributionSource);
+    android::startRecording(attributionSource, msgStr16, source);
+    android::finishRecording(attributionSource, source);
+    android::captureAudioOutputAllowed(attributionSource);
+    android::captureMediaOutputAllowed(attributionSource);
+    android::captureHotwordAllowed(attributionSource);
+    android::modifyPhoneStateAllowed(attributionSource);
+    android::bypassInterruptionPolicyAllowed(attributionSource);
     android::settingsAllowed();
     android::modifyAudioRoutingAllowed();
     android::modifyDefaultAudioEffectsAllowed();
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 6e75746..734313c 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -25,7 +25,9 @@
 #include <cutils/multiuser.h>
 #include <private/android_filesystem_config.h>
 #include <system/audio-hal-enums.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
+#include <binder/PermissionController.h>
+#include <android/permission/PermissionChecker.h>
 
 #include <map>
 #include <optional>
@@ -35,6 +37,8 @@
 
 namespace android {
 
+using content::AttributionSourceState;
+
 // Audio permission utilities
 
 // Used for calls that should originate from system services.
@@ -80,26 +84,30 @@
     }
 }
 
-bool recordingAllowed(const media::permission::Identity& identity);
-bool startRecording(const media::permission::Identity& identity,
+bool recordingAllowed(const AttributionSourceState& attributionSource,
+        audio_source_t source = AUDIO_SOURCE_DEFAULT);
+bool startRecording(const AttributionSourceState& attributionSource,
     const String16& msg, audio_source_t source);
-void finishRecording(const media::permission::Identity& identity, audio_source_t source);
-bool captureAudioOutputAllowed(const media::permission::Identity& identity);
-bool captureMediaOutputAllowed(const media::permission::Identity& identity);
-bool captureTunerAudioInputAllowed(const media::permission::Identity& identity);
-bool captureVoiceCommunicationOutputAllowed(const media::permission::Identity& identity);
-bool captureHotwordAllowed(const media::permission::Identity& identity);
+void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source);
+std::optional<AttributionSourceState> resolveAttributionSource(
+    const AttributionSourceState& callerAttributionSource);
+bool captureAudioOutputAllowed(const AttributionSourceState& attributionSource);
+bool captureMediaOutputAllowed(const AttributionSourceState& attributionSource);
+bool captureTunerAudioInputAllowed(const AttributionSourceState& attributionSource);
+bool captureVoiceCommunicationOutputAllowed(const AttributionSourceState& attributionSource);
+bool captureHotwordAllowed(const AttributionSourceState& attributionSource);
 bool settingsAllowed();
 bool modifyAudioRoutingAllowed();
-bool modifyAudioRoutingAllowed(const media::permission::Identity& identity);
+bool modifyAudioRoutingAllowed(const AttributionSourceState& attributionSource);
 bool modifyDefaultAudioEffectsAllowed();
-bool modifyDefaultAudioEffectsAllowed(const media::permission::Identity& identity);
+bool modifyDefaultAudioEffectsAllowed(const AttributionSourceState& attributionSource);
 bool dumpAllowed();
-bool modifyPhoneStateAllowed(const media::permission::Identity& identity);
-bool bypassInterruptionPolicyAllowed(const media::permission::Identity& identity);
+bool modifyPhoneStateAllowed(const AttributionSourceState& attributionSource);
+bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource);
 void purgePermissionCache();
+int32_t getOpForSource(audio_source_t source);
 
-media::permission::Identity getCallingIdentity();
+AttributionSourceState getCallingAttributionSource();
 
 status_t checkIMemory(const sp<IMemory>& iMemory);
 
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index a7d47fb..b91f302 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -81,12 +81,12 @@
         "libmedia_helper",
         "libshmemcompat",
         "libvibrator",
-        "media_permission-aidl-cpp",
     ],
 
     static_libs: [
         "libcpustats",
         "libsndfile",
+        "libpermission",
     ],
 
     header_libs: [
@@ -97,7 +97,6 @@
 
     export_shared_lib_headers: [
         "libpermission",
-        "media_permission-aidl-cpp",
     ],
 
     cflags: [
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 3562b00..54a6425 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -103,7 +103,7 @@
 namespace android {
 
 using media::IEffectClient;
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
 static const char kHardwareLockedString[] = "Hardware lock is taken\n";
@@ -163,31 +163,32 @@
     }
 };
 
-// TODO b/182392769: use identity util
+// TODO b/182392769: use attribution source util
 /* static */
-media::permission::Identity AudioFlinger::checkIdentityPackage(
-        const media::permission::Identity& identity) {
+AttributionSourceState AudioFlinger::checkAttributionSourcePackage(
+        const AttributionSourceState& attributionSource) {
     Vector<String16> packages;
-    PermissionController{}.getPackagesForUid(identity.uid, packages);
+    PermissionController{}.getPackagesForUid(attributionSource.uid, packages);
 
-    Identity checkedIdentity = identity;
-    if (!identity.packageName.has_value() || identity.packageName.value().size() == 0) {
+    AttributionSourceState checkedAttributionSource = attributionSource;
+    if (!attributionSource.packageName.has_value()
+            || attributionSource.packageName.value().size() == 0) {
         if (!packages.isEmpty()) {
-            checkedIdentity.packageName =
+            checkedAttributionSource.packageName =
                 std::move(legacy2aidl_String16_string(packages[0]).value());
         }
     } else {
         String16 opPackageLegacy = VALUE_OR_FATAL(
-            aidl2legacy_string_view_String16(identity.packageName.value_or("")));
+            aidl2legacy_string_view_String16(attributionSource.packageName.value_or("")));
         if (std::find_if(packages.begin(), packages.end(),
                 [&opPackageLegacy](const auto& package) {
                 return opPackageLegacy == package; }) == packages.end()) {
             ALOGW("The package name(%s) provided does not correspond to the uid %d",
-                    identity.packageName.value_or("").c_str(), identity.uid);
-            checkedIdentity.packageName = std::optional<std::string>();
+                    attributionSource.packageName.value_or("").c_str(), attributionSource.uid);
+            checkedAttributionSource.packageName = std::optional<std::string>();
         }
     }
-    return checkedIdentity;
+    return checkedAttributionSource;
 }
 
 // ----------------------------------------------------------------------------
@@ -236,11 +237,12 @@
     timespec ts{};
     clock_gettime(CLOCK_MONOTONIC, &ts);
     // zero ID has a special meaning, so start allocation at least at AUDIO_UNIQUE_ID_USE_MAX
-    uint32_t sessionBase = (uint32_t)std::max((long)1, ts.tv_sec);
+    uint32_t movingBase = (uint32_t)std::max((long)1, ts.tv_sec);
     // unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
     for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use < AUDIO_UNIQUE_ID_USE_MAX; use++) {
         mNextUniqueIds[use] =
-                ((use == AUDIO_UNIQUE_ID_USE_SESSION) ? sessionBase : 1) * AUDIO_UNIQUE_ID_USE_MAX;
+                ((use == AUDIO_UNIQUE_ID_USE_SESSION || use == AUDIO_UNIQUE_ID_USE_CLIENT) ?
+                        movingBase : 1) * AUDIO_UNIQUE_ID_USE_MAX;
     }
 
 #if 1
@@ -312,6 +314,27 @@
     return NO_ERROR;
 }
 
+status_t AudioFlinger::updateSecondaryOutputs(
+        const TrackSecondaryOutputsMap& trackSecondaryOutputs) {
+    Mutex::Autolock _l(mLock);
+    for (const auto& [trackId, secondaryOutputs] : trackSecondaryOutputs) {
+        size_t i = 0;
+        for (; i < mPlaybackThreads.size(); ++i) {
+            PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+            Mutex::Autolock _tl(thread->mLock);
+            sp<PlaybackThread::Track> track = thread->getTrackById_l(trackId);
+            if (track != nullptr) {
+                ALOGD("%s trackId: %u", __func__, trackId);
+                updateSecondaryOutputsForTrack_l(track.get(), thread, secondaryOutputs);
+                break;
+            }
+        }
+        ALOGW_IF(i >= mPlaybackThreads.size(),
+                 "%s cannot find track with id %u", __func__, trackId);
+    }
+    return NO_ERROR;
+}
+
 // getDefaultVibratorInfo_l must be called with AudioFlinger lock held.
 const media::AudioVibratorInfo* AudioFlinger::getDefaultVibratorInfo_l() {
     if (mAudioVibratorInfos.empty()) {
@@ -409,7 +432,7 @@
 
         ret = AudioSystem::getOutputForAttr(&localAttr, &io,
                                             actualSessionId,
-                                            &streamType, client.identity,
+                                            &streamType, client.attributionSource,
                                             &fullConfig,
                                             (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
                                                     AUDIO_OUTPUT_FLAG_DIRECT),
@@ -420,7 +443,7 @@
         ret = AudioSystem::getInputForAttr(&localAttr, &io,
                                               RECORD_RIID_INVALID,
                                               actualSessionId,
-                                              client.identity,
+                                              client.attributionSource,
                                               config,
                                               AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId);
     }
@@ -826,21 +849,21 @@
 
     // TODO b/182392553: refactor or make clearer
     pid_t clientPid =
-        VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(input.clientInfo.identity.pid));
+        VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(input.clientInfo.attributionSource.pid));
     bool updatePid = (clientPid == (pid_t)-1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     uid_t clientUid =
-        VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(input.clientInfo.identity.uid));
+        VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(input.clientInfo.attributionSource.uid));
     audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE;
     std::vector<int> effectIds;
     audio_attributes_t localAttr = input.attr;
 
-    Identity adjIdentity = input.clientInfo.identity;
+    AttributionSourceState adjAttributionSource = input.clientInfo.attributionSource;
     if (!isAudioServerOrMediaServerUid(callingUid)) {
         ALOGW_IF(clientUid != callingUid,
                 "%s uid %d tried to pass itself off as %d",
                 __FUNCTION__, callingUid, clientUid);
-        adjIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+        adjAttributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
         clientUid = callingUid;
         updatePid = true;
     }
@@ -850,7 +873,7 @@
                  "%s uid %d pid %d tried to pass itself off as pid %d",
                  __func__, callingUid, callingPid, clientPid);
         clientPid = callingPid;
-        adjIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
+        adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
     }
 
     audio_session_t sessionId = input.sessionId;
@@ -865,7 +888,7 @@
     output.outputId = AUDIO_IO_HANDLE_NONE;
     output.selectedDeviceId = input.selectedDeviceId;
     lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
-                                            adjIdentity, &input.config, input.flags,
+                                            adjAttributionSource, &input.config, input.flags,
                                             &output.selectedDeviceId, &portId, &secondaryOutputs);
 
     if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
@@ -930,7 +953,7 @@
                                       &output.frameCount, &output.notificationFrameCount,
                                       input.notificationsPerBuffer, input.speed,
                                       input.sharedBuffer, sessionId, &output.flags,
-                                      callingPid, adjIdentity, input.clientInfo.clientTid,
+                                      callingPid, adjAttributionSource, input.clientInfo.clientTid,
                                       &lStatus, portId, input.audioTrackCallback);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
         // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
@@ -944,88 +967,7 @@
             // Connect secondary outputs. Failure on a secondary output must not imped the primary
             // Any secondary output setup failure will lead to a desync between the AP and AF until
             // the track is destroyed.
-            TeePatches teePatches;
-            for (audio_io_handle_t secondaryOutput : secondaryOutputs) {
-                PlaybackThread *secondaryThread = checkPlaybackThread_l(secondaryOutput);
-                if (secondaryThread == NULL) {
-                    ALOGE("no playback thread found for secondary output %d", output.outputId);
-                    continue;
-                }
-
-                size_t sourceFrameCount = thread->frameCount() * output.sampleRate
-                                          / thread->sampleRate();
-                size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate
-                                          / secondaryThread->sampleRate();
-                // If the secondary output has just been opened, the first secondaryThread write
-                // will not block as it will fill the empty startup buffer of the HAL,
-                // so a second sink buffer needs to be ready for the immediate next blocking write.
-                // Additionally, have a margin of one main thread buffer as the scheduling jitter
-                // can reorder the writes (eg if thread A&B have the same write intervale,
-                // the scheduler could schedule AB...BA)
-                size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
-                // Total secondary output buffer must be at least as the read frames plus
-                // the margin of a few buffers on both sides in case the
-                // threads scheduling has some jitter.
-                // That value should not impact latency as the secondary track is started before
-                // its buffer is full, see frameCountToBeReady.
-                size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
-                // The frameCount should also not be smaller than the secondary thread min frame
-                // count
-                size_t minFrameCount = AudioSystem::calculateMinFrameCount(
-                            [&] { Mutex::Autolock _l(secondaryThread->mLock);
-                                  return secondaryThread->latency_l(); }(),
-                            secondaryThread->mNormalFrameCount,
-                            secondaryThread->mSampleRate,
-                            output.sampleRate,
-                            input.speed);
-                frameCount = std::max(frameCount, minFrameCount);
-
-                using namespace std::chrono_literals;
-                auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask);
-                sp patchRecord = new RecordThread::PatchRecord(nullptr /* thread */,
-                                                               output.sampleRate,
-                                                               inChannelMask,
-                                                               input.config.format,
-                                                               frameCount,
-                                                               NULL /* buffer */,
-                                                               (size_t)0 /* bufferSize */,
-                                                               AUDIO_INPUT_FLAG_DIRECT,
-                                                               0ns /* timeout */);
-                status_t status = patchRecord->initCheck();
-                if (status != NO_ERROR) {
-                    ALOGE("Secondary output patchRecord init failed: %d", status);
-                    continue;
-                }
-
-                // TODO: We could check compatibility of the secondaryThread with the PatchTrack
-                // for fast usage: thread has fast mixer, sample rate matches, etc.;
-                // for now, we exclude fast tracks by removing the Fast flag.
-                const audio_output_flags_t outputFlags =
-                        (audio_output_flags_t)(output.flags & ~AUDIO_OUTPUT_FLAG_FAST);
-                sp patchTrack = new PlaybackThread::PatchTrack(secondaryThread,
-                                                               streamType,
-                                                               output.sampleRate,
-                                                               input.config.channel_mask,
-                                                               input.config.format,
-                                                               frameCount,
-                                                               patchRecord->buffer(),
-                                                               patchRecord->bufferSize(),
-                                                               outputFlags,
-                                                               0ns /* timeout */,
-                                                               frameCountToBeReady);
-                status = patchTrack->initCheck();
-                if (status != NO_ERROR) {
-                    ALOGE("Secondary output patchTrack init failed: %d", status);
-                    continue;
-                }
-                teePatches.push_back({patchRecord, patchTrack});
-                secondaryThread->addPatchTrack(patchTrack);
-                // In case the downstream patchTrack on the secondaryThread temporarily outlives
-                // our created track, ensure the corresponding patchRecord is still alive.
-                patchTrack->setPeerProxy(patchRecord, true /* holdReference */);
-                patchRecord->setPeerProxy(patchTrack, false /* holdReference */);
-            }
-            track->setTeePatches(std::move(teePatches));
+            updateSecondaryOutputsForTrack_l(track.get(), thread, secondaryOutputs);
         }
 
         // move effect chain to this output thread if an effect on same session was waiting
@@ -2090,24 +2032,26 @@
     output.inputId = AUDIO_IO_HANDLE_NONE;
 
     // TODO b/182392553: refactor or clean up
-    Identity adjIdentity = input.clientInfo.identity;
-    bool updatePid = (adjIdentity.pid == -1);
+    AttributionSourceState adjAttributionSource = input.clientInfo.attributionSource;
+    bool updatePid = (adjAttributionSource.pid == -1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    const uid_t currentUid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(adjIdentity.uid));
+    const uid_t currentUid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(
+           adjAttributionSource.uid));
     if (!isAudioServerOrMediaServerUid(callingUid)) {
         ALOGW_IF(currentUid != callingUid,
                 "%s uid %d tried to pass itself off as %d",
                 __FUNCTION__, callingUid, currentUid);
-        adjIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+        adjAttributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
         updatePid = true;
     }
     const pid_t callingPid = IPCThreadState::self()->getCallingPid();
-    const pid_t currentPid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(adjIdentity.pid));
+    const pid_t currentPid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(
+            adjAttributionSource.pid));
     if (updatePid) {
         ALOGW_IF(currentPid != (pid_t)-1 && currentPid != callingPid,
                  "%s uid %d pid %d tried to pass itself off as pid %d",
                  __func__, callingUid, callingPid, currentPid);
-        adjIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
+        adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
     }
 
     // we don't yet support anything other than linear PCM
@@ -2135,7 +2079,7 @@
     output.selectedDeviceId = input.selectedDeviceId;
     output.flags = input.flags;
 
-    client = registerPid(VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(adjIdentity.pid)));
+    client = registerPid(VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(adjAttributionSource.pid)));
 
     // Not a conventional loop, but a retry loop for at most two iterations total.
     // Try first maybe with FAST flag then try again without FAST flag if that fails.
@@ -2155,7 +2099,7 @@
                                       input.riid,
                                       sessionId,
                                     // FIXME compare to AudioTrack
-                                      adjIdentity,
+                                      adjAttributionSource,
                                       &input.config,
                                       output.flags, &output.selectedDeviceId, &portId);
     if (lStatus != NO_ERROR) {
@@ -2182,7 +2126,7 @@
                                                   input.config.format, input.config.channel_mask,
                                                   &output.frameCount, sessionId,
                                                   &output.notificationFrameCount,
-                                                  callingPid, adjIdentity, &output.flags,
+                                                  callingPid, adjAttributionSource, &output.flags,
                                                   input.clientInfo.clientTid,
                                                   &lStatus, portId, input.maxSharedAudioHistoryMs);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
@@ -2952,8 +2896,8 @@
         audio_is_linear_pcm(config->format) &&
         audio_is_linear_pcm(halconfig.format) &&
         (halconfig.sample_rate <= AUDIO_RESAMPLER_DOWN_RATIO_MAX * config->sample_rate) &&
-        (audio_channel_count_from_in_mask(halconfig.channel_mask) <= FCC_8) &&
-        (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_8)) {
+        (audio_channel_count_from_in_mask(halconfig.channel_mask) <= FCC_LIMIT) &&
+        (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_LIMIT)) {
         // FIXME describe the change proposed by HAL (save old values so we can log them here)
         ALOGV("openInput_l() reopening with proposed sampling rate and channel mask");
         inStream.clear();
@@ -3441,6 +3385,94 @@
     return nullptr;
 }
 
+void AudioFlinger::updateSecondaryOutputsForTrack_l(
+        PlaybackThread::Track* track,
+        PlaybackThread* thread,
+        const std::vector<audio_io_handle_t> &secondaryOutputs) const {
+    TeePatches teePatches;
+    for (audio_io_handle_t secondaryOutput : secondaryOutputs) {
+        PlaybackThread *secondaryThread = checkPlaybackThread_l(secondaryOutput);
+        if (secondaryThread == nullptr) {
+            ALOGE("no playback thread found for secondary output %d", thread->id());
+            continue;
+        }
+
+        size_t sourceFrameCount = thread->frameCount() * track->sampleRate()
+                                  / thread->sampleRate();
+        size_t sinkFrameCount = secondaryThread->frameCount() * track->sampleRate()
+                                  / secondaryThread->sampleRate();
+        // If the secondary output has just been opened, the first secondaryThread write
+        // will not block as it will fill the empty startup buffer of the HAL,
+        // so a second sink buffer needs to be ready for the immediate next blocking write.
+        // Additionally, have a margin of one main thread buffer as the scheduling jitter
+        // can reorder the writes (eg if thread A&B have the same write intervale,
+        // the scheduler could schedule AB...BA)
+        size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
+        // Total secondary output buffer must be at least as the read frames plus
+        // the margin of a few buffers on both sides in case the
+        // threads scheduling has some jitter.
+        // That value should not impact latency as the secondary track is started before
+        // its buffer is full, see frameCountToBeReady.
+        size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
+        // The frameCount should also not be smaller than the secondary thread min frame
+        // count
+        size_t minFrameCount = AudioSystem::calculateMinFrameCount(
+                    [&] { Mutex::Autolock _l(secondaryThread->mLock);
+                          return secondaryThread->latency_l(); }(),
+                    secondaryThread->mNormalFrameCount,
+                    secondaryThread->mSampleRate,
+                    track->sampleRate(),
+                    track->getSpeed());
+        frameCount = std::max(frameCount, minFrameCount);
+
+        using namespace std::chrono_literals;
+        auto inChannelMask = audio_channel_mask_out_to_in(track->channelMask());
+        sp patchRecord = new RecordThread::PatchRecord(nullptr /* thread */,
+                                                       track->sampleRate(),
+                                                       inChannelMask,
+                                                       track->format(),
+                                                       frameCount,
+                                                       nullptr /* buffer */,
+                                                       (size_t)0 /* bufferSize */,
+                                                       AUDIO_INPUT_FLAG_DIRECT,
+                                                       0ns /* timeout */);
+        status_t status = patchRecord->initCheck();
+        if (status != NO_ERROR) {
+            ALOGE("Secondary output patchRecord init failed: %d", status);
+            continue;
+        }
+
+        // TODO: We could check compatibility of the secondaryThread with the PatchTrack
+        // for fast usage: thread has fast mixer, sample rate matches, etc.;
+        // for now, we exclude fast tracks by removing the Fast flag.
+        const audio_output_flags_t outputFlags =
+                (audio_output_flags_t)(track->getOutputFlags() & ~AUDIO_OUTPUT_FLAG_FAST);
+        sp patchTrack = new PlaybackThread::PatchTrack(secondaryThread,
+                                                       track->streamType(),
+                                                       track->sampleRate(),
+                                                       track->channelMask(),
+                                                       track->format(),
+                                                       frameCount,
+                                                       patchRecord->buffer(),
+                                                       patchRecord->bufferSize(),
+                                                       outputFlags,
+                                                       0ns /* timeout */,
+                                                       frameCountToBeReady);
+        status = patchTrack->initCheck();
+        if (status != NO_ERROR) {
+            ALOGE("Secondary output patchTrack init failed: %d", status);
+            continue;
+        }
+        teePatches.push_back({patchRecord, patchTrack});
+        secondaryThread->addPatchTrack(patchTrack);
+        // In case the downstream patchTrack on the secondaryThread temporarily outlives
+        // our created track, ensure the corresponding patchRecord is still alive.
+        patchTrack->setPeerProxy(patchRecord, true /* holdReference */);
+        patchRecord->setPeerProxy(patchTrack, false /* holdReference */);
+    }
+    track->setTeePatches(std::move(teePatches));
+}
+
 sp<AudioFlinger::SyncEvent> AudioFlinger::createSyncEvent(AudioSystem::sync_event_t type,
                                     audio_session_t triggerSession,
                                     audio_session_t listenerSession,
@@ -3577,7 +3609,7 @@
     const int32_t priority = request.priority;
     const AudioDeviceTypeAddr device = VALUE_OR_RETURN_STATUS(
             aidl2legacy_AudioDeviceTypeAddress(request.device));
-    Identity adjIdentity = request.identity;
+    AttributionSourceState adjAttributionSource = request.attributionSource;
     const audio_session_t sessionId = VALUE_OR_RETURN_STATUS(
             aidl2legacy_int32_t_audio_session_t(request.sessionId));
     audio_io_handle_t io = VALUE_OR_RETURN_STATUS(
@@ -3595,19 +3627,20 @@
 
     // TODO b/182392553: refactor or make clearer
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    adjIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
-    pid_t currentPid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(adjIdentity.pid));
+    adjAttributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+    pid_t currentPid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(adjAttributionSource.pid));
     if (currentPid == -1 || !isAudioServerOrMediaServerUid(callingUid)) {
         const pid_t callingPid = IPCThreadState::self()->getCallingPid();
         ALOGW_IF(currentPid != -1 && currentPid != callingPid,
                  "%s uid %d pid %d tried to pass itself off as pid %d",
                  __func__, callingUid, callingPid, currentPid);
-        adjIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
+        adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
         currentPid = callingPid;
     }
 
     ALOGV("createEffect pid %d, effectClient %p, priority %d, sessionId %d, io %d, factory %p",
-          adjIdentity.pid, effectClient.get(), priority, sessionId, io, mEffectsFactoryHal.get());
+          adjAttributionSource.pid, effectClient.get(), priority, sessionId, io,
+          mEffectsFactoryHal.get());
 
     if (mEffectsFactoryHal == 0) {
         ALOGE("%s: no effects factory hal", __func__);
@@ -3635,7 +3668,7 @@
             goto Exit;
         }
     } else if (sessionId == AUDIO_SESSION_DEVICE) {
-        if (!modifyDefaultAudioEffectsAllowed(adjIdentity)) {
+        if (!modifyDefaultAudioEffectsAllowed(adjAttributionSource)) {
             ALOGE("%s: device effect permission denied for uid %d", __func__, callingUid);
             lStatus = PERMISSION_DENIED;
             goto Exit;
@@ -3680,7 +3713,7 @@
         // check recording permission for visualizer
         if ((memcmp(&descOut.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
             // TODO: Do we need to start/stop op - i.e. is there recording being performed?
-            !recordingAllowed(adjIdentity)) {
+            !recordingAllowed(adjAttributionSource)) {
             lStatus = PERMISSION_DENIED;
             goto Exit;
         }
@@ -3963,7 +3996,7 @@
         // if the move request is not received from audio policy manager, the effect must be
         // re-registered with the new strategy and output
         if (dstChain == 0) {
-            dstChain = effect->callback()->chain().promote();
+            dstChain = effect->getCallback()->chain().promote();
             if (dstChain == 0) {
                 ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
                 status = NO_INIT;
@@ -4013,7 +4046,7 @@
             goto Exit;
         }
 
-        dstChain = effect->callback()->chain().promote();
+        dstChain = effect->getCallback()->chain().promote();
         if (dstChain == 0) {
             thread->addEffect_l(effect);
             status = INVALID_OPERATION;
@@ -4170,7 +4203,8 @@
         case TransactionCode::SET_LOW_RAM_DEVICE:
         case TransactionCode::SYSTEM_READY:
         case TransactionCode::SET_AUDIO_HAL_PIDS:
-        case TransactionCode::SET_VIBRATOR_INFOS: {
+        case TransactionCode::SET_VIBRATOR_INFOS:
+        case TransactionCode::UPDATE_SECONDARY_OUTPUTS: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 4b03d10..fff61f8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -37,6 +37,8 @@
 #include <android/media/IAudioFlingerClient.h>
 #include <android/media/IAudioTrackCallback.h>
 #include <android/os/BnExternalVibrationController.h>
+#include <android/content/AttributionSourceState.h>
+
 
 #include <android-base/macros.h>
 #include <cutils/atomic.h>
@@ -124,13 +126,15 @@
 
 #define INCLUDING_FROM_AUDIOFLINGER_H
 
+using android::content::AttributionSourceState;
+
 class AudioFlinger : public AudioFlingerServerAdapter::Delegate
 {
 public:
     static void instantiate() ANDROID_API;
 
-    static media::permission::Identity checkIdentityPackage(
-                                            const media::permission::Identity& identity);
+    static AttributionSourceState checkAttributionSourcePackage(
+        const AttributionSourceState& attributionSource);
 
     status_t dump(int fd, const Vector<String16>& args) override;
 
@@ -272,6 +276,9 @@
 
     virtual status_t setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos);
 
+    virtual status_t updateSecondaryOutputs(
+            const TrackSecondaryOutputsMap& trackSecondaryOutputs);
+
     status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
         const std::function<status_t()>& delegate) override;
 
@@ -775,6 +782,11 @@
 
               ThreadBase *hapticPlaybackThread_l() const;
 
+              void updateSecondaryOutputsForTrack_l(
+                      PlaybackThread::Track* track,
+                      PlaybackThread* thread,
+                      const std::vector<audio_io_handle_t>& secondaryOutputs) const;
+
 
                 void        removeClient_l(pid_t pid);
                 void        removeNotificationClient(pid_t pid);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index d75b13b..b267d88 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -152,12 +152,12 @@
     if (fromHandle) {
         if (enabled) {
             if (status != NO_ERROR) {
-                mCallback->checkSuspendOnEffectEnabled(this, false, false /*threadLocked*/);
+                getCallback()->checkSuspendOnEffectEnabled(this, false, false /*threadLocked*/);
             } else {
-                mCallback->onEffectEnable(this);
+                getCallback()->onEffectEnable(this);
             }
         } else {
-            mCallback->onEffectDisable(this);
+            getCallback()->onEffectDisable(this);
         }
     }
     return status;
@@ -247,8 +247,9 @@
             doRegister = true;
             mPolicyRegistered = mHandles.size() > 0;
             if (mPolicyRegistered) {
-                io = mCallback->io();
-                strategy = mCallback->strategy();
+                const auto callback = getCallback();
+                io = callback->io();
+                strategy = callback->strategy();
             }
         }
         // enable effect when registered according to enable state requested by controlling handle
@@ -349,8 +350,9 @@
 // unsafe method called when the effect parent thread has been destroyed
 ssize_t AudioFlinger::EffectBase::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
 {
+    const auto callback = getCallback();
     ALOGV("disconnect() %p handle %p", this, handle);
-    if (mCallback->disconnectEffectHandle(handle, unpinIfLast)) {
+    if (callback->disconnectEffectHandle(handle, unpinIfLast)) {
         return mHandles.size();
     }
 
@@ -358,7 +360,7 @@
     ssize_t numHandles = removeHandle_l(handle);
     if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
         mLock.unlock();
-        mCallback->updateOrphanEffectChains(this);
+        callback->updateOrphanEffectChains(this);
         mLock.lock();
     }
     return numHandles;
@@ -377,7 +379,7 @@
 }
 
 void AudioFlinger::EffectBase::checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) {
-    mCallback->checkSuspendOnEffectEnabled(this, enabled, threadLocked);
+    getCallback()->checkSuspendOnEffectEnabled(this, enabled, threadLocked);
 }
 
 static String8 effectFlagsToString(uint32_t flags) {
@@ -556,7 +558,8 @@
       mStatus(NO_INIT),
       mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
       mDisableWaitCnt(0),    // set by process() and updateState()
-      mOffloaded(false)
+      mOffloaded(false),
+      mAddedToHal(false)
 #ifdef FLOAT_EFFECT_CHAIN
       , mSupportsFloat(false)
 #endif
@@ -835,7 +838,7 @@
                 mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
         // If an insert effect is idle and input buffer is different from output buffer,
         // accumulate input onto output
-        if (mCallback->activeTrackCnt() != 0) {
+        if (getCallback()->activeTrackCnt() != 0) {
             // similar handling with data_bypass above.
             if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
                 accumulateInputToOutput();
@@ -860,6 +863,7 @@
     status_t status;
     uint32_t size;
     audio_channel_mask_t channelMask;
+    sp<EffectCallbackInterface> callback;
 
     if (mEffectInterface == 0) {
         status = NO_INIT;
@@ -870,7 +874,8 @@
     // TODO: handle configuration of input (record) SW effects above the HAL,
     // similar to output EFFECT_FLAG_TYPE_INSERT/REPLACE,
     // in which case input channel masks should be used here.
-    channelMask = mCallback->channelMask();
+    callback = getCallback();
+    channelMask = callback->channelMask();
     mConfig.inputCfg.channels = channelMask;
     mConfig.outputCfg.channels = channelMask;
 
@@ -899,7 +904,7 @@
 #endif
     }
     if (isHapticGenerator()) {
-        audio_channel_mask_t hapticChannelMask = mCallback->hapticChannelMask();
+        audio_channel_mask_t hapticChannelMask = callback->hapticChannelMask();
         mConfig.inputCfg.channels |= hapticChannelMask;
         mConfig.outputCfg.channels |= hapticChannelMask;
     }
@@ -912,11 +917,11 @@
     mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
 
     // Don't use sample rate for thread if effect isn't offloadable.
-    if (mCallback->isOffloadOrDirect() && !isOffloaded()) {
+    if (callback->isOffloadOrDirect() && !isOffloaded()) {
         mConfig.inputCfg.samplingRate = DEFAULT_OUTPUT_SAMPLE_RATE;
         ALOGV("Overriding effect input as 48kHz");
     } else {
-        mConfig.inputCfg.samplingRate = mCallback->sampleRate();
+        mConfig.inputCfg.samplingRate = callback->sampleRate();
     }
     mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
     mConfig.inputCfg.bufferProvider.cookie = NULL;
@@ -942,11 +947,11 @@
     }
     mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
     mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
-    mConfig.inputCfg.buffer.frameCount = mCallback->frameCount();
+    mConfig.inputCfg.buffer.frameCount = callback->frameCount();
     mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
 
     ALOGV("configure() %p chain %p buffer %p framecount %zu",
-          this, mCallback->chain().promote().get(),
+          this, callback->chain().promote().get(),
           mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
 
     status_t cmdStatus;
@@ -962,7 +967,7 @@
 
 #ifdef MULTICHANNEL_EFFECT_CHAIN
     if (status != NO_ERROR &&
-            mCallback->isOutput() &&
+            callback->isOutput() &&
             (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
                     || mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO)) {
         // Older effects may require exact STEREO position mask.
@@ -1029,7 +1034,7 @@
             size = sizeof(int);
             *(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
 
-            uint32_t latency = mCallback->latency();
+            uint32_t latency = callback->latency();
 
             *((int32_t *)p->data + 1)= latency;
             mEffectInterface->command(EFFECT_CMD_SET_PARAM,
@@ -1076,7 +1081,12 @@
 {
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
          (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
-        (void)mCallback->addEffectToHal(mEffectInterface);
+        if (mAddedToHal) {
+            return;
+        }
+
+        (void)getCallback()->addEffectToHal(mEffectInterface);
+        mAddedToHal = true;
     }
 }
 
@@ -1089,7 +1099,7 @@
         status = start_l();
     }
     if (status == NO_ERROR) {
-        mCallback->resetVolume();
+        getCallback()->resetVolume();
     }
     return status;
 }
@@ -1139,7 +1149,7 @@
         // We have the EffectChain and EffectModule lock, permit a reentrant call to setVolume:
         // resetVolume_l --> setVolume_l --> EffectModule::setVolume
         mSetVolumeReentrantTid = gettid();
-        mCallback->resetVolume();
+        getCallback()->resetVolume();
         mSetVolumeReentrantTid = INVALID_PID;
     }
 
@@ -1172,7 +1182,12 @@
 {
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
              (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
-        mCallback->removeEffectFromHal(mEffectInterface);
+        if (!mAddedToHal) {
+            return NO_ERROR;
+        }
+
+        getCallback()->removeEffectFromHal(mEffectInterface);
+        mAddedToHal = false;
     }
     return NO_ERROR;
 }
@@ -1288,7 +1303,7 @@
 
 bool AudioFlinger::EffectModule::isOffloadedOrDirect() const
 {
-    return mCallback->isOffloadOrDirect();
+    return getCallback()->isOffloadOrDirect();
 }
 
 bool AudioFlinger::EffectModule::isVolumeControlEnabled() const
@@ -1332,7 +1347,7 @@
                 || size > mInConversionBuffer->getSize())) {
             mInConversionBuffer.clear();
             ALOGV("%s: allocating mInConversionBuffer %zu", __func__, size);
-            (void)mCallback->allocateHalBuffer(size, &mInConversionBuffer);
+            (void)getCallback()->allocateHalBuffer(size, &mInConversionBuffer);
         }
         if (mInConversionBuffer != nullptr) {
             mInConversionBuffer->setFrameCount(inFrameCount);
@@ -1376,7 +1391,7 @@
                 || size > mOutConversionBuffer->getSize())) {
             mOutConversionBuffer.clear();
             ALOGV("%s: allocating mOutConversionBuffer %zu", __func__, size);
-            (void)mCallback->allocateHalBuffer(size, &mOutConversionBuffer);
+            (void)getCallback()->allocateHalBuffer(size, &mOutConversionBuffer);
         }
         if (mOutConversionBuffer != nullptr) {
             mOutConversionBuffer->setFrameCount(outFrameCount);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 9da95bc..a727e04 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -138,8 +138,9 @@
                              int32_t __unused,
                              std::vector<uint8_t>* __unused) { return NO_ERROR; };
 
+    // mCallback is atomic so this can be lock-free.
     void setCallback(const sp<EffectCallbackInterface>& callback) { mCallback = callback; }
-    sp<EffectCallbackInterface>&     callback() { return mCallback; }
+    sp<EffectCallbackInterface> getCallback() const { return mCallback.load(); }
 
     status_t addHandle(EffectHandle *handle);
     ssize_t disconnectHandle(EffectHandle *handle, bool unpinIfLast);
@@ -170,7 +171,7 @@
     DISALLOW_COPY_AND_ASSIGN(EffectBase);
 
 mutable Mutex                 mLock;      // mutex for process, commands and handles list protection
-    sp<EffectCallbackInterface> mCallback; // parent effect chain
+    mediautils::atomic_sp<EffectCallbackInterface> mCallback; // parent effect chain
     const int                 mId;        // this instance unique ID
     const audio_session_t     mSessionId; // audio session ID
     const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
@@ -285,6 +286,7 @@
                                     // sending disable command.
     uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
     bool     mOffloaded;            // effect is currently offloaded to the audio DSP
+    bool     mAddedToHal;           // effect has been added to the audio HAL
 
 #ifdef FLOAT_EFFECT_CHAIN
     bool    mSupportsFloat;         // effect supports float processing
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index d6d6e25..2963202 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -107,7 +107,7 @@
             mSampleRate = Format_sampleRate(mFormat);
 #if !LOG_NDEBUG
             unsigned channelCount = Format_channelCount(mFormat);
-            ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8);
+            ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_LIMIT);
 #endif
         }
         dumpState->mSampleRate = mSampleRate;
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 13e2ced..88d4eaf 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -48,6 +48,15 @@
 
 /*static*/ const FastMixerState FastMixer::sInitial;
 
+static audio_channel_mask_t getChannelMaskFromCount(size_t count) {
+    const audio_channel_mask_t mask = audio_channel_out_mask_from_count(count);
+    if (mask == AUDIO_CHANNEL_INVALID) {
+        // some counts have no positional masks. TODO: Update this to return index count?
+        return audio_channel_mask_for_index_assignment_from_count(count);
+    }
+    return mask;
+}
+
 FastMixer::FastMixer(audio_io_handle_t parentIoHandle)
     : FastThread("cycle_ms", "load_us"),
     // mFastTrackNames
@@ -79,7 +88,7 @@
     mDummyDumpState = &mDummyFastMixerDumpState;
     // TODO: Add channel mask to NBAIO_Format.
     // We assume that the channel mask must be a valid positional channel mask.
-    mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
+    mSinkChannelMask = getChannelMaskFromCount(mSinkChannelCount);
 
     unsigned i;
     for (i = 0; i < FastMixerState::sMaxFastTracks; ++i) {
@@ -238,7 +247,7 @@
             LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS);
 
             if (mSinkChannelMask == AUDIO_CHANNEL_NONE) {
-                mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
+                mSinkChannelMask = getChannelMaskFromCount(mSinkChannelCount);
             }
             mAudioChannelCount = mSinkChannelCount - audio_channel_count_from_out_mask(
                     mSinkChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index ba868d7..eb640bb 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -29,7 +29,7 @@
                             audio_channel_mask_t channelMask,
                             audio_session_t sessionId,
                             bool isOut,
-                            const media::permission::Identity& identity,
+                            const android::content::AttributionSourceState& attributionSource,
                             pid_t creatorPid,
                             audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
     virtual             ~MmapTrack();
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 2436248..0929055 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -15,8 +15,6 @@
 ** limitations under the License.
 */
 
-#include <android/media/permission/Identity.h>
-
 #ifndef INCLUDING_FROM_AUDIOFLINGER_H
     #error This header file should only be included from AudioFlinger.h
 #endif
@@ -28,12 +26,12 @@
     bool hasOpPlayAudio() const;
 
     static sp<OpPlayAudioMonitor> createIfNeeded(
-            const android::media::permission::Identity& identity,
+            const AttributionSourceState& attributionSource,
             const audio_attributes_t& attr, int id,
             audio_stream_type_t streamType);
 
 private:
-    OpPlayAudioMonitor(const android::media::permission::Identity& identity,
+    OpPlayAudioMonitor(const AttributionSourceState& attributionSource,
         audio_usage_t usage, int id);
     void onFirstRef() override;
     static void getPackagesForUid(uid_t uid, Vector<String16>& packages);
@@ -54,7 +52,7 @@
     void checkPlayAudioForUsage();
 
     std::atomic_bool mHasOpPlayAudio;
-    const android::media::permission::Identity mIdentity;
+    const AttributionSourceState mAttributionSource;
     const int32_t mUsage; // on purpose not audio_usage_t because always checked in appOps as int32_t
     const int mId; // for logging purposes only
 };
@@ -75,13 +73,14 @@
                                 const sp<IMemory>& sharedBuffer,
                                 audio_session_t sessionId,
                                 pid_t creatorPid,
-                                const media::permission::Identity& identity,
+                                const AttributionSourceState& attributionSource,
                                 audio_output_flags_t flags,
                                 track_type type,
                                 audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
                                 /** default behaviour is to start when there are as many frames
                                   * ready as possible (aka. Buffer is full). */
-                                size_t frameCountToBeReady = SIZE_MAX);
+                                size_t frameCountToBeReady = SIZE_MAX,
+                                float speed = 1.0f);
     virtual             ~Track();
     virtual status_t    initCheck() const;
 
@@ -148,14 +147,6 @@
     void                setFinalVolume(float volume);
     float               getFinalVolume() const { return mFinalVolume; }
 
-    /** @return true if the track has changed (metadata or volume) since
-     *          the last time this function was called,
-     *          true if this function was never called since the track creation,
-     *          false otherwise.
-     *  Thread safe.
-     */
-    bool            readAndClearHasChanged() { return !mChangeNotified.test_and_set(); }
-
     using SourceMetadatas = std::vector<playback_track_metadata_v7_t>;
     using MetadataInserter = std::back_insert_iterator<SourceMetadatas>;
     /** Copy the track metadata in the provided iterator. Thread safe. */
@@ -191,6 +182,9 @@
                    mAudioTrackServerProxy->getUnderrunFrames());
        }
     }
+
+    audio_output_flags_t getOutputFlags() const { return mFlags; }
+    float getSpeed() const { return mSpeed; }
 protected:
     // for numerous
     friend class PlaybackThread;
@@ -228,14 +222,25 @@
 
     sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
 
+    // presentationComplete checked by frames. (Mixed Tracks).
     // framesWritten is cumulative, never reset, and is shared all tracks
     // audioHalFrames is derived from output latency
-    // FIXME parameters not needed, could get them from the thread
     bool presentationComplete(int64_t framesWritten, size_t audioHalFrames);
+
+    // presentationComplete checked by time. (Direct Tracks).
+    bool presentationComplete(uint32_t latencyMs);
+
+    void resetPresentationComplete() {
+        mPresentationCompleteFrames = 0;
+        mPresentationCompleteTimeNs = 0;
+    }
+
+    // notifyPresentationComplete is called when presentationComplete() detects
+    // that the track is finished stopping.
+    void notifyPresentationComplete();
+
     void signalClientFlag(int32_t flag);
 
-    /** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
-    void setMetadataHasChanged() { mChangeNotified.clear(); }
 public:
     void triggerEvents(AudioSystem::sync_event_t type);
     virtual void invalidate();
@@ -264,9 +269,6 @@
     int32_t             *mAuxBuffer;
     int                 mAuxEffectId;
     bool                mHasVolumeController;
-    size_t              mPresentationCompleteFrames; // number of frames written to the
-                                    // audio HAL when this track will be fully rendered
-                                    // zero means not monitoring
 
     // access these three variables only when holding thread lock.
     LinearMap<int64_t> mFrameMap;           // track frame to server frame mapping
@@ -302,6 +304,14 @@
         for (auto& tp : mTeePatches) { f(tp.patchTrack); }
     };
 
+    size_t              mPresentationCompleteFrames = 0; // (Used for Mixed tracks)
+                                    // The number of frames written to the
+                                    // audio HAL when this track is considered fully rendered.
+                                    // Zero means not monitoring.
+    int64_t             mPresentationCompleteTimeNs = 0; // (Used for Direct tracks)
+                                    // The time when this track is considered fully rendered.
+                                    // Zero means not monitoring.
+
     // The following fields are only for fast tracks, and should be in a subclass
     int                 mFastIndex; // index within FastMixerState::mFastTracks[];
                                     // either mFastIndex == -1 if not isFastTrack()
@@ -320,9 +330,8 @@
     bool                mFlushHwPending; // track requests for thread flush
     bool                mPauseHwPending = false; // direct/offload track request for thread pause
     audio_output_flags_t mFlags;
-    // If the last track change was notified to the client with readAndClearHasChanged
-    std::atomic_flag     mChangeNotified = ATOMIC_FLAG_INIT;
     TeePatches  mTeePatches;
+    const float         mSpeed;
 };  // end of Track
 
 
@@ -341,7 +350,7 @@
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
                                 size_t frameCount,
-                                const android::media::permission::Identity& identity);
+                                const AttributionSourceState& attributionSource);
     virtual             ~OutputTrack();
 
     virtual status_t    start(AudioSystem::sync_event_t event =
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 451c198..e8552c4 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -15,43 +15,12 @@
 ** limitations under the License.
 */
 
+#include <android/content/AttributionSourceState.h>
+
 #ifndef INCLUDING_FROM_AUDIOFLINGER_H
     #error This header file should only be included from AudioFlinger.h
 #endif
 
-// Checks and monitors OP_RECORD_AUDIO
-class OpRecordAudioMonitor : public RefBase {
-public:
-    ~OpRecordAudioMonitor() override;
-    bool hasOpRecordAudio() const;
-
-    static sp<OpRecordAudioMonitor> createIfNeeded
-        (const media::permission::Identity& identity, const audio_attributes_t& attr);
-
-private:
-    explicit OpRecordAudioMonitor(const media::permission::Identity& identity);
-    void onFirstRef() override;
-
-    AppOpsManager mAppOpsManager;
-
-    class RecordAudioOpCallback : public BnAppOpsCallback {
-    public:
-        explicit RecordAudioOpCallback(const wp<OpRecordAudioMonitor>& monitor);
-        void opChanged(int32_t op, const String16& packageName) override;
-
-    private:
-        const wp<OpRecordAudioMonitor> mMonitor;
-    };
-
-    sp<RecordAudioOpCallback> mOpCallback;
-    // called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
-    // and in onFirstRef()
-    void checkRecordAudio();
-
-    std::atomic_bool mHasOpRecordAudio;
-    const media::permission::Identity mIdentity;
-};
-
 // record track
 class RecordTrack : public TrackBase {
 public:
@@ -66,7 +35,7 @@
                                 size_t bufferSize,
                                 audio_session_t sessionId,
                                 pid_t creatorPid,
-                                const media::permission::Identity& identity,
+                                const AttributionSourceState& attributionSource,
                                 audio_input_flags_t flags,
                                 track_type type,
                                 audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
@@ -102,7 +71,7 @@
                                 { return (mFlags & AUDIO_INPUT_FLAG_DIRECT) != 0; }
 
             void        setSilenced(bool silenced) { if (!isPatchTrack()) mSilenced = silenced; }
-            bool        isSilenced() const;
+            bool        isSilenced() const { return mSilenced; }
 
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
@@ -149,8 +118,6 @@
 
             bool                               mSilenced;
 
-            // used to enforce OP_RECORD_AUDIO
-            sp<OpRecordAudioMonitor>           mOpRecordAudioMonitor;
             std::string                        mSharedAudioPackageName = {};
             int32_t                            mStartFrames = -1;
 };
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d42a6ca..9e099ce 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -118,7 +118,7 @@
 namespace android {
 
 using media::IEffectClient;
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 // retry counts for buffer fill timeout
 // 50 * ~20msecs = 1 second
@@ -1638,7 +1638,7 @@
         detachAuxEffect_l(effect->id());
     }
 
-    sp<EffectChain> chain = effect->callback()->chain().promote();
+    sp<EffectChain> chain = effect->getCallback()->chain().promote();
     if (chain != 0) {
         // remove effect chain if removing last effect
         if (chain->removeEffect_l(effect, release) == 0) {
@@ -1798,8 +1798,14 @@
 
 template <typename T>
 bool AudioFlinger::ThreadBase::ActiveTracks<T>::readAndClearHasChanged() {
-    const bool hasChanged = mHasChanged;
+    bool hasChanged = mHasChanged;
     mHasChanged = false;
+
+    for (const sp<T> &track : mActiveTracks) {
+        // Do not short-circuit as all hasChanged states must be reset
+        // as all the metadata are going to be sent
+        hasChanged |= track->readAndClearHasChanged();
+    }
     return hasChanged;
 }
 
@@ -1986,7 +1992,7 @@
 
 void AudioFlinger::PlaybackThread::onFirstRef()
 {
-    if (mOutput == nullptr || mOutput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         ALOGE("The stream is not open yet"); // This should not happen.
     } else {
         // setEventCallback will need a strong pointer as a parameter. Calling it
@@ -2123,7 +2129,7 @@
         audio_session_t sessionId,
         audio_output_flags_t *flags,
         pid_t creatorPid,
-        const Identity& identity,
+        const AttributionSourceState& attributionSource,
         pid_t tid,
         status_t *status,
         audio_port_handle_t portId,
@@ -2418,8 +2424,8 @@
         track = new Track(this, client, streamType, attr, sampleRate, format,
                           channelMask, frameCount,
                           nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
-                          sessionId, creatorPid, identity, trackFlags, TrackBase::TYPE_DEFAULT,
-                          portId, SIZE_MAX /*frameCountToBeReady*/);
+                          sessionId, creatorPid, attributionSource, trackFlags,
+                          TrackBase::TYPE_DEFAULT, portId, SIZE_MAX /*frameCountToBeReady*/, speed);
 
         lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
         if (lStatus != NO_ERROR) {
@@ -2625,7 +2631,7 @@
         }
 
         track->mResetDone = false;
-        track->mPresentationCompleteFrames = 0;
+        track->resetPresentationComplete();
         mActiveTracks.add(track);
         if (chain != 0) {
             ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(),
@@ -2695,7 +2701,7 @@
 
 status_t AudioFlinger::DirectOutputThread::selectPresentation(int presentationId, int programId) {
     Mutex::Autolock _l(mLock);
-    if (mOutput == nullptr || mOutput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     return mOutput->stream->selectPresentation(presentationId, programId);
@@ -2992,16 +2998,7 @@
 
 void AudioFlinger::PlaybackThread::updateMetadata_l()
 {
-    if (mOutput == nullptr || mOutput->stream == nullptr ) {
-        return; // That should not happen
-    }
-    bool hasChanged = mActiveTracks.readAndClearHasChanged();
-    for (const sp<Track> &track : mActiveTracks) {
-        // Do not short-circuit as all hasChanged states must be reset
-        // as all the metadata are going to be sent
-        hasChanged |= track->readAndClearHasChanged();
-    }
-    if (!hasChanged) {
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
         return; // nothing to do
     }
     StreamOutHalInterface::SourceMetadata metadata;
@@ -3324,6 +3321,17 @@
     invalidateTracks_l(streamType);
 }
 
+// getTrackById_l must be called with holding thread lock
+AudioFlinger::PlaybackThread::Track* AudioFlinger::PlaybackThread::getTrackById_l(
+        audio_port_handle_t trackPortId) {
+    for (size_t i = 0; i < mTracks.size(); i++) {
+        if (mTracks[i]->portId() == trackPortId) {
+            return mTracks[i].get();
+        }
+    }
+    return nullptr;
+}
+
 status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
 {
     audio_session_t session = chain->sessionId();
@@ -6030,16 +6038,8 @@
                     track->isStopping_2() || track->isPaused()) {
                 // We have consumed all the buffers of this track.
                 // Remove it from the list of active tracks.
-                size_t audioHALFrames;
-                if (audio_has_proportional_frames(mFormat)) {
-                    audioHALFrames = (latency_l() * mSampleRate) / 1000;
-                } else {
-                    audioHALFrames = 0;
-                }
-
-                int64_t framesWritten = mBytesWritten / mFrameSize;
                 if (mStandby || !last ||
-                        track->presentationComplete(framesWritten, audioHALFrames) ||
+                        track->presentationComplete(latency_l()) ||
                         track->isPaused() || mHwPaused) {
                     if (track->isStopping_2()) {
                         track->mState = TrackBase::STOPPED;
@@ -6613,14 +6613,7 @@
                 // Drain has completed or we are in standby, signal presentation complete
                 if (!(mDrainSequence & 1) || !last || mStandby) {
                     track->mState = TrackBase::STOPPED;
-                    uint32_t latency = 0;
-                    status_t result = mOutput->stream->getLatency(&latency);
-                    ALOGE_IF(result != OK,
-                            "Error when retrieving output stream latency: %d", result);
-                    size_t audioHALFrames = (latency * mSampleRate) / 1000;
-                    int64_t framesWritten =
-                            mBytesWritten / mOutput->getFrameSize();
-                    track->presentationComplete(framesWritten, audioHALFrames);
+                    track->presentationComplete(latency_l());
                     track->reset();
                     tracksToRemove->add(track);
                     // OFFLOADED stop resets frame counts.
@@ -6878,19 +6871,20 @@
     // from different OutputTracks and their associated MixerThreads (e.g. one may
     // nearly empty and the other may be dropping data).
 
-    // TODO b/182392769: use identity util, move to server edge
-    Identity identity = Identity();
-    identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
+    // TODO b/182392769: use attribution source util, move to server edge
+    AttributionSourceState attributionSource = AttributionSourceState();
+    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
         IPCThreadState::self()->getCallingUid()));
-    identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(
+    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(
       IPCThreadState::self()->getCallingPid()));
+    attributionSource.token = sp<BBinder>::make();
     sp<OutputTrack> outputTrack = new OutputTrack(thread,
                                             this,
                                             mSampleRate,
                                             mFormat,
                                             mChannelMask,
                                             frameCount,
-                                            identity);
+                                            attributionSource);
     status_t status = outputTrack != 0 ? outputTrack->initCheck() : (status_t) NO_MEMORY;
     if (status != NO_ERROR) {
         ALOGE("addOutputTrack() initCheck failed %d", status);
@@ -7814,7 +7808,7 @@
         audio_session_t sessionId,
         size_t *pNotificationFrameCount,
         pid_t creatorPid,
-        const Identity& identity,
+        const AttributionSourceState& attributionSource,
         audio_input_flags_t *flags,
         pid_t tid,
         status_t *status,
@@ -7828,7 +7822,8 @@
     audio_input_flags_t inputFlags = mInput->flags;
     audio_input_flags_t requestedFlags = *flags;
     uint32_t sampleRate;
-    Identity checkedIdentity = AudioFlinger::checkIdentityPackage(identity);
+    AttributionSourceState checkedAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+            attributionSource);
 
     lStatus = initCheck();
     if (lStatus != NO_ERROR) {
@@ -7843,7 +7838,7 @@
     }
 
     if (maxSharedAudioHistoryMs != 0) {
-        if (!captureHotwordAllowed(checkedIdentity)) {
+        if (!captureHotwordAllowed(checkedAttributionSource)) {
             lStatus = PERMISSION_DENIED;
             goto Exit;
         }
@@ -7965,16 +7960,17 @@
         Mutex::Autolock _l(mLock);
         int32_t startFrames = -1;
         if (!mSharedAudioPackageName.empty()
-                && mSharedAudioPackageName == checkedIdentity.packageName
+                && mSharedAudioPackageName == checkedAttributionSource.packageName
                 && mSharedAudioSessionId == sessionId
-                && captureHotwordAllowed(checkedIdentity)) {
+                && captureHotwordAllowed(checkedAttributionSource)) {
             startFrames = mSharedAudioStartFrames;
         }
 
         track = new RecordTrack(this, client, attr, sampleRate,
                       format, channelMask, frameCount,
                       nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid,
-                      checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startFrames);
+                      checkedAttributionSource, *flags, TrackBase::TYPE_DEFAULT, portId,
+                      startFrames);
 
         lStatus = track->initCheck();
         if (lStatus != NO_ERROR) {
@@ -8186,7 +8182,7 @@
 {
     ALOGV("RecordThread::getActiveMicrophones");
     AutoMutex _l(mLock);
-    if (mInput == nullptr || mInput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     status_t status = mInput->stream->getActiveMicrophones(activeMicrophones);
@@ -8198,7 +8194,7 @@
 {
     ALOGV("setPreferredMicrophoneDirection(%d)", direction);
     AutoMutex _l(mLock);
-    if (mInput == nullptr || mInput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     return mInput->stream->setPreferredMicrophoneDirection(direction);
@@ -8208,7 +8204,7 @@
 {
     ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
     AutoMutex _l(mLock);
-    if (mInput == nullptr || mInput->stream == nullptr) {
+    if (!isStreamInitialized()) {
         return NO_INIT;
     }
     return mInput->stream->setPreferredMicrophoneFieldDimension(zoom);
@@ -8259,9 +8255,8 @@
 
 void AudioFlinger::RecordThread::updateMetadata_l()
 {
-    if (mInput == nullptr || mInput->stream == nullptr ||
-            !mActiveTracks.readAndClearHasChanged()) {
-        return;
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
+        return; // nothing to do
     }
     StreamInHalInterface::SinkMetadata metadata;
     for (const sp<RecordTrack> &track : mActiveTracks) {
@@ -8563,7 +8558,7 @@
     if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
         audio_channel_mask_t mask = (audio_channel_mask_t) value;
         if (!audio_is_input_channel(mask) ||
-                audio_channel_count_from_in_mask(mask) > FCC_8) {
+                audio_channel_count_from_in_mask(mask) > FCC_LIMIT) {
             status = BAD_VALUE;
         } else {
             channelMask = mask;
@@ -8600,7 +8595,7 @@
                 if (mInput->stream->getAudioProperties(&config) == OK &&
                         audio_is_linear_pcm(config.format) && audio_is_linear_pcm(reqFormat) &&
                         config.sample_rate <= (AUDIO_RESAMPLER_DOWN_RATIO_MAX * samplingRate) &&
-                        audio_channel_count_from_in_mask(config.channel_mask) <= FCC_8) {
+                        audio_channel_count_from_in_mask(config.channel_mask) <= FCC_LIMIT) {
                     status = NO_ERROR;
                 }
             }
@@ -8662,10 +8657,10 @@
     mFormat = mHALFormat;
     mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
     if (audio_is_linear_pcm(mFormat)) {
-        LOG_ALWAYS_FATAL_IF(mChannelCount > FCC_8, "HAL channel count %d > %d",
-                mChannelCount, FCC_8);
+        LOG_ALWAYS_FATAL_IF(mChannelCount > FCC_LIMIT, "HAL channel count %d > %d",
+                mChannelCount, FCC_LIMIT);
     } else {
-        // Can have more that FCC_8 channels in encoded streams.
+        // Can have more that FCC_LIMIT channels in encoded streams.
         ALOGI("HAL format %#x is not linear pcm", mFormat);
     }
     result = mInput->stream->getFrameSize(&mFrameSize);
@@ -9167,7 +9162,7 @@
                                          audio_port_handle_t *handle)
 {
     ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
-          client.identity.uid, mStandby, mPortId, *handle);
+          client.attributionSource.uid, mStandby, mPortId, *handle);
     if (mHalStream == 0) {
         return NO_INIT;
     }
@@ -9199,7 +9194,7 @@
         ret = AudioSystem::getOutputForAttr(&mAttr, &io,
                                             mSessionId,
                                             &stream,
-                                            client.identity,
+                                            client.attributionSource,
                                             &config,
                                             flags,
                                             &deviceId,
@@ -9216,7 +9211,7 @@
         ret = AudioSystem::getInputForAttr(&mAttr, &io,
                                               RECORD_RIID_INVALID,
                                               mSessionId,
-                                              client.identity,
+                                              client.attributionSource,
                                               &config,
                                               AUDIO_INPUT_FLAG_MMAP_NOIRQ,
                                               &deviceId,
@@ -9256,7 +9251,8 @@
 
     // Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
     sp<MmapTrack> track = new MmapTrack(this, attr == nullptr ? mAttr : *attr, mSampleRate, mFormat,
-                                        mChannelMask, mSessionId, isOutput(), client.identity,
+                                        mChannelMask, mSessionId, isOutput(),
+                                        client.attributionSource,
                                         IPCThreadState::self()->getCallingPid(), portId);
 
     if (isOutput()) {
@@ -9264,7 +9260,7 @@
         mHalVolFloat = -1.0f;
     } else if (!track->isSilenced_l()) {
         for (const sp<MmapTrack> &t : mActiveTracks) {
-            if (t->isSilenced_l() && t->uid() != client.identity.uid)
+            if (t->isSilenced_l() && t->uid() != client.attributionSource.uid)
                 t->invalidate();
         }
     }
@@ -9959,14 +9955,16 @@
                 }
             }
         }
+        for (const sp<MmapTrack> &track : mActiveTracks) {
+            track->setMetadataHasChanged();
+        }
     }
 }
 
 void AudioFlinger::MmapPlaybackThread::updateMetadata_l()
 {
-    if (mOutput == nullptr || mOutput->stream == nullptr ||
-            !mActiveTracks.readAndClearHasChanged()) {
-        return;
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
+        return; // nothing to do
     }
     StreamOutHalInterface::SourceMetadata metadata;
     for (const sp<MmapTrack> &track : mActiveTracks) {
@@ -10093,9 +10091,8 @@
 
 void AudioFlinger::MmapCaptureThread::updateMetadata_l()
 {
-    if (mInput == nullptr || mInput->stream == nullptr ||
-            !mActiveTracks.readAndClearHasChanged()) {
-        return;
+    if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
+        return; // nothing to do
     }
     StreamInHalInterface::SinkMetadata metadata;
     for (const sp<MmapTrack> &track : mActiveTracks) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 65db986..eee1f2b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -527,6 +527,8 @@
                     }
                 }
 
+    virtual     bool isStreamInitialized() = 0;
+
 protected:
 
                 // entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -741,7 +743,9 @@
                     void            updatePowerState(sp<ThreadBase> thread, bool force = false);
 
                     /** @return true if one or move active tracks was added or removed since the
-                     *          last time this function was called or the vector was created. */
+                     *          last time this function was called or the vector was created.
+                     *          true if volume of one of active tracks was changed.
+                     */
                     bool            readAndClearHasChanged();
 
                 private:
@@ -914,7 +918,7 @@
                                 audio_session_t sessionId,
                                 audio_output_flags_t *flags,
                                 pid_t creatorPid,
-                                const media::permission::Identity& identity,
+                                const AttributionSourceState& attributionSource,
                                 pid_t tid,
                                 status_t *status /*non-NULL*/,
                                 audio_port_handle_t portId,
@@ -993,6 +997,10 @@
                                         && outDeviceTypes().count(mTimestampCorrectedDevice) != 0;
                             }
 
+    virtual     bool        isStreamInitialized() {
+                                return !(mOutput == nullptr || mOutput->stream == nullptr);
+                            }
+
                 audio_channel_mask_t hapticChannelMask() const override {
                                          return mHapticChannelMask;
                                      }
@@ -1005,6 +1013,8 @@
                     mDownStreamPatch = *patch;
                 }
 
+                PlaybackThread::Track* getTrackById_l(audio_port_handle_t trackId);
+
 protected:
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -1688,7 +1698,7 @@
                     audio_session_t sessionId,
                     size_t *pNotificationFrameCount,
                     pid_t creatorPid,
-                    const media::permission::Identity& identity,
+                    const AttributionSourceState& attributionSource,
                     audio_input_flags_t *flags,
                     pid_t tid,
                     status_t *status /*non-NULL*/,
@@ -1780,6 +1790,10 @@
                                           audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
                                           int64_t sharedAudioStartMs = -1);
 
+    virtual bool        isStreamInitialized() {
+                            return !(mInput == nullptr || mInput->stream == nullptr);
+                        }
+
 protected:
             void        dumpInternals_l(int fd, const Vector<String16>& args) override;
             void        dumpTracks_l(int fd, const Vector<String16>& args) override;
@@ -1949,6 +1963,8 @@
     virtual     void        setRecordSilenced(audio_port_handle_t portId __unused,
                                               bool silenced __unused) {}
 
+    virtual     bool        isStreamInitialized() { return false; }
+
  protected:
                 void        dumpInternals_l(int fd, const Vector<String16>& args) override;
                 void        dumpTracks_l(int fd, const Vector<String16>& args) override;
@@ -2011,6 +2027,10 @@
 
                 status_t    getExternalPosition(uint64_t *position, int64_t *timeNanos) override;
 
+    virtual     bool        isStreamInitialized() {
+                                return !(mOutput == nullptr || mOutput->stream == nullptr);
+                            }
+
 protected:
                 void        dumpInternals_l(int fd, const Vector<String16>& args) override;
 
@@ -2043,6 +2063,10 @@
 
                 status_t       getExternalPosition(uint64_t *position, int64_t *timeNanos) override;
 
+    virtual     bool           isStreamInitialized() {
+                                   return !(mInput == nullptr || mInput->stream == nullptr);
+                               }
+
 protected:
 
                 AudioStreamIn*  mInput;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 38dab5b..92f129c 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -255,6 +255,17 @@
 
     audio_channel_mask_t channelMask() const { return mChannelMask; }
 
+    /** @return true if the track has changed (metadata or volume) since
+     *          the last time this function was called,
+     *          true if this function was never called since the track creation,
+     *          false otherwise.
+     *  Thread safe.
+     */
+    bool readAndClearHasChanged() { return !mChangeNotified.test_and_set(); }
+
+    /** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
+    void setMetadataHasChanged() { mChangeNotified.clear(); }
+
 protected:
     DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
@@ -391,6 +402,9 @@
     std::atomic<FrameTime> mKernelFrameTime{};     // last frame time on kernel side.
     const pid_t         mCreatorPid;  // can be different from mclient->pid() for instance
                                       // when created by NuPlayer on behalf of a client
+
+    // If the last track change was notified to the client with readAndClearHasChanged
+    std::atomic_flag    mChangeNotified = ATOMIC_FLAG_INIT;
 };
 
 // PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 3e04804..a6e3c06 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -65,7 +65,7 @@
 
 using ::android::aidl_utils::binderStatusFromStatusT;
 using binder::Status;
-using media::permission::Identity;
+using content::AttributionSourceState;
 using media::VolumeShaper;
 // ----------------------------------------------------------------------------
 //      TrackBase
@@ -238,12 +238,13 @@
     }
 }
 
-// TODO b/182392769: use identity util
-static Identity audioServerIdentity(pid_t pid) {
-   Identity i{};
-   i.uid = AID_AUDIOSERVER;
-   i.pid = pid;
-   return i;
+// TODO b/182392769: use attribution source util
+static AttributionSourceState audioServerAttributionSource(pid_t pid) {
+   AttributionSourceState attributionSource{};
+   attributionSource.uid = AID_AUDIOSERVER;
+   attributionSource.pid = pid;
+   attributionSource.token = sp<BBinder>::make();
+   return attributionSource;
 }
 
 status_t AudioFlinger::ThreadBase::TrackBase::initCheck() const
@@ -498,11 +499,11 @@
 // static
 sp<AudioFlinger::PlaybackThread::OpPlayAudioMonitor>
 AudioFlinger::PlaybackThread::OpPlayAudioMonitor::createIfNeeded(
-            const Identity& identity, const audio_attributes_t& attr, int id,
+            const AttributionSourceState& attributionSource, const audio_attributes_t& attr, int id,
             audio_stream_type_t streamType)
 {
     Vector <String16> packages;
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
     getPackagesForUid(uid, packages);
     if (isServiceUid(uid)) {
         if (packages.isEmpty()) {
@@ -525,13 +526,15 @@
         return nullptr;
     }
 
-    Identity checkedIdentity = AudioFlinger::checkIdentityPackage(identity);
-    return new OpPlayAudioMonitor(checkedIdentity, attr.usage, id);
+    AttributionSourceState checkedAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+            attributionSource);
+    return new OpPlayAudioMonitor(checkedAttributionSource, attr.usage, id);
 }
 
 AudioFlinger::PlaybackThread::OpPlayAudioMonitor::OpPlayAudioMonitor(
-        const Identity& identity, audio_usage_t usage, int id)
-        : mHasOpPlayAudio(true), mIdentity(identity), mUsage((int32_t) usage), mId(id)
+        const AttributionSourceState& attributionSource, audio_usage_t usage, int id)
+        : mHasOpPlayAudio(true), mAttributionSource(attributionSource), mUsage((int32_t) usage),
+        mId(id)
 {
 }
 
@@ -546,10 +549,11 @@
 void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::onFirstRef()
 {
     checkPlayAudioForUsage();
-    if (mIdentity.packageName.has_value()) {
+    if (mAttributionSource.packageName.has_value()) {
         mOpCallback = new PlayAudioOpCallback(this);
         mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO,
-            VALUE_OR_FATAL(aidl2legacy_string_view_String16(mIdentity.packageName.value_or("")))
+            VALUE_OR_FATAL(aidl2legacy_string_view_String16(
+            mAttributionSource.packageName.value_or("")))
             , mOpCallback);
     }
 }
@@ -563,12 +567,12 @@
 // - not called from PlayAudioOpCallback because the callback is not installed in this case
 void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::checkPlayAudioForUsage()
 {
-    if (!mIdentity.packageName.has_value()) {
+    if (!mAttributionSource.packageName.has_value()) {
         mHasOpPlayAudio.store(false);
     } else {
-        uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mIdentity.uid));
+        uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAttributionSource.uid));
         String16 packageName = VALUE_OR_FATAL(
-            aidl2legacy_string_view_String16(mIdentity.packageName.value_or("")));
+            aidl2legacy_string_view_String16(mAttributionSource.packageName.value_or("")));
         bool hasIt = mAppOpsManager.checkAudioOpNoThrow(AppOpsManager::OP_PLAY_AUDIO,
                     mUsage, uid, packageName) == AppOpsManager::MODE_ALLOWED;
         ALOGD("OpPlayAudio: track:%d usage:%d %smuted", mId, mUsage, hasIt ? "not " : "");
@@ -620,11 +624,12 @@
             const sp<IMemory>& sharedBuffer,
             audio_session_t sessionId,
             pid_t creatorPid,
-            const Identity& identity,
+            const AttributionSourceState& attributionSource,
             audio_output_flags_t flags,
             track_type type,
             audio_port_handle_t portId,
-            size_t frameCountToBeReady)
+            size_t frameCountToBeReady,
+            float speed)
     :   TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
                   // TODO: Using unsecurePointer() has some associated security pitfalls
                   //       (see declaration for details).
@@ -633,7 +638,7 @@
                   (sharedBuffer != 0) ? sharedBuffer->unsecurePointer() : buffer,
                   (sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
                   sessionId, creatorPid,
-                  VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)), true /*isOut*/,
+                  VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)), true /*isOut*/,
                   (type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
                   type,
                   portId,
@@ -645,10 +650,9 @@
     mMainBuffer(thread->sinkBuffer()),
     mAuxBuffer(NULL),
     mAuxEffectId(0), mHasVolumeController(false),
-    mPresentationCompleteFrames(0),
     mFrameMap(16 /* sink-frame-to-track-frame map memory */),
     mVolumeHandler(new media::VolumeHandler(sampleRate)),
-    mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(identity, attr, id(),
+    mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(attributionSource, attr, id(),
         streamType)),
     // mSinkTimestamp
     mFastIndex(-1),
@@ -658,7 +662,8 @@
     mFinalVolume(0.f),
     mResumeToStopping(false),
     mFlushHwPending(false),
-    mFlags(flags)
+    mFlags(flags),
+    mSpeed(speed)
 {
     // client == 0 implies sharedBuffer == 0
     ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
@@ -670,7 +675,7 @@
         return;
     }
 
-    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
     if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
         ALOGE("%s(%d): no more tracks available", __func__, mId);
         releaseCblk(); // this makes the track invalid.
@@ -716,8 +721,8 @@
         // HapticGenerator effect, which will generate haptic data, on the track. In that case,
         // external vibration is always created for all tracks attached to haptic playback thread.
         mAudioVibrationController = new AudioVibrationController(this);
-        std::string packageName = identity.packageName.has_value() ?
-            identity.packageName.value() : "";
+        std::string packageName = attributionSource.packageName.has_value() ?
+            attributionSource.packageName.value() : "";
         mExternalVibration = new os::ExternalVibration(
                 mUid, packageName, mAttr, mAudioVibrationController);
     }
@@ -1065,6 +1070,8 @@
             reset();
         }
 
+        // clear mPauseHwPending because of pause (and possibly flush) during underrun.
+        mPauseHwPending = false;
         if (state == PAUSED || state == PAUSING) {
             if (mResumeToStopping) {
                 // happened we need to resume to STOPPING_1
@@ -1402,6 +1409,10 @@
 void AudioFlinger::PlaybackThread::Track::setTeePatches(TeePatches teePatches) {
     forEachTeePatchTrack([](auto patchTrack) { patchTrack->destroy(); });
     mTeePatches = std::move(teePatches);
+    if (mState == TrackBase::ACTIVE || mState == TrackBase::RESUMING ||
+            mState == TrackBase::STOPPING_1) {
+        forEachTeePatchTrack([](auto patchTrack) { patchTrack->start(); });
+    }
 }
 
 status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
@@ -1450,6 +1461,7 @@
     mAuxBuffer = buffer;
 }
 
+// presentationComplete verified by frames, used by Mixed tracks.
 bool AudioFlinger::PlaybackThread::Track::presentationComplete(
         int64_t framesWritten, size_t audioHalFrames)
 {
@@ -1468,30 +1480,70 @@
             (long long)mPresentationCompleteFrames, (long long)framesWritten);
     if (mPresentationCompleteFrames == 0) {
         mPresentationCompleteFrames = framesWritten + audioHalFrames;
-        ALOGV("%s(%d): presentationComplete() reset:"
+        ALOGV("%s(%d): set:"
                 " mPresentationCompleteFrames %lld audioHalFrames %zu",
                 __func__, mId,
                 (long long)mPresentationCompleteFrames, audioHalFrames);
     }
 
     bool complete;
-    if (isOffloaded()) {
-        complete = true;
-    } else if (isDirect() || isFastTrack()) { // these do not go through linear map
+    if (isFastTrack()) { // does not go through linear map
         complete = framesWritten >= (int64_t) mPresentationCompleteFrames;
+        ALOGV("%s(%d): %s framesWritten:%lld  mPresentationCompleteFrames:%lld",
+                __func__, mId, (complete ? "complete" : "waiting"),
+                (long long) framesWritten, (long long) mPresentationCompleteFrames);
     } else {  // Normal tracks, OutputTracks, and PatchTracks
         complete = framesWritten >= (int64_t) mPresentationCompleteFrames
                 && mAudioTrackServerProxy->isDrained();
     }
 
     if (complete) {
-        triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
-        mAudioTrackServerProxy->setStreamEndDone();
+        notifyPresentationComplete();
         return true;
     }
     return false;
 }
 
+// presentationComplete checked by time, used by DirectTracks.
+bool AudioFlinger::PlaybackThread::Track::presentationComplete(uint32_t latencyMs)
+{
+    // For Offloaded or Direct tracks.
+
+    // For a direct track, we incorporated time based testing for presentationComplete.
+
+    // For an offloaded track the HAL+h/w delay is variable so a HAL drain() is used
+    // to detect when all frames have been played. In this case latencyMs isn't
+    // useful because it doesn't always reflect whether there is data in the h/w
+    // buffers, particularly if a track has been paused and resumed during draining
+
+    constexpr float MIN_SPEED = 0.125f; // min speed scaling allowed for timely response.
+    if (mPresentationCompleteTimeNs == 0) {
+        mPresentationCompleteTimeNs = systemTime() + latencyMs * 1e6 / fmax(mSpeed, MIN_SPEED);
+        ALOGV("%s(%d): set: latencyMs %u  mPresentationCompleteTimeNs:%lld",
+                __func__, mId, latencyMs, (long long) mPresentationCompleteTimeNs);
+    }
+
+    bool complete;
+    if (isOffloaded()) {
+        complete = true;
+    } else { // Direct
+        complete = systemTime() >= mPresentationCompleteTimeNs;
+        ALOGV("%s(%d): %s", __func__, mId, (complete ? "complete" : "waiting"));
+    }
+    if (complete) {
+        notifyPresentationComplete();
+        return true;
+    }
+    return false;
+}
+
+void AudioFlinger::PlaybackThread::Track::notifyPresentationComplete()
+{
+    // This only triggers once. TODO: should we enforce this?
+    triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
+    mAudioTrackServerProxy->setStreamEndDone();
+}
+
 void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_t type)
 {
     for (size_t i = 0; i < mSyncEvents.size();) {
@@ -1832,12 +1884,12 @@
             audio_format_t format,
             audio_channel_mask_t channelMask,
             size_t frameCount,
-            const Identity& identity)
+            const AttributionSourceState& attributionSource)
     :   Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
               audio_attributes_t{} /* currently unused for output track */,
               sampleRate, format, channelMask, frameCount,
               nullptr /* buffer */, (size_t)0 /* bufferSize */, nullptr /* sharedBuffer */,
-              AUDIO_SESSION_NONE, getpid(), identity, AUDIO_OUTPUT_FLAG_NONE,
+              AUDIO_SESSION_NONE, getpid(), attributionSource, AUDIO_OUTPUT_FLAG_NONE,
               TYPE_OUTPUT),
     mActive(false), mSourceThread(sourceThread)
 {
@@ -2067,7 +2119,7 @@
               audio_attributes_t{} /* currently unused for patch track */,
               sampleRate, format, channelMask, frameCount,
               buffer, bufferSize, nullptr /* sharedBuffer */,
-              AUDIO_SESSION_NONE, getpid(), audioServerIdentity(getpid()), flags,
+              AUDIO_SESSION_NONE, getpid(), audioServerAttributionSource(getpid()), flags,
               TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
         PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true),
                        *playbackThread, timeout)
@@ -2195,106 +2247,6 @@
 // ----------------------------------------------------------------------------
 
 
-// ----------------------------------------------------------------------------
-//      AppOp for audio recording
-// -------------------------------
-
-#undef LOG_TAG
-#define LOG_TAG "AF::OpRecordAudioMonitor"
-
-// static
-sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
-AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded(
-            const Identity& identity, const audio_attributes_t& attr)
-{
-    if (isServiceUid(identity.uid)) {
-        ALOGV("not silencing record for service %s",
-                identity.toString().c_str());
-        return nullptr;
-    }
-
-    // Capturing from FM TUNER output is not controlled by OP_RECORD_AUDIO
-    // because it does not affect users privacy as does capturing from an actual microphone.
-    if (attr.source == AUDIO_SOURCE_FM_TUNER) {
-        ALOGV("not muting FM TUNER capture for uid %d", identity.uid);
-        return nullptr;
-    }
-
-    Identity checkedIdentity = AudioFlinger::checkIdentityPackage(identity);
-    if (!checkedIdentity.packageName.has_value()
-            || checkedIdentity.packageName.value().size() == 0) {
-        return nullptr;
-    }
-    return new OpRecordAudioMonitor(checkedIdentity);
-}
-
-AudioFlinger::RecordThread::OpRecordAudioMonitor::OpRecordAudioMonitor(
-        const Identity& identity)
-        : mHasOpRecordAudio(true), mIdentity(identity)
-{
-}
-
-AudioFlinger::RecordThread::OpRecordAudioMonitor::~OpRecordAudioMonitor()
-{
-    if (mOpCallback != 0) {
-        mAppOpsManager.stopWatchingMode(mOpCallback);
-    }
-    mOpCallback.clear();
-}
-
-void AudioFlinger::RecordThread::OpRecordAudioMonitor::onFirstRef()
-{
-    checkRecordAudio();
-    mOpCallback = new RecordAudioOpCallback(this);
-    ALOGV("start watching OP_RECORD_AUDIO for %s", mIdentity.toString().c_str());
-    mAppOpsManager.startWatchingMode(AppOpsManager::OP_RECORD_AUDIO,
-        VALUE_OR_FATAL(aidl2legacy_string_view_String16(mIdentity.packageName.value_or(""))),
-        mOpCallback);
-}
-
-bool AudioFlinger::RecordThread::OpRecordAudioMonitor::hasOpRecordAudio() const {
-    return mHasOpRecordAudio.load();
-}
-
-// Called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
-// and in onFirstRef()
-// Note this method is never called (and never to be) for audio server / root track
-// due to the UID in createIfNeeded(). As a result for those record track, it's:
-// - not called from constructor,
-// - not called from RecordAudioOpCallback because the callback is not installed in this case
-void AudioFlinger::RecordThread::OpRecordAudioMonitor::checkRecordAudio()
-{
-
-    const int32_t mode = mAppOpsManager.checkOp(AppOpsManager::OP_RECORD_AUDIO,
-            mIdentity.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
-                mIdentity.packageName.value_or(""))));
-    const bool hasIt =  (mode == AppOpsManager::MODE_ALLOWED);
-    // verbose logging only log when appOp changed
-    ALOGI_IF(hasIt != mHasOpRecordAudio.load(),
-            "OP_RECORD_AUDIO missing, %ssilencing record %s",
-            hasIt ? "un" : "", mIdentity.toString().c_str());
-    mHasOpRecordAudio.store(hasIt);
-
-}
-
-AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback(
-        const wp<OpRecordAudioMonitor>& monitor) : mMonitor(monitor)
-{ }
-
-void AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
-            const String16& packageName) {
-    UNUSED(packageName);
-    if (op != AppOpsManager::OP_RECORD_AUDIO) {
-        return;
-    }
-    sp<OpRecordAudioMonitor> monitor = mMonitor.promote();
-    if (monitor != NULL) {
-        monitor->checkRecordAudio();
-    }
-}
-
-
-
 #undef LOG_TAG
 #define LOG_TAG "AF::RecordHandle"
 
@@ -2374,7 +2326,7 @@
             size_t bufferSize,
             audio_session_t sessionId,
             pid_t creatorPid,
-            const Identity& identity,
+            const AttributionSourceState& attributionSource,
             audio_input_flags_t flags,
             track_type type,
             audio_port_handle_t portId,
@@ -2382,7 +2334,7 @@
     :   TrackBase(thread, client, attr, sampleRate, format,
                   channelMask, frameCount, buffer, bufferSize, sessionId,
                   creatorPid,
-                  VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)),
+                  VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)),
                   false /*isOut*/,
                   (type == TYPE_DEFAULT) ?
                           ((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
@@ -2395,7 +2347,6 @@
         mRecordBufferConverter(NULL),
         mFlags(flags),
         mSilenced(false),
-        mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(identity, attr)),
         mStartFrames(startFrames)
 {
     if (mCblk == NULL) {
@@ -2654,14 +2605,6 @@
     mServerLatencyMs.store(latencyMs);
 }
 
-bool AudioFlinger::RecordThread::RecordTrack::isSilenced() const {
-    if (mSilenced) {
-        return true;
-    }
-    // The monitor is only created for record tracks that can be silenced.
-    return mOpRecordAudioMonitor ? !mOpRecordAudioMonitor->hasOpRecordAudio() : false;
-}
-
 status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones(
         std::vector<media::MicrophoneInfo>* activeMicrophones)
 {
@@ -2704,10 +2647,11 @@
         return PERMISSION_DENIED;
     }
 
-    Identity identity{};
-    identity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
-    identity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingPid));
-    if (!captureHotwordAllowed(identity)) {
+    AttributionSourceState attributionSource{};
+    attributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+    attributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingPid));
+    attributionSource.token = sp<BBinder>::make();
+    if (!captureHotwordAllowed(attributionSource)) {
         return PERMISSION_DENIED;
     }
 
@@ -2743,7 +2687,7 @@
                 audio_attributes_t{} /* currently unused for patch track */,
                 sampleRate, format, channelMask, frameCount,
                 buffer, bufferSize, AUDIO_SESSION_NONE, getpid(),
-                audioServerIdentity(getpid()), flags, TYPE_PATCH),
+                audioServerAttributionSource(getpid()), flags, TYPE_PATCH),
         PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true),
                        *recordThread, timeout)
 {
@@ -3020,19 +2964,19 @@
         audio_channel_mask_t channelMask,
         audio_session_t sessionId,
         bool isOut,
-        const Identity& identity,
+        const AttributionSourceState& attributionSource,
         pid_t creatorPid,
         audio_port_handle_t portId)
     :   TrackBase(thread, NULL, attr, sampleRate, format,
                   channelMask, (size_t)0 /* frameCount */,
                   nullptr /* buffer */, (size_t)0 /* bufferSize */,
                   sessionId, creatorPid,
-                  VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)),
+                  VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)),
                   isOut,
                   ALLOC_NONE,
                   TYPE_DEFAULT, portId,
                   std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
-        mPid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.pid))),
+        mPid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.pid))),
             mSilenced(false), mSilencedNotified(false)
 {
     // Once this item is logged by the server, the client can add properties.
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 5f052a5..2e49e71 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -17,15 +17,18 @@
 #ifndef ANDROID_AUDIOPOLICY_INTERFACE_H
 #define ANDROID_AUDIOPOLICY_INTERFACE_H
 
+#include <media/AudioCommonTypes.h>
 #include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
 #include <media/DeviceDescriptorBase.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <utils/String8.h>
 
 namespace android {
 
+using content::AttributionSourceState;
+
 // ----------------------------------------------------------------------------
 
 // The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication interfaces
@@ -123,7 +126,7 @@
                                         audio_io_handle_t *output,
                                         audio_session_t session,
                                         audio_stream_type_t *stream,
-                                        const media::permission::Identity& identity,
+                                        const AttributionSourceState& attributionSouce,
                                         const audio_config_t *config,
                                         audio_output_flags_t *flags,
                                         audio_port_handle_t *selectedDeviceId,
@@ -142,7 +145,7 @@
                                      audio_io_handle_t *input,
                                      audio_unique_id_t riid,
                                      audio_session_t session,
-                                     const media::permission::Identity& identity,
+                                     const AttributionSourceState& attributionSouce,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId,
@@ -453,6 +456,9 @@
     virtual void setSoundTriggerCaptureState(bool active) = 0;
 
     virtual status_t getAudioPort(struct audio_port_v7 *port) = 0;
+
+    virtual status_t updateSecondaryOutputs(
+            const TrackSecondaryOutputsMap& trackSecondaryOutputs) = 0;
 };
 
     // These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 552919d..577f641 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -42,7 +42,7 @@
 
 // For mixed output and inputs, the policy will use max mixer channel count.
 // Do not limit channel count otherwise
-#define MAX_MIXER_CHANNEL_COUNT FCC_8
+#define MAX_MIXER_CHANNEL_COUNT FCC_LIMIT
 
 /**
  * Alias to AUDIO_DEVICE_OUT_DEFAULT defined for clarification when this value is used by volume
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 59876c6..74b3405 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -109,6 +109,9 @@
     const std::vector<wp<SwAudioOutputDescriptor>>& getSecondaryOutputs() const {
         return mSecondaryOutputs;
     };
+    void setSecondaryOutputs(std::vector<wp<SwAudioOutputDescriptor>>&& secondaryOutputs) {
+        mSecondaryOutputs = std::move(secondaryOutputs);
+    }
     VolumeSource volumeSource() const { return mVolumeSource; }
     const sp<AudioPolicyMix> getPrimaryMix() const {
         return mPrimaryMix.promote();
@@ -143,7 +146,7 @@
     const product_strategy_t mStrategy;
     const VolumeSource mVolumeSource;
     const audio_output_flags_t mFlags;
-    const std::vector<wp<SwAudioOutputDescriptor>> mSecondaryOutputs;
+    std::vector<wp<SwAudioOutputDescriptor>> mSecondaryOutputs;
     const wp<AudioPolicyMix> mPrimaryMix;
     /**
      * required for duplicating thread, prevent from removing active client from an output
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 1c86051..81e803f 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -139,11 +139,24 @@
                                          Collection &collection);
 };
 
-using xmlCharUnique = std::unique_ptr<xmlChar, decltype(xmlFree)>;
+template <class T>
+constexpr void (*xmlDeleter)(T* t);
+template <>
+constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
+template <>
+constexpr auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
+
+/** @return a unique_ptr with the correct deleter for the libxml2 object. */
+template <class T>
+constexpr auto make_xmlUnique(T *t) {
+    // Wrap deleter in lambda to enable empty base optimization
+    auto deleter = [](T *t) { xmlDeleter<T>(t); };
+    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
+}
 
 std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
 {
-    xmlCharUnique charPtr(xmlGetProp(cur, reinterpret_cast<const xmlChar *>(attribute)), xmlFree);
+    auto charPtr = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar *>(attribute)));
     if (charPtr == NULL) {
         return "";
     }
@@ -441,7 +454,7 @@
     for (const xmlNode *child = referenceName.empty() ?
          root->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) {
         if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
-            xmlCharUnique pointXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
+            auto pointXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
             if (pointXml == NULL) {
                 return BAD_VALUE;
             }
@@ -471,14 +484,14 @@
 
     for (const xmlNode *child = root->xmlChildrenNode; child != NULL; child = child->next) {
         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::name)) {
-            xmlCharUnique nameXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
+            auto nameXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
             if (nameXml == nullptr) {
                 return BAD_VALUE;
             }
             name = reinterpret_cast<const char*>(nameXml.get());
         }
         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::indexMin)) {
-            xmlCharUnique indexMinXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
+            auto indexMinXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
             if (indexMinXml == nullptr) {
                 return BAD_VALUE;
             }
@@ -488,7 +501,7 @@
             }
         }
         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::indexMax)) {
-            xmlCharUnique indexMaxXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
+            auto indexMaxXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
             if (indexMaxXml == nullptr) {
                 return BAD_VALUE;
             }
@@ -548,7 +561,7 @@
     for (const xmlNode *child = referenceName.empty() ?
          cur->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) {
         if (!xmlStrcmp(child->name, (const xmlChar *)VolumeTraits::volumePointTag)) {
-            xmlCharUnique pointXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
+            auto pointXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
             if (pointXml == NULL) {
                 return BAD_VALUE;
             }
@@ -640,8 +653,7 @@
 
 ParsingResult parse(const char* path) {
     XmlErrorHandler errorHandler;
-    xmlDocPtr doc;
-    doc = xmlParseFile(path);
+    auto doc = make_xmlUnique(xmlParseFile(path));
     if (doc == NULL) {
         // It is OK not to find an engine config file at the default location
         // as the caller will default to hardcoded default config
@@ -650,13 +662,12 @@
         }
         return {nullptr, 0};
     }
-    xmlNodePtr cur = xmlDocGetRootElement(doc);
+    xmlNodePtr cur = xmlDocGetRootElement(doc.get());
     if (cur == NULL) {
         ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
-        xmlFreeDoc(doc);
         return {nullptr, 0};
     }
-    if (xmlXIncludeProcess(doc) < 0) {
+    if (xmlXIncludeProcess(doc.get()) < 0) {
         ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
         return {nullptr, 0};
     }
@@ -669,37 +680,35 @@
     auto config = std::make_unique<Config>();
     config->version = std::stof(version);
     deserializeCollection<ProductStrategyTraits>(
-                doc, cur, config->productStrategies, nbSkippedElements);
+                doc.get(), cur, config->productStrategies, nbSkippedElements);
     deserializeCollection<CriterionTraits>(
-                doc, cur, config->criteria, nbSkippedElements);
+                doc.get(), cur, config->criteria, nbSkippedElements);
     deserializeCollection<CriterionTypeTraits>(
-                doc, cur, config->criterionTypes, nbSkippedElements);
+                doc.get(), cur, config->criterionTypes, nbSkippedElements);
     deserializeCollection<VolumeGroupTraits>(
-                doc, cur, config->volumeGroups, nbSkippedElements);
+                doc.get(), cur, config->volumeGroups, nbSkippedElements);
 
     return {std::move(config), nbSkippedElements};
 }
 
 android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups) {
     XmlErrorHandler errorHandler;
-    xmlDocPtr doc;
-    doc = xmlParseFile(path);
+    auto doc = make_xmlUnique(xmlParseFile(path));
     if (doc == NULL) {
         ALOGE("%s: Could not parse document %s", __FUNCTION__, path);
         return BAD_VALUE;
     }
-    xmlNodePtr cur = xmlDocGetRootElement(doc);
+    xmlNodePtr cur = xmlDocGetRootElement(doc.get());
     if (cur == NULL) {
         ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
-        xmlFreeDoc(doc);
         return BAD_VALUE;
     }
-    if (xmlXIncludeProcess(doc) < 0) {
+    if (xmlXIncludeProcess(doc.get()) < 0) {
         ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
         return BAD_VALUE;
     }
     size_t nbSkippedElements = 0;
-    return deserializeLegacyVolumeCollection(doc, cur, volumeGroups, nbSkippedElements);
+    return deserializeLegacyVolumeCollection(doc.get(), cur, volumeGroups, nbSkippedElements);
 }
 
 android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups) {
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index b5885c0..76c35c1 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -200,6 +200,11 @@
     #
     ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
 
+    #
+    # Reaching 32 bit limit for inclusive criterion out devices: removing
+    #
+    ignored_output_device_values = ['BleSpeaker', 'BleHeadset']
+
     criteria_pattern = re.compile(
         r"\s*V\((?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
         r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*,\s*" \
@@ -235,7 +240,9 @@
             if criterion_name == "OutputDevicesMaskType":
                 if criterion_literal == "Default":
                     criterion_numerical_value = str(int("0x40000000", 0))
-
+                if criterion_literal in ignored_output_device_values:
+                    logging.info("OutputDevicesMaskType skipping {}".format(criterion_literal))
+                    continue
             try:
                 string_int = int(criterion_numerical_value, 0)
             except ValueError:
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index f67ffc1..ca8e96c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -186,6 +186,14 @@
                  (primaryOutput->getPolicyAudioPort()->getModuleVersionMajor() < 3))) {
                 availableOutputDevices = availPrimaryOutputDevices;
             }
+
+        }
+        // Do not use A2DP devices when in call but use them when not in call
+        // (e.g for voice mail playback)
+        if (isInCall()) {
+            availableOutputDevices.remove(availableOutputDevices.getDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, }));
         }
         } break;
     case STRATEGY_ACCESSIBILITY: {
diff --git a/services/audiopolicy/fuzzer/Android.bp b/services/audiopolicy/fuzzer/Android.bp
index 38bdedc..faf15d6 100644
--- a/services/audiopolicy/fuzzer/Android.bp
+++ b/services/audiopolicy/fuzzer/Android.bp
@@ -50,7 +50,7 @@
         "libbinder",
         "libaudiopolicy",
         "libaudiopolicymanagerdefault",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
     static_libs: [
         "android.hardware.audio.common@7.0-enums",
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 1177b95..7000cd9 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -26,7 +26,7 @@
 
 #include <Serializer.h>
 #include <android-base/file.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <libxml/parser.h>
 #include <libxml/xinclude.h>
 #include <media/AudioPolicy.h>
@@ -47,7 +47,7 @@
 using namespace ::android::audio::policy::configuration::V7_0;
 }
 
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 static const std::vector<audio_format_t> kAudioFormats = [] {
     std::vector<audio_format_t> result;
@@ -249,11 +249,12 @@
     *portId = AUDIO_PORT_HANDLE_NONE;
     AudioPolicyInterface::output_type_t outputType;
 
-    // TODO b/182392769: use identity util
-    Identity i;
-    i.uid = 0;
-    if (mManager->getOutputForAttr(&attr, output, AUDIO_SESSION_NONE, &stream, i, &config,
-                                   &flags, selectedDeviceId, portId, {}, &outputType) != OK) {
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource;
+    attributionSource.uid = 0;
+    attributionSource.token = sp<BBinder>::make();
+    if (mManager->getOutputForAttr(&attr, output, AUDIO_SESSION_NONE, &stream, attributionSource,
+            &config, &flags, selectedDeviceId, portId, {}, &outputType) != OK) {
         return false;
     }
     if (*output == AUDIO_IO_HANDLE_NONE || *portId == AUDIO_PORT_HANDLE_NONE) {
@@ -276,10 +277,11 @@
     *portId = AUDIO_PORT_HANDLE_NONE;
     AudioPolicyInterface::input_type_t inputType;
 
-    Identity i;
-    i.uid = 0;
-    if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, i, &config,
-                                  flags, selectedDeviceId, &inputType, portId) != OK) {
+    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) != OK) {
         return false;
     }
     if (*portId == AUDIO_PORT_HANDLE_NONE || input == AUDIO_IO_HANDLE_NONE) {
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index b111db4..0165dc8 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -34,7 +34,7 @@
         // a dependency on it in the device makefile. There will be no build time
         // conflict with libaudiopolicyenginedefault.
         "libaudiopolicyenginedefault",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
     ],
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 485188a..0c4608a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -31,6 +31,7 @@
 
 #include <algorithm>
 #include <inttypes.h>
+#include <map>
 #include <math.h>
 #include <set>
 #include <unordered_set>
@@ -52,7 +53,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 //FIXME: workaround for truncated touch sounds
 // to be removed when the problem is handled by system UI
@@ -1132,7 +1133,7 @@
                                               audio_io_handle_t *output,
                                               audio_session_t session,
                                               audio_stream_type_t *stream,
-                                              const Identity& identity,
+                                              const AttributionSourceState& attributionSource,
                                               const audio_config_t *config,
                                               audio_output_flags_t *flags,
                                               audio_port_handle_t *selectedDeviceId,
@@ -1145,7 +1146,7 @@
         return INVALID_OPERATION;
     }
     const uid_t uid = VALUE_OR_RETURN_STATUS(
-        aidl2legacy_int32_t_uid_t(identity.uid));
+        aidl2legacy_int32_t_uid_t(attributionSource.uid));
     const audio_port_handle_t requestedPortId = *selectedDeviceId;
     audio_attributes_t resultAttr;
     bool isRequestedDeviceForExclusiveUse = false;
@@ -2114,7 +2115,7 @@
                                              audio_io_handle_t *input,
                                              audio_unique_id_t riid,
                                              audio_session_t session,
-                                             const Identity& identity,
+                                             const AttributionSourceState& attributionSource,
                                              const audio_config_base_t *config,
                                              audio_input_flags_t flags,
                                              audio_port_handle_t *selectedDeviceId,
@@ -2133,7 +2134,7 @@
     sp<AudioInputDescriptor> inputDesc;
     sp<RecordClientDescriptor> clientDesc;
     audio_port_handle_t requestedDeviceId = *selectedDeviceId;
-    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(identity.uid));
+    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid));
     bool isSoundTrigger;
 
     // The supplied portId must be AUDIO_PORT_HANDLE_NONE
@@ -5694,6 +5695,7 @@
 
 void AudioPolicyManager::checkSecondaryOutputs() {
     std::set<audio_stream_type_t> streamsToInvalidate;
+    TrackSecondaryOutputsMap trackSecondaryOutputs;
     for (size_t i = 0; i < mOutputs.size(); i++) {
         const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
         for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
@@ -5710,16 +5712,28 @@
                 }
             }
 
-            if (status != OK ||
-                !std::equal(client->getSecondaryOutputs().begin(),
-                            client->getSecondaryOutputs().end(),
-                            secondaryDescs.begin(), secondaryDescs.end())) {
+            if (status != OK) {
                 streamsToInvalidate.insert(client->stream());
+            } else if (!std::equal(
+                    client->getSecondaryOutputs().begin(),
+                    client->getSecondaryOutputs().end(),
+                    secondaryDescs.begin(), secondaryDescs.end())) {
+                std::vector<wp<SwAudioOutputDescriptor>> weakSecondaryDescs;
+                std::vector<audio_io_handle_t> secondaryOutputIds;
+                for (const auto& secondaryDesc : secondaryDescs) {
+                    secondaryOutputIds.push_back(secondaryDesc->mIoHandle);
+                    weakSecondaryDescs.push_back(secondaryDesc);
+                }
+                trackSecondaryOutputs.emplace(client->portId(), secondaryOutputIds);
+                client->setSecondaryOutputs(std::move(weakSecondaryDescs));
             }
         }
     }
+    if (!trackSecondaryOutputs.empty()) {
+        mpClientInterface->updateSecondaryOutputs(trackSecondaryOutputs);
+    }
     for (audio_stream_type_t stream : streamsToInvalidate) {
-        ALOGD("%s Invalidate stream %d due to secondary output change", __func__, stream);
+        ALOGD("%s Invalidate stream %d due to fail getting output for attr", __func__, stream);
         mpClientInterface->invalidateStream(stream);
     }
 }
@@ -5833,11 +5847,12 @@
         // With low-latency playing on speaker, music on WFD, when the first low-latency
         // output is stopped, getNewOutputDevices checks for a product strategy
         // from the list, as STRATEGY_SONIFICATION comes prior to STRATEGY_MEDIA.
-        // If an ALARM or ENFORCED_AUDIBLE stream is supported by the product strategy,
+        // If an ALARM, RING or ENFORCED_AUDIBLE stream is supported by the product strategy,
         // devices are returned for STRATEGY_SONIFICATION without checking whether the
         // stream is associated to the output descriptor.
         if (doGetOutputDevicesForVoice() || outputDesc->isStrategyActive(productStrategy) ||
                ((hasStreamActive(AUDIO_STREAM_ALARM) ||
+                hasStreamActive(AUDIO_STREAM_RING) ||
                 hasStreamActive(AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
                 mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) {
             // Retrieval of devices for voice DL is done on primary output profile, cannot
@@ -6439,8 +6454,9 @@
                 volumeDb = minVolDb;
                 ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDb, musicVolDb);
             }
-            if (!Intersection(deviceTypes, {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
-                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}).empty()) {
+            if (Volume::getDeviceForVolume(deviceTypes) != AUDIO_DEVICE_OUT_SPEAKER
+                    &&  !Intersection(deviceTypes, {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}).empty()) {
                 // on A2DP, also ensure notification volume is not too low compared to media when
                 // intended to be played
                 if ((volumeDb > -96.0f) &&
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index f5dd20c..98f96d1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -52,6 +52,8 @@
 
 namespace android {
 
+using content::AttributionSourceState;
+
 // ----------------------------------------------------------------------------
 
 // Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
@@ -116,7 +118,7 @@
                                   audio_io_handle_t *output,
                                   audio_session_t session,
                                   audio_stream_type_t *stream,
-                                  const media::permission::Identity& identity,
+                                  const AttributionSourceState& attributionSource,
                                   const audio_config_t *config,
                                   audio_output_flags_t *flags,
                                   audio_port_handle_t *selectedDeviceId,
@@ -130,7 +132,7 @@
                                          audio_io_handle_t *input,
                                          audio_unique_id_t riid,
                                          audio_session_t session,
-                                         const media::permission::Identity& identity,
+                                         const AttributionSourceState& attributionSource,
                                          const audio_config_base_t *config,
                                          audio_input_flags_t flags,
                                          audio_port_handle_t *selectedDeviceId,
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index 14be671..454c020 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -38,6 +38,7 @@
         "libmedia_helper",
         "libmediametrics",
         "libmediautils",
+        "libpermission",
         "libsensorprivacy",
         "libutils",
         "audioclient-types-aidl-cpp",
@@ -45,12 +46,12 @@
         "audiopolicy-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     static_libs: [
         "libaudiopolicycomponents",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     header_libs: [
@@ -70,6 +71,6 @@
     export_shared_lib_headers: [
         "libactivitymanager_aidl",
         "libsensorprivacy",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 }
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 77b5200..cd53073 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -291,4 +291,14 @@
     return af->getAudioPort(port);
 }
 
+status_t AudioPolicyService::AudioPolicyClient::updateSecondaryOutputs(
+        const TrackSecondaryOutputsMap& trackSecondaryOutputs) {
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == nullptr) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return PERMISSION_DENIED;
+    }
+    return af->updateSecondaryOutputs(trackSecondaryOutputs);
+}
+
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 8426a77..3f01de9 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -35,7 +35,7 @@
 
 namespace android {
 
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 // ----------------------------------------------------------------------------
 // AudioPolicyEffects Implementation
@@ -123,9 +123,10 @@
         Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
         for (size_t i = 0; i < effects.size(); i++) {
             EffectDesc *effect = effects[i];
-            Identity identity;
-            identity.packageName = "android";
-            sp<AudioEffect> fx = new AudioEffect(identity);
+            AttributionSourceState attributionSource;
+            attributionSource.packageName = "android";
+            attributionSource.token = sp<BBinder>::make();
+            sp<AudioEffect> fx = new AudioEffect(attributionSource);
             fx->set(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
             status_t status = fx->initCheck();
             if (status != NO_ERROR && status != ALREADY_EXISTS) {
@@ -274,9 +275,10 @@
         Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
         for (size_t i = 0; i < effects.size(); i++) {
             EffectDesc *effect = effects[i];
-            Identity identity;
-            identity.packageName = "android";
-            sp<AudioEffect> fx = new AudioEffect(identity);
+            AttributionSourceState attributionSource;
+            attributionSource.packageName = "android";
+            attributionSource.token = sp<BBinder>::make();
+            sp<AudioEffect> fx = new AudioEffect(attributionSource);
             fx->set(NULL, &effect->mUuid, 0, 0, 0, audioSession, output);
             status_t status = fx->initCheck();
             if (status != NO_ERROR && status != ALREADY_EXISTS) {
@@ -976,9 +978,10 @@
     for (const auto& deviceEffectsIter : mDeviceEffects) {
         const auto& deviceEffects =  deviceEffectsIter.second;
         for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) {
-            Identity identity;
-            identity.packageName = "android";
-            sp<AudioEffect> fx = new AudioEffect(identity);
+            AttributionSourceState attributionSource;
+            attributionSource.packageName = "android";
+            attributionSource.token = sp<BBinder>::make();
+            sp<AudioEffect> fx = new AudioEffect(attributionSource);
             fx->set(EFFECT_UUID_NULL, &effectDesc->mUuid, 0, nullptr,
                     nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE,
                     AudioDeviceTypeAddr{deviceEffects->getDeviceType(),
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 551013f..b4b6ddf 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -25,7 +25,7 @@
 #include <media/MediaMetricsItem.h>
 #include <media/PolicyAidlConversion.h>
 #include <utils/Log.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #define VALUE_OR_RETURN_BINDER_STATUS(x) \
     ({ auto _tmp = (x); \
@@ -43,7 +43,7 @@
 namespace android {
 using binder::Status;
 using aidl_utils::binderStatusFromStatusT;
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 const std::vector<audio_usage_t>& SYSTEM_USAGES = {
     AUDIO_USAGE_CALL_ASSISTANT,
@@ -64,15 +64,16 @@
 }
 
 status_t AudioPolicyService::validateUsage(audio_usage_t usage) {
-     return validateUsage(usage, getCallingIdentity());
+     return validateUsage(usage, getCallingAttributionSource());
 }
 
-status_t AudioPolicyService::validateUsage(audio_usage_t usage, const Identity& identity) {
+status_t AudioPolicyService::validateUsage(audio_usage_t usage,
+        const AttributionSourceState& attributionSource) {
     if (isSystemUsage(usage)) {
         if (isSupportedSystemUsage(usage)) {
-            if (!modifyAudioRoutingAllowed(identity)) {
+            if (!modifyAudioRoutingAllowed(attributionSource)) {
                 ALOGE(("permission denied: modify audio routing not allowed "
-                       "for identity %s"), identity.toString().c_str());
+                       "for attributionSource %s"), attributionSource.toString().c_str());
                 return PERMISSION_DENIED;
             }
         } else {
@@ -279,7 +280,7 @@
 
 Status AudioPolicyService::getOutputForAttr(const media::AudioAttributesInternal& attrAidl,
                                             int32_t sessionAidl,
-                                            const Identity& identity,
+                                            const AttributionSourceState& attributionSource,
                                             const media::AudioConfig& configAidl,
                                             int32_t flagsAidl,
                                             int32_t selectedDeviceIdAidl,
@@ -307,28 +308,28 @@
 
     RETURN_IF_BINDER_ERROR(
             binderStatusFromStatusT(AudioValidator::validateAudioAttributes(attr, "68953950")));
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage, identity)));
+    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage, attributionSource)));
 
     ALOGV("%s()", __func__);
     Mutex::Autolock _l(mLock);
 
     // TODO b/182392553: refactor or remove
-    Identity adjIdentity = identity;
+    AttributionSourceState adjAttributionSource = attributionSource;
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!isAudioServerOrMediaServerUid(callingUid) || identity.uid == -1) {
+    if (!isAudioServerOrMediaServerUid(callingUid) || attributionSource.uid == -1) {
         int32_t callingUidAidl = VALUE_OR_RETURN_BINDER_STATUS(
             legacy2aidl_uid_t_int32_t(callingUid));
-        ALOGW_IF(identity.uid != -1 && identity.uid != callingUidAidl,
+        ALOGW_IF(attributionSource.uid != -1 && attributionSource.uid != callingUidAidl,
                 "%s uid %d tried to pass itself off as %d", __func__,
-                callingUidAidl, identity.uid);
-        adjIdentity.uid = callingUidAidl;
+                callingUidAidl, attributionSource.uid);
+        adjAttributionSource.uid = callingUidAidl;
     }
     if (!mPackageManager.allowPlaybackCapture(VALUE_OR_RETURN_BINDER_STATUS(
-        aidl2legacy_int32_t_uid_t(adjIdentity.uid)))) {
+        aidl2legacy_int32_t_uid_t(adjAttributionSource.uid)))) {
         attr.flags = static_cast<audio_flags_mask_t>(attr.flags | AUDIO_FLAG_NO_MEDIA_PROJECTION);
     }
     if (((attr.flags & (AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE)) != 0)
-            && !bypassInterruptionPolicyAllowed(identity)) {
+            && !bypassInterruptionPolicyAllowed(adjAttributionSource)) {
         attr.flags = static_cast<audio_flags_mask_t>(
                 attr.flags & ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE));
     }
@@ -336,7 +337,7 @@
     AudioPolicyInterface::output_type_t outputType;
     status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
                                                             &stream,
-                                                            adjIdentity,
+                                                            adjAttributionSource,
                                                             &config,
                                                             &flags, &selectedDeviceId, &portId,
                                                             &secondaryOutputs,
@@ -349,16 +350,16 @@
         case AudioPolicyInterface::API_OUTPUT_LEGACY:
             break;
         case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
-            if (!modifyPhoneStateAllowed(adjIdentity)) {
+            if (!modifyPhoneStateAllowed(adjAttributionSource)) {
                 ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
-                    __func__, adjIdentity.uid);
+                    __func__, adjAttributionSource.uid);
                 result = PERMISSION_DENIED;
             }
             break;
         case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
-            if (!modifyAudioRoutingAllowed(adjIdentity)) {
+            if (!modifyAudioRoutingAllowed(adjAttributionSource)) {
                 ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
-                    __func__, adjIdentity.uid);
+                    __func__, adjAttributionSource.uid);
                 result = PERMISSION_DENIED;
             }
             break;
@@ -371,7 +372,7 @@
 
     if (result == NO_ERROR) {
         sp<AudioPlaybackClient> client =
-                new AudioPlaybackClient(attr, output, adjIdentity, session,
+                new AudioPlaybackClient(attr, output, adjAttributionSource, session,
                     portId, selectedDeviceId, stream);
         mAudioPlaybackClients.add(portId, client);
 
@@ -508,7 +509,7 @@
                                            int32_t inputAidl,
                                            int32_t riidAidl,
                                            int32_t sessionAidl,
-                                           const Identity& identity,
+                                           const AttributionSourceState& attributionSource,
                                            const media::AudioConfigBase& configAidl,
                                            int32_t flagsAidl,
                                            int32_t selectedDeviceIdAidl,
@@ -551,42 +552,46 @@
         return binderStatusFromStatusT(BAD_VALUE);
     }
 
-    // Make sure identity represents the current caller
-    Identity adjIdentity = identity;
+    // Make sure attribution source represents the current caller
+    AttributionSourceState adjAttributionSource = attributionSource;
     // TODO b/182392553: refactor or remove
-    bool updatePid = (identity.pid == -1);
+    bool updatePid = (attributionSource.pid == -1);
     const uid_t callingUid =IPCThreadState::self()->getCallingUid();
-    const uid_t currentUid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(identity.uid));
+    const uid_t currentUid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(
+            attributionSource.uid));
     if (!isAudioServerOrMediaServerUid(callingUid)) {
         ALOGW_IF(currentUid != (uid_t)-1 && currentUid != callingUid,
                 "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid,
                 currentUid);
-        adjIdentity.uid = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+        adjAttributionSource.uid = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_uid_t_int32_t(
+                callingUid));
         updatePid = true;
     }
 
     if (updatePid) {
         const int32_t callingPid = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_pid_t_int32_t(
             IPCThreadState::self()->getCallingPid()));
-        ALOGW_IF(identity.pid != -1 && identity.pid != callingPid,
+        ALOGW_IF(attributionSource.pid != -1 && attributionSource.pid != callingPid,
                  "%s uid %d pid %d tried to pass itself off as pid %d",
-                 __func__, adjIdentity.uid, callingPid, identity.pid);
-        adjIdentity.pid = callingPid;
+                 __func__, adjAttributionSource.uid, callingPid, attributionSource.pid);
+        adjAttributionSource.pid = callingPid;
     }
 
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage, adjIdentity)));
+    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage,
+            adjAttributionSource)));
 
     // check calling permissions.
     // Capturing from FM_TUNER source is controlled by captureTunerAudioInputAllowed() and
     // captureAudioOutputAllowed() (deprecated) as this does not affect users privacy
     // as does capturing from an actual microphone.
-    if (!(recordingAllowed(adjIdentity) || attr.source == AUDIO_SOURCE_FM_TUNER)) {
+    if (!(recordingAllowed(adjAttributionSource, attr.source)
+            || attr.source == AUDIO_SOURCE_FM_TUNER)) {
         ALOGE("%s permission denied: recording not allowed for %s",
-                __func__, adjIdentity.toString().c_str());
+                __func__, adjAttributionSource.toString().c_str());
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
-    bool canCaptureOutput = captureAudioOutputAllowed(adjIdentity);
+    bool canCaptureOutput = captureAudioOutputAllowed(adjAttributionSource);
     if ((inputSource == AUDIO_SOURCE_VOICE_UPLINK ||
         inputSource == AUDIO_SOURCE_VOICE_DOWNLINK ||
         inputSource == AUDIO_SOURCE_VOICE_CALL ||
@@ -596,12 +601,12 @@
     }
 
     if (inputSource == AUDIO_SOURCE_FM_TUNER
-        && !captureTunerAudioInputAllowed(adjIdentity)
+        && !captureTunerAudioInputAllowed(adjAttributionSource)
         && !canCaptureOutput) {
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
-    bool canCaptureHotword = captureHotwordAllowed(adjIdentity);
+    bool canCaptureHotword = captureHotwordAllowed(adjAttributionSource);
     if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
@@ -609,7 +614,7 @@
     if (((flags & AUDIO_INPUT_FLAG_HW_HOTWORD) != 0)
             && !canCaptureHotword) {
         ALOGE("%s: permission denied: hotword mode not allowed"
-              " for uid %d pid %d", __func__, adjIdentity.uid, adjIdentity.pid);
+              " for uid %d pid %d", __func__, adjAttributionSource.uid, adjAttributionSource.pid);
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
@@ -623,7 +628,7 @@
             AutoCallerClear acc;
             // the audio_in_acoustics_t parameter is ignored by get_input()
             status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
-                                                          adjIdentity, &config,
+                                                          adjAttributionSource, &config,
                                                           flags, &selectedDeviceId,
                                                           &inputType, &portId);
 
@@ -647,7 +652,7 @@
                 }
                 break;
             case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
-                if (!modifyAudioRoutingAllowed(adjIdentity)) {
+                if (!modifyAudioRoutingAllowed(adjAttributionSource)) {
                     ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
                     status = PERMISSION_DENIED;
                 }
@@ -668,8 +673,9 @@
         }
 
         sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
-                                                             selectedDeviceId, adjIdentity,
-                                                             canCaptureOutput, canCaptureHotword);
+                                                             selectedDeviceId, adjAttributionSource,
+                                                             canCaptureOutput, canCaptureHotword,
+                                                             mAudioCommandThread);
         mAudioRecordClients.add(portId, client);
     }
 
@@ -723,11 +729,11 @@
     msg << "Audio recording on session " << client->session;
 
     // check calling permissions
-    if (!(startRecording(client->identity, String16(msg.str().c_str()),
+    if (!(startRecording(client->attributionSource, String16(msg.str().c_str()),
         client->attributes.source)
             || client->attributes.source == AUDIO_SOURCE_FM_TUNER)) {
-        ALOGE("%s permission denied: recording not allowed for identity %s",
-                __func__, client->identity.toString().c_str());
+        ALOGE("%s permission denied: recording not allowed for attribution source %s",
+                __func__, client->attributionSource.toString().c_str());
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
@@ -771,13 +777,13 @@
             item->setCString(kAudioPolicyRqstSrc,
                              toString(client->attributes.source).c_str());
             item->setInt32(kAudioPolicyRqstSession, client->session);
-            if (client->identity.packageName.has_value() &&
-                client->identity.packageName.value().size() != 0) {
+            if (client->attributionSource.packageName.has_value() &&
+                client->attributionSource.packageName.value().size() != 0) {
                 item->setCString(kAudioPolicyRqstPkg,
-                    client->identity.packageName.value().c_str());
+                    client->attributionSource.packageName.value().c_str());
             } else {
                 item->setCString(kAudioPolicyRqstPkg,
-                    std::to_string(client->identity.uid).c_str());
+                    std::to_string(client->attributionSource.uid).c_str());
             }
             item->setCString(
                     kAudioPolicyRqstDevice, getDeviceTypeStrForPortId(client->deviceId).c_str());
@@ -793,13 +799,13 @@
                     item->setCString(kAudioPolicyActiveSrc,
                                      toString(other->attributes.source).c_str());
                     item->setInt32(kAudioPolicyActiveSession, other->session);
-                    if (other->identity.packageName.has_value() &&
-                        other->identity.packageName.value().size() != 0) {
+                    if (other->attributionSource.packageName.has_value() &&
+                        other->attributionSource.packageName.value().size() != 0) {
                         item->setCString(kAudioPolicyActivePkg,
-                            other->identity.packageName.value().c_str());
+                            other->attributionSource.packageName.value().c_str());
                     } else {
                         item->setCString(kAudioPolicyRqstPkg, std::to_string(
-                            other->identity.uid).c_str());
+                            other->attributionSource.uid).c_str());
                     }
                     item->setCString(kAudioPolicyActiveDevice,
                                      getDeviceTypeStrForPortId(other->deviceId).c_str());
@@ -815,7 +821,7 @@
         client->active = false;
         client->startTimeNs = 0;
         updateUidStates_l();
-        finishRecording(client->identity, client->attributes.source);
+        finishRecording(client->attributionSource, client->attributes.source);
     }
 
     return binderStatusFromStatusT(status);
@@ -844,7 +850,7 @@
     updateUidStates_l();
 
     // finish the recording app op
-    finishRecording(client->identity, client->attributes.source);
+    finishRecording(client->attributionSource, client->attributes.source);
     AutoCallerClear acc;
     return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId));
 }
@@ -1641,15 +1647,15 @@
     bool needCaptureMediaOutput = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
             return mix.mAllowPrivilegedMediaPlaybackCapture; });
 
-    const Identity identity = getCallingIdentity();
+    const AttributionSourceState attributionSource = getCallingAttributionSource();
 
 
-    if (needCaptureMediaOutput && !captureMediaOutputAllowed(identity)) {
+    if (needCaptureMediaOutput && !captureMediaOutputAllowed(attributionSource)) {
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
     if (needCaptureVoiceCommunicationOutput &&
-        !captureVoiceCommunicationOutputAllowed(identity)) {
+        !captureVoiceCommunicationOutputAllowed(attributionSource)) {
         return binderStatusFromStatusT(PERMISSION_DENIED);
     }
 
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index fb38e3d..5df5f1d 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -594,7 +594,8 @@
 
     for (size_t i =0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
-        uid_t currentUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(current->identity.uid));
+        uid_t currentUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
+                current->attributionSource.uid));
         if (!current->active) {
             continue;
         }
@@ -641,7 +642,7 @@
                             || (isInCommunication && currentUid == mPhoneStateOwnerUid)) {
                         if (!isInCommunication || latestSensitiveActiveOrComm == nullptr
                                 || VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
-                                    latestSensitiveActiveOrComm->identity.uid))
+                                    latestSensitiveActiveOrComm->attributionSource.uid))
                                         != mPhoneStateOwnerUid) {
                             latestSensitiveActiveOrComm = current;
                             latestSensitiveStartNs = current->startTimeNs;
@@ -676,7 +677,7 @@
         // if audio mode is IN_COMMUNICATION, favor audio mode owner over an app with
         // foreground UI in case both are capturing with privacy sensitive flag.
         uid_t latestActiveUid = VALUE_OR_FATAL(
-            aidl2legacy_int32_t_uid_t(latestSensitiveActiveOrComm->identity.uid));
+            aidl2legacy_int32_t_uid_t(latestSensitiveActiveOrComm->attributionSource.uid));
         if (isInCommunication && latestActiveUid == mPhoneStateOwnerUid) {
             topSensitiveActive = latestSensitiveActiveOrComm;
             topSensitiveStartNs = latestSensitiveStartNs;
@@ -696,20 +697,20 @@
     for (size_t i =0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
         uid_t currentUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
-            current->identity.uid));
+            current->attributionSource.uid));
         if (!current->active) {
             continue;
         }
 
         audio_source_t source = current->attributes.source;
         bool isTopOrLatestActive = topActive == nullptr ? false :
-            current->identity.uid == topActive->identity.uid;
+            current->attributionSource.uid == topActive->attributionSource.uid;
         bool isTopOrLatestSensitive = topSensitiveActive == nullptr ? false :
-            current->identity.uid == topSensitiveActive->identity.uid;
+            current->attributionSource.uid == topSensitiveActive->attributionSource.uid;
 
         auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) REQUIRES(mLock) {
             uid_t recordUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
-                recordClient->identity.uid));
+                recordClient->attributionSource.uid));
             bool canCaptureCall = recordClient->canCaptureOutput;
             bool canCaptureCommunication = recordClient->canCaptureOutput
                 || !isPhoneStateOwnerActive
@@ -729,7 +730,10 @@
                     && !(isTopOrLatestSensitive || current->canCaptureOutput))
                 && canCaptureIfInCallOrCommunication(current);
 
-        if (isVirtualSource(source)) {
+        if (!current->hasOp()) {
+            // Never allow capture if app op is denied
+            allowCapture = false;
+        } else if (isVirtualSource(source)) {
             // Allow capture for virtual (remote submix, call audio TX or RX...) sources
             allowCapture = true;
         } else if (mUidPolicy->isAssistantUid(currentUid)) {
@@ -785,7 +789,7 @@
                 allowCapture = true;
             }
         }
-        setAppState_l(current->portId,
+        setAppState_l(current,
                       allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(currentUid)) :
                                 APP_STATE_IDLE);
     }
@@ -795,7 +799,7 @@
     for (size_t i = 0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
         if (!isVirtualSource(current->attributes.source)) {
-            setAppState_l(current->portId, APP_STATE_IDLE);
+            setAppState_l(current, APP_STATE_IDLE);
         }
     }
 }
@@ -829,17 +833,45 @@
     return false;
 }
 
-void AudioPolicyService::setAppState_l(audio_port_handle_t portId, app_state_t state)
+/* static */
+bool AudioPolicyService::isAppOpSource(audio_source_t source)
+{
+    switch (source) {
+        case AUDIO_SOURCE_FM_TUNER:
+        case AUDIO_SOURCE_ECHO_REFERENCE:
+            return false;
+        default:
+            break;
+    }
+    return true;
+}
+
+void AudioPolicyService::setAppState_l(sp<AudioRecordClient> client, app_state_t state)
 {
     AutoCallerClear acc;
 
     if (mAudioPolicyManager) {
-        mAudioPolicyManager->setAppState(portId, state);
+        mAudioPolicyManager->setAppState(client->portId, state);
     }
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af) {
         bool silenced = state == APP_STATE_IDLE;
-        af->setRecordSilenced(portId, silenced);
+        if (client->silenced != silenced) {
+            if (client->active) {
+                if (silenced) {
+                    finishRecording(client->attributionSource, client->attributes.source);
+                } else {
+                    std::stringstream msg;
+                    msg << "Audio recording un-silenced on session " << client->session;
+                    if (!startRecording(client->attributionSource, String16(msg.str().c_str()),
+                            client->attributes.source)) {
+                        silenced = true;
+                    }
+                }
+            }
+            af->setRecordSilenced(client->portId, silenced);
+            client->silenced = silenced;
+        }
     }
 }
 
@@ -1402,6 +1434,109 @@
     return binder::Status::ok();
 }
 
+// -----------  AudioPolicyService::OpRecordAudioMonitor implementation ----------
+
+// static
+sp<AudioPolicyService::OpRecordAudioMonitor>
+AudioPolicyService::OpRecordAudioMonitor::createIfNeeded(
+            const AttributionSourceState& attributionSource, const audio_attributes_t& attr,
+            wp<AudioCommandThread> commandThread)
+{
+    if (isServiceUid(attributionSource.uid)) {
+        ALOGV("not silencing record for service %s",
+                attributionSource.toString().c_str());
+        return nullptr;
+    }
+
+    if (!AudioPolicyService::isAppOpSource(attr.source)) {
+        ALOGD("not monitoring app op for uid %d and source %d",
+                attributionSource.uid, attr.source);
+        return nullptr;
+    }
+
+    if (!attributionSource.packageName.has_value()
+            || attributionSource.packageName.value().size() == 0) {
+        return nullptr;
+    }
+    return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread);
+}
+
+AudioPolicyService::OpRecordAudioMonitor::OpRecordAudioMonitor(
+        const AttributionSourceState& attributionSource, int32_t appOp,
+        wp<AudioCommandThread> commandThread) :
+            mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp),
+            mCommandThread(commandThread)
+{
+}
+
+AudioPolicyService::OpRecordAudioMonitor::~OpRecordAudioMonitor()
+{
+    if (mOpCallback != 0) {
+        mAppOpsManager.stopWatchingMode(mOpCallback);
+    }
+    mOpCallback.clear();
+}
+
+void AudioPolicyService::OpRecordAudioMonitor::onFirstRef()
+{
+    checkOp();
+    mOpCallback = new RecordAudioOpCallback(this);
+    ALOGV("start watching op %d for %s", mAppOp, mAttributionSource.toString().c_str());
+    // TODO: We need to always watch AppOpsManager::OP_RECORD_AUDIO too
+    // since it controls the mic permission for legacy apps.
+    mAppOpsManager.startWatchingMode(mAppOp, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
+        mAttributionSource.packageName.value_or(""))),
+        mOpCallback);
+}
+
+bool AudioPolicyService::OpRecordAudioMonitor::hasOp() const {
+    return mHasOp.load();
+}
+
+// Called by RecordAudioOpCallback when the app op corresponding to this OpRecordAudioMonitor
+// is updated in AppOp callback and in onFirstRef()
+// Note this method is never called (and never to be) for audio server / root track
+// due to the UID in createIfNeeded(). As a result for those record track, it's:
+// - not called from constructor,
+// - not called from RecordAudioOpCallback because the callback is not installed in this case
+void AudioPolicyService::OpRecordAudioMonitor::checkOp(bool updateUidStates)
+{
+    // TODO: We need to always check AppOpsManager::OP_RECORD_AUDIO too
+    // since it controls the mic permission for legacy apps.
+    const int32_t mode = mAppOpsManager.checkOp(mAppOp,
+            mAttributionSource.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
+                mAttributionSource.packageName.value_or(""))));
+    const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
+    // verbose logging only log when appOp changed
+    ALOGI_IF(hasIt != mHasOp.load(),
+            "App op %d missing, %ssilencing record %s",
+            mAppOp, hasIt ? "un" : "", mAttributionSource.toString().c_str());
+    mHasOp.store(hasIt);
+
+    if (updateUidStates) {
+          sp<AudioCommandThread> commandThread = mCommandThread.promote();
+          if (commandThread != nullptr) {
+              commandThread->updateUidStatesCommand();
+          }
+    }
+}
+
+AudioPolicyService::OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback(
+        const wp<OpRecordAudioMonitor>& monitor) : mMonitor(monitor)
+{ }
+
+void AudioPolicyService::OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
+            const String16& packageName __unused) {
+    sp<OpRecordAudioMonitor> monitor = mMonitor.promote();
+    if (monitor != NULL) {
+        if (op != monitor->getOp()) {
+            return;
+        }
+        monitor->checkOp(true);
+    }
+}
+
+
 // -----------  AudioPolicyService::AudioCommandThread implementation ----------
 
 AudioPolicyService::AudioCommandThread::AudioCommandThread(String8 name,
@@ -1618,6 +1753,17 @@
                     mLock.lock();
                     } break;
 
+                case UPDATE_UID_STATES: {
+                    ALOGV("AudioCommandThread() processing updateUID states");
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->updateUidStates();
+                    mLock.lock();
+                    } break;
+
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                 }
@@ -1831,6 +1977,14 @@
     sendCommand(command);
 }
 
+void AudioPolicyService::AudioCommandThread::updateUidStatesCommand()
+{
+    sp<AudioCommand> command = new AudioCommand();
+    command->mCommand = UPDATE_UID_STATES;
+    ALOGV("AudioCommandThread() adding update UID states");
+    sendCommand(command);
+}
+
 void AudioPolicyService::AudioCommandThread::updateAudioPatchListCommand()
 {
     sp<AudioCommand>command = new AudioCommand();
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 00d9670..3b77ed8 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2009 The Android Open Source Project
  *
@@ -26,6 +27,7 @@
 #include <utils/Vector.h>
 #include <utils/SortedVector.h>
 #include <binder/ActivityManager.h>
+#include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IUidObserver.h>
 #include <system/audio.h>
@@ -38,12 +40,14 @@
 #include "CaptureStateNotifier.h"
 #include <AudioPolicyInterface.h>
 #include <android/hardware/BnSensorPrivacyListener.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #include <unordered_map>
 
 namespace android {
 
+using content::AttributionSourceState;
+
 // ----------------------------------------------------------------------------
 
 class AudioPolicyService :
@@ -81,7 +85,7 @@
                                media::AudioPolicyForcedConfig* _aidl_return) override;
     binder::Status getOutput(media::AudioStreamType stream, int32_t* _aidl_return) override;
     binder::Status getOutputForAttr(const media::AudioAttributesInternal& attr, int32_t session,
-                                    const media::permission::Identity &identity,
+                                    const AttributionSourceState &attributionSource,
                                     const media::AudioConfig& config,
                                     int32_t flags, int32_t selectedDeviceId,
                                     media::GetOutputForAttrResponse* _aidl_return) override;
@@ -90,7 +94,7 @@
     binder::Status releaseOutput(int32_t portId) override;
     binder::Status getInputForAttr(const media::AudioAttributesInternal& attr, int32_t input,
                                    int32_t riid, int32_t session,
-                                   const media::permission::Identity &identity,
+                                   const AttributionSourceState &attributionSource,
                                    const media::AudioConfigBase& config, int32_t flags,
                                    int32_t selectedDeviceId,
                                    media::GetInputForAttrResponse* _aidl_return) override;
@@ -321,8 +325,10 @@
     // Handles binder shell commands
     virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
 
+    class AudioRecordClient;
+
     // Sets whether the given UID records only silence
-    virtual void setAppState_l(audio_port_handle_t portId, app_state_t state) REQUIRES(mLock);
+    virtual void setAppState_l(sp<AudioRecordClient> client, app_state_t state) REQUIRES(mLock);
 
     // Overrides the UID state as if it is idle
     status_t handleSetUidState(Vector<String16>& args, int err);
@@ -344,7 +350,7 @@
 
     bool isSupportedSystemUsage(audio_usage_t usage);
     status_t validateUsage(audio_usage_t usage);
-    status_t validateUsage(audio_usage_t usage, const media::permission::Identity& identity);
+    status_t validateUsage(audio_usage_t usage, const AttributionSourceState& attributionSource);
 
     void updateUidStates();
     void updateUidStates_l() REQUIRES(mLock);
@@ -353,6 +359,13 @@
 
     static bool isVirtualSource(audio_source_t source);
 
+    /** returns true if the audio source must be silenced when the corresponding app op is denied.
+     *          false if the audio source does not actually capture from the microphone while still
+     *          being mapped to app op OP_RECORD_AUDIO and not a specialized op tracked separately.
+     *          See getOpForSource().
+     */
+    static bool isAppOpSource(audio_source_t source);
+
     // If recording we need to make sure the UID is allowed to do that. If the UID is idle
     // then it cannot record and gets buffers with zeros - silence. As soon as the UID
     // transitions to an active state we will start reporting buffers with data. This approach
@@ -462,6 +475,7 @@
             SET_EFFECT_SUSPENDED,
             AUDIO_MODULES_UPDATE,
             ROUTING_UPDATED,
+            UPDATE_UID_STATES
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -509,6 +523,7 @@
                                                           bool suspended);
                     void        audioModulesUpdateCommand();
                     void        routingChangedCommand();
+                    void        updateUidStatesCommand();
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
     private:
         class AudioCommandData;
@@ -735,6 +750,9 @@
 
         status_t getAudioPort(struct audio_port_v7 *port) override;
 
+        status_t updateSecondaryOutputs(
+                const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
+
      private:
         AudioPolicyService *mAudioPolicyService;
     };
@@ -788,23 +806,65 @@
     public:
                 AudioClient(const audio_attributes_t attributes,
                             const audio_io_handle_t io,
-                            const media::permission::Identity& identity,
+                            const AttributionSourceState& attributionSource,
                             const audio_session_t session,  audio_port_handle_t portId,
                             const audio_port_handle_t deviceId) :
-                                attributes(attributes), io(io), identity(identity),
-                                session(session), portId(portId), deviceId(deviceId), active(false) {}
+                                attributes(attributes), io(io), attributionSource(
+                                attributionSource), session(session), portId(portId),
+                                deviceId(deviceId), active(false) {}
                 ~AudioClient() override = default;
 
 
         const audio_attributes_t attributes; // source, flags ...
         const audio_io_handle_t io;          // audio HAL stream IO handle
-        const media::permission::Identity& identity; //client identity
+        const AttributionSourceState& attributionSource; //client attributionsource
         const audio_session_t session;       // audio session ID
         const audio_port_handle_t portId;
         const audio_port_handle_t deviceId;  // selected input device port ID
               bool active;                   // Playback/Capture is active or inactive
     };
 
+    // Checks and monitors app ops for AudioRecordClient
+    class OpRecordAudioMonitor : public RefBase {
+    public:
+        ~OpRecordAudioMonitor() override;
+        bool hasOp() const;
+        int32_t getOp() const { return mAppOp; }
+
+        static sp<OpRecordAudioMonitor> createIfNeeded(
+                const AttributionSourceState& attributionSource,
+                const audio_attributes_t& attr, wp<AudioCommandThread> commandThread);
+
+    private:
+        OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp,
+                wp<AudioCommandThread> commandThread);
+
+        void onFirstRef() override;
+
+        AppOpsManager mAppOpsManager;
+
+        class RecordAudioOpCallback : public BnAppOpsCallback {
+        public:
+            explicit RecordAudioOpCallback(const wp<OpRecordAudioMonitor>& monitor);
+            void opChanged(int32_t op, const String16& packageName) override;
+
+        private:
+            const wp<OpRecordAudioMonitor> mMonitor;
+        };
+
+        sp<RecordAudioOpCallback> mOpCallback;
+        // called by RecordAudioOpCallback when the app op for this OpRecordAudioMonitor is updated
+        // in AppOp callback and in onFirstRef()
+        // updateUidStates is true when the silenced state of active AudioRecordClients must be
+        // re-evaluated
+        void checkOp(bool updateUidStates = false);
+
+        std::atomic_bool mHasOp;
+        const AttributionSourceState mAttributionSource;
+        const int32_t mAppOp;
+        wp<AudioCommandThread> mCommandThread;
+    };
+
     // --- AudioRecordClient ---
     // Information about each registered AudioRecord client
     // (between calls to getInputForAttr() and releaseInput())
@@ -814,29 +874,43 @@
                           const audio_io_handle_t io,
                           const audio_session_t session, audio_port_handle_t portId,
                           const audio_port_handle_t deviceId,
-                          const media::permission::Identity& identity,
-                          bool canCaptureOutput, bool canCaptureHotword) :
-                    AudioClient(attributes, io, identity,
-                        session, portId, deviceId), identity(identity), startTimeNs(0),
-                    canCaptureOutput(canCaptureOutput), canCaptureHotword(canCaptureHotword) {}
+                          const AttributionSourceState& attributionSource,
+                          bool canCaptureOutput, bool canCaptureHotword,
+                          wp<AudioCommandThread> commandThread) :
+                    AudioClient(attributes, io, attributionSource,
+                        session, portId, deviceId), attributionSource(attributionSource),
+                        startTimeNs(0), canCaptureOutput(canCaptureOutput),
+                        canCaptureHotword(canCaptureHotword), silenced(false),
+                        mOpRecordAudioMonitor(
+                                OpRecordAudioMonitor::createIfNeeded(attributionSource,
+                                attributes, commandThread)) {}
                 ~AudioRecordClient() override = default;
 
-        const media::permission::Identity identity;        // identity of client
+        bool hasOp() const {
+            return mOpRecordAudioMonitor ? mOpRecordAudioMonitor->hasOp() : true;
+        }
+
+        const AttributionSourceState attributionSource; // attribution source of client
         nsecs_t startTimeNs;
         const bool canCaptureOutput;
         const bool canCaptureHotword;
+        bool silenced;
+
+    private:
+        sp<OpRecordAudioMonitor>           mOpRecordAudioMonitor;
     };
 
+
     // --- AudioPlaybackClient ---
     // Information about each registered AudioTrack client
     // (between calls to getOutputForAttr() and releaseOutput())
     class AudioPlaybackClient : public AudioClient {
     public:
                 AudioPlaybackClient(const audio_attributes_t attributes,
-                      const audio_io_handle_t io, media::permission::Identity identity,
+                      const audio_io_handle_t io, AttributionSourceState attributionSource,
                             const audio_session_t session, audio_port_handle_t portId,
                             audio_port_handle_t deviceId, audio_stream_type_t stream) :
-                    AudioClient(attributes, io, identity, session, portId,
+                    AudioClient(attributes, io, attributionSource, session, portId,
                         deviceId), stream(stream) {}
                 ~AudioPlaybackClient() override = default;
 
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index f480210..b296fb0 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -25,7 +25,8 @@
         "libmedia_helper",
         "libutils",
         "libxml2",
-        "media_permission-aidl-cpp",
+        "libpermission",
+        "libbinder",
     ],
 
     static_libs: [
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index e2d7d17..f7b0565 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -134,6 +134,11 @@
     size_t getRoutingUpdatedCounter() const {
         return mRoutingUpdatedUpdateCount; }
 
+    status_t updateSecondaryOutputs(
+            const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
+        return NO_ERROR;
+    }
+
 private:
     audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
     audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index d289e15..1384864 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -91,6 +91,10 @@
     status_t getAudioPort(struct audio_port_v7 *port __unused) override {
         return INVALID_OPERATION;
     };
+    status_t updateSecondaryOutputs(
+            const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
+        return NO_INIT;
+    }
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 8f12ecf..a16ab7d 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -25,7 +25,7 @@
 #define LOG_TAG "APM_Test"
 #include <Serializer.h>
 #include <android-base/file.h>
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <media/AudioPolicy.h>
 #include <media/PatchBuilder.h>
 #include <media/RecordingActivityTracker.h>
@@ -40,7 +40,7 @@
 
 using namespace android;
 using testing::UnorderedElementsAre;
-using media::permission::Identity;
+using android::content::AttributionSourceState;
 
 TEST(AudioPolicyManagerTestInit, EngineFailure) {
     AudioPolicyTestClient client;
@@ -216,11 +216,12 @@
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
     AudioPolicyInterface::output_type_t outputType;
-    // TODO b/182392769: use identity util
-    Identity i = Identity();
-    i.uid = 0;
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource = AttributionSourceState();
+    attributionSource.uid = 0;
+    attributionSource.token = sp<BBinder>::make();
     ASSERT_EQ(OK, mManager->getOutputForAttr(
-                    &attr, output, AUDIO_SESSION_NONE, &stream, i, &config, &flags,
+                    &attr, output, AUDIO_SESSION_NONE, &stream, attributionSource, &config, &flags,
                     selectedDeviceId, portId, {}, &outputType));
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
     ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
@@ -244,11 +245,12 @@
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
     AudioPolicyInterface::input_type_t inputType;
-    // TODO b/182392769: use identity util
-    Identity i = Identity();
-    i.uid = 0;
+    // TODO b/182392769: use attribution source util
+    AttributionSourceState attributionSource = AttributionSourceState();
+    attributionSource.uid = 0;
+    attributionSource.token = sp<BBinder>::make();
     ASSERT_EQ(OK, mManager->getInputForAttr(
-            &attr, &input, riid, AUDIO_SESSION_NONE, i, &config, flags,
+            &attr, &input, riid, AUDIO_SESSION_NONE, attributionSource, &config, flags,
             selectedDeviceId, &inputType, portId));
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
 }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a0448b4..3deea6b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -85,6 +85,7 @@
 
 using base::StringPrintf;
 using binder::Status;
+using camera3::SessionConfigurationUtils;
 using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
 using hardware::ICamera;
 using hardware::ICameraClient;
@@ -131,7 +132,7 @@
         "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
 static const String16
         sCameraInjectExternalCameraPermission("android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
-
+const char *sFileName = "lastOpenSessionDumpFile";
 static constexpr int32_t kVendorClientScore = resource_policy::PERCEPTIBLE_APP_ADJ;
 static constexpr int32_t kVendorClientState = ActivityManager::PROCESS_STATE_PERSISTENT_UI;
 
@@ -148,6 +149,10 @@
         mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE) {
     ALOGI("CameraService started (pid=%d)", getpid());
     mServiceLockWrapper = std::make_shared<WaitableMutexWrapper>(&mServiceLock);
+    mMemFd = memfd_create(sFileName, MFD_ALLOW_SEALING);
+    if (mMemFd == -1) {
+        ALOGE("%s: Error while creating the file: %s", __FUNCTION__, sFileName);
+    }
 }
 
 void CameraService::onFirstRef()
@@ -232,6 +237,12 @@
         }
     }
 
+    //Derive primary rear/front cameras, and filter their charactierstics.
+    //This needs to be done after all cameras are enumerated and camera ids are sorted.
+    if (SessionConfigurationUtils::IS_PERF_CLASS) {
+        filterSPerfClassCharacteristics();
+    }
+
     return OK;
 }
 
@@ -302,6 +313,46 @@
     filterAPI1SystemCameraLocked(mNormalDeviceIds);
 }
 
+void CameraService::filterSPerfClassCharacteristics() {
+    // To claim to be S Performance primary cameras, the cameras must be
+    // backward compatible. So performance class primary camera Ids must be API1
+    // compatible.
+    bool firstRearCameraSeen = false, firstFrontCameraSeen = false;
+    for (const auto& cameraId : mNormalDeviceIdsWithoutSystemCamera) {
+        int facing = -1;
+        int orientation = 0;
+        String8 cameraId8(cameraId.c_str());
+        getDeviceVersion(cameraId8, /*out*/&facing, /*out*/&orientation);
+        if (facing == -1) {
+            ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.c_str());
+            return;
+        }
+
+        if ((facing == hardware::CAMERA_FACING_BACK && !firstRearCameraSeen) ||
+                (facing == hardware::CAMERA_FACING_FRONT && !firstFrontCameraSeen)) {
+            status_t res = mCameraProviderManager->filterSmallJpegSizes(cameraId);
+            if (res == OK) {
+                mPerfClassPrimaryCameraIds.insert(cameraId);
+            } else {
+                ALOGE("%s: Failed to filter small JPEG sizes for performance class primary "
+                        "camera %s: %s(%d)", __FUNCTION__, cameraId.c_str(), strerror(-res), res);
+                break;
+            }
+
+            if (facing == hardware::CAMERA_FACING_BACK) {
+                firstRearCameraSeen = true;
+            }
+            if (facing == hardware::CAMERA_FACING_FRONT) {
+                firstFrontCameraSeen = true;
+            }
+        }
+
+        if (firstRearCameraSeen && firstFrontCameraSeen) {
+            break;
+        }
+    }
+}
+
 void CameraService::addStates(const String8 id) {
     std::string cameraId(id.c_str());
     hardware::camera::common::V1_0::CameraResourceCost cost;
@@ -655,7 +706,7 @@
 }
 
 Status CameraService::getCameraCharacteristics(const String16& cameraId,
-        CameraMetadata* cameraInfo) {
+        int targetSdkVersion, CameraMetadata* cameraInfo) {
     ATRACE_CALL();
     if (!cameraInfo) {
         ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
@@ -676,8 +727,13 @@
 
     Status ret{};
 
+
+    std::string cameraIdStr = String8(cameraId).string();
+    bool overrideForPerfClass =
+            SessionConfigurationUtils::targetPerfClassPrimaryCamera(mPerfClassPrimaryCameraIds,
+                    cameraIdStr, targetSdkVersion);
     status_t res = mCameraProviderManager->getCameraCharacteristics(
-            String8(cameraId).string(), cameraInfo);
+            cameraIdStr, overrideForPerfClass, cameraInfo);
     if (res != OK) {
         if (res == NAME_NOT_FOUND) {
             return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to retrieve camera "
@@ -819,7 +875,7 @@
         const sp<IInterface>& cameraCb, const String16& packageName,
         const std::optional<String16>& featureId,  const String8& cameraId,
         int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid,
-        int servicePid, int deviceVersion, apiLevel effectiveApiLevel,
+        int servicePid, int deviceVersion, apiLevel effectiveApiLevel, bool overrideForPerfClass,
         /*out*/sp<BasicClient>* client) {
 
     // Create CameraClient based on device version reported by the HAL.
@@ -843,12 +899,13 @@
                 *client = new Camera2Client(cameraService, tmp, packageName, featureId,
                         cameraId, api1CameraId,
                         facing, sensorOrientation, clientPid, clientUid,
-                        servicePid);
+                        servicePid, overrideForPerfClass);
             } else { // Camera2 API route
                 sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                         static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
                 *client = new CameraDeviceClient(cameraService, tmp, packageName, featureId,
-                        cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid);
+                        cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
+                        overrideForPerfClass);
             }
             break;
         default:
@@ -945,7 +1002,8 @@
     if (!(ret = connectHelper<ICameraClient,Client>(
             sp<ICameraClient>{nullptr}, id, cameraId,
             internalPackageName, {}, uid, USE_CALLING_PID,
-            API_1, /*shimUpdateOnly*/ true, /*out*/ tmp)
+            API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
+            /*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*out*/ tmp)
             ).isOk()) {
         ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
     }
@@ -1217,10 +1275,12 @@
 }
 
 void CameraService::finishConnectLocked(const sp<BasicClient>& client,
-        const CameraService::DescriptorPtr& desc) {
+        const CameraService::DescriptorPtr& desc, int oomScoreOffset) {
 
     // Make a descriptor for the incoming client
-    auto clientDescriptor = CameraService::CameraClientManager::makeClientDescriptor(client, desc);
+    auto clientDescriptor =
+            CameraService::CameraClientManager::makeClientDescriptor(client, desc,
+                    oomScoreOffset);
     auto evicted = mActiveClientManager.addAndEvict(clientDescriptor);
 
     logConnected(desc->getKey(), static_cast<int>(desc->getOwnerId()),
@@ -1250,6 +1310,7 @@
 
 status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid,
         apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const String8& packageName,
+        int oomScoreOffset,
         /*out*/
         sp<BasicClient>* client,
         std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial) {
@@ -1301,7 +1362,8 @@
         for (size_t i = 0; i < ownerPids.size() - 1; i++) {
             pidToPriorityMap.emplace(ownerPids[i],
                     resource_policy::ClientPriority(priorityScores[i], states[i],
-                            /* isVendorClient won't get copied over*/ false));
+                            /* isVendorClient won't get copied over*/ false,
+                            /* oomScoreOffset won't get copied over*/ 0));
         }
         mActiveClientManager.updatePriorities(pidToPriorityMap);
 
@@ -1314,13 +1376,16 @@
             return BAD_VALUE;
         }
 
-        // Make descriptor for incoming client
+        int32_t actualScore = priorityScores[priorityScores.size() - 1];
+        int32_t actualState = states[states.size() - 1];
+
+        // Make descriptor for incoming client. We store the oomScoreOffset
+        // since we might need it later on new handleEvictionsLocked and
+        // ProcessInfoService would not take that into account.
         clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
                 sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
-                state->getConflicting(),
-                priorityScores[priorityScores.size() - 1],
-                clientPid,
-                states[states.size() - 1]);
+                state->getConflicting(), actualScore, clientPid, actualState,
+                oomScoreOffset);
 
         resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority();
 
@@ -1453,6 +1518,7 @@
         const String16& clientPackageName,
         int clientUid,
         int clientPid,
+        int targetSdkVersion,
         /*out*/
         sp<ICamera>* device) {
 
@@ -1463,7 +1529,7 @@
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
             clientPackageName, {}, clientUid, clientPid, API_1,
-            /*shimUpdateOnly*/ false, /*out*/client);
+            /*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion, /*out*/client);
 
     if(!ret.isOk()) {
         logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
@@ -1539,7 +1605,7 @@
         const String16& cameraId,
         const String16& clientPackageName,
         const std::optional<String16>& clientFeatureId,
-        int clientUid,
+        int clientUid, int oomScoreOffset, int targetSdkVersion,
         /*out*/
         sp<hardware::camera2::ICameraDeviceUser>* device) {
 
@@ -1548,23 +1614,61 @@
     String8 id = String8(cameraId);
     sp<CameraDeviceClient> client = nullptr;
     String16 clientPackageNameAdj = clientPackageName;
+    int callingPid = CameraThreadState::getCallingPid();
 
     if (getCurrentServingCall() == BinderCallType::HWBINDER) {
         std::string vendorClient =
                 StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
         clientPackageNameAdj = String16(vendorClient.c_str());
     }
+
+    if (oomScoreOffset < 0) {
+        String8 msg =
+                String8::format("Cannot increase the priority of a client %s pid %d for "
+                        "camera id %s", String8(clientPackageNameAdj).string(), callingPid,
+                        id.string());
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+
+    // enforce system camera permissions
+    if (oomScoreOffset > 0 &&
+            !hasPermissionsForSystemCamera(callingPid, CameraThreadState::getCallingUid())) {
+        String8 msg =
+                String8::format("Cannot change the priority of a client %s pid %d for "
+                        "camera id %s without SYSTEM_CAMERA permissions",
+                        String8(clientPackageNameAdj).string(), callingPid, id.string());
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(ERROR_PERMISSION_DENIED, msg.string());
+    }
+
     ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
             /*api1CameraId*/-1, clientPackageNameAdj, clientFeatureId,
-            clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
+            clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, oomScoreOffset,
+            targetSdkVersion, /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageNameAdj),
-                ret.toString8());
+        logRejected(id, callingPid, String8(clientPackageNameAdj), ret.toString8());
         return ret;
     }
 
     *device = client;
+    Mutex::Autolock lock(mServiceLock);
+
+    // Clear the previous cached logs and reposition the
+    // file offset to beginning of the file to log new data.
+    // If either truncate or lseek fails, close the previous file and create a new one.
+    if ((ftruncate(mMemFd, 0) == -1) || (lseek(mMemFd, 0, SEEK_SET) == -1)) {
+        ALOGE("%s: Error while truncating the file: %s", __FUNCTION__, sFileName);
+        // Close the previous memfd.
+        close(mMemFd);
+        // If failure to wipe the data, then create a new file and
+        // assign the new value to mMemFd.
+        mMemFd = memfd_create(sFileName, MFD_ALLOW_SEALING);
+        if (mMemFd == -1) {
+            ALOGE("%s: Error while creating the file: %s", __FUNCTION__, sFileName);
+        }
+    }
     return ret;
 }
 
@@ -1572,7 +1676,7 @@
 Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
         int api1CameraId, const String16& clientPackageName,
         const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
-        apiLevel effectiveApiLevel, bool shimUpdateOnly,
+        apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
         /*out*/sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
 
@@ -1623,7 +1727,7 @@
         sp<BasicClient> clientTmp = nullptr;
         std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
         if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
-                IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,
+                IInterface::asBinder(cameraCb), clientName8, oomScoreOffset, /*out*/&clientTmp,
                 /*out*/&partial)) != NO_ERROR) {
             switch (err) {
                 case -ENODEV:
@@ -1662,10 +1766,12 @@
         }
 
         sp<BasicClient> tmp = nullptr;
+        bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+                mPerfClassPrimaryCameraIds, cameraId.string(), targetSdkVersion);
         if(!(ret = makeClient(this, cameraCb, clientPackageName, clientFeatureId,
                 cameraId, api1CameraId, facing, orientation,
                 clientPid, clientUid, getpid(),
-                deviceVersion, effectiveApiLevel,
+                deviceVersion, effectiveApiLevel, overrideForPerfClass,
                 /*out*/&tmp)).isOk()) {
             return ret;
         }
@@ -1741,7 +1847,7 @@
             mServiceLock.lock();
         } else {
             // Otherwise, add client to active clients list
-            finishConnectLocked(client, partial);
+            finishConnectLocked(client, partial, oomScoreOffset);
         }
 
         client->setImageDumpMask(mImageDumpMask);
@@ -1788,7 +1894,8 @@
         auto offlineClientDesc = CameraClientManager::makeClientDescriptor(
                 kOfflineDevice + onlineClientDesc->getKey(), offlineClient, /*cost*/ 0,
                 /*conflictingKeys*/ std::set<String8>(), onlinePriority.getScore(),
-                onlineClientDesc->getOwnerId(), onlinePriority.getState());
+                onlineClientDesc->getOwnerId(), onlinePriority.getState(),
+                /*ommScoreOffset*/ 0);
 
         // Allow only one offline device per camera
         auto incompatibleClients = mActiveClientManager.getIncompatibleClients(offlineClientDesc);
@@ -2139,7 +2246,7 @@
 
 Status CameraService::isConcurrentSessionConfigurationSupported(
         const std::vector<CameraIdAndSessionConfiguration>& cameraIdsAndSessionConfigurations,
-        /*out*/bool* isSupported) {
+        int targetSdkVersion, /*out*/bool* isSupported) {
     if (!isSupported) {
         ALOGE("%s: isSupported is NULL", __FUNCTION__);
         return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "isSupported is NULL");
@@ -2163,7 +2270,8 @@
 
     status_t res =
             mCameraProviderManager->isConcurrentSessionConfigurationSupported(
-                    cameraIdsAndSessionConfigurations, isSupported);
+                    cameraIdsAndSessionConfigurations, mPerfClassPrimaryCameraIds,
+                    targetSdkVersion, isSupported);
     if (res != OK) {
         logServiceError(String8::format("Unable to query session configuration support"),
             ERROR_INVALID_OPERATION);
@@ -3662,21 +3770,23 @@
 CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
         const String8& key, const sp<BasicClient>& value, int32_t cost,
         const std::set<String8>& conflictingKeys, int32_t score, int32_t ownerId,
-        int32_t state) {
+        int32_t state, int32_t oomScoreOffset) {
 
     bool isVendorClient = getCurrentServingCall() == BinderCallType::HWBINDER;
     int32_t score_adj = isVendorClient ? kVendorClientScore : score;
     int32_t state_adj = isVendorClient ? kVendorClientState: state;
 
     return std::make_shared<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>(
-            key, value, cost, conflictingKeys, score_adj, ownerId, state_adj, isVendorClient);
+            key, value, cost, conflictingKeys, score_adj, ownerId, state_adj, isVendorClient,
+            oomScoreOffset);
 }
 
 CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
-        const sp<BasicClient>& value, const CameraService::DescriptorPtr& partial) {
+        const sp<BasicClient>& value, const CameraService::DescriptorPtr& partial,
+        int32_t oomScoreOffset) {
     return makeClientDescriptor(partial->getKey(), value, partial->getCost(),
             partial->getConflicting(), partial->getPriority().getScore(),
-            partial->getOwnerId(), partial->getPriority().getState());
+            partial->getOwnerId(), partial->getPriority().getState(), oomScoreOffset);
 }
 
 // ----------------------------------------------------------------------------
@@ -3757,6 +3867,28 @@
     return locked;
 }
 
+void CameraService::cacheDump() {
+    if (mMemFd != -1) {
+        const Vector<String16> args;
+        ATRACE_CALL();
+        // Acquiring service lock here will avoid the deadlock since
+        // cacheDump will not be called during the second disconnect.
+        Mutex::Autolock lock(mServiceLock);
+
+        Mutex::Autolock l(mCameraStatesLock);
+        // Start collecting the info for open sessions and store it in temp file.
+        for (const auto& state : mCameraStates) {
+            String8 cameraId = state.first;
+            auto clientDescriptor = mActiveClientManager.get(cameraId);
+            if (clientDescriptor != nullptr) {
+                dprintf(mMemFd, "== Camera device %s dynamic info: ==\n", cameraId.string());
+                // Log the current open session info before device is disconnected.
+                dumpOpenSessionClientLogs(mMemFd, args, cameraId);
+            }
+        }
+    }
+}
+
 status_t CameraService::dump(int fd, const Vector<String16>& args) {
     ATRACE_CALL();
 
@@ -3823,21 +3955,10 @@
 
         auto clientDescriptor = mActiveClientManager.get(cameraId);
         if (clientDescriptor != nullptr) {
-            dprintf(fd, "  Device %s is open. Client instance dump:\n",
-                    cameraId.string());
-            dprintf(fd, "    Client priority score: %d state: %d\n",
-                    clientDescriptor->getPriority().getScore(),
-                    clientDescriptor->getPriority().getState());
-            dprintf(fd, "    Client PID: %d\n", clientDescriptor->getOwnerId());
-
-            auto client = clientDescriptor->getValue();
-            dprintf(fd, "    Client package: %s\n",
-                    String8(client->getPackageName()).string());
-
-            client->dumpClient(fd, args);
+            // log the current open session info
+            dumpOpenSessionClientLogs(fd, args, cameraId);
         } else {
-            dprintf(fd, "  Device %s is closed, no client instance\n",
-                    cameraId.string());
+            dumpClosedSessionClientLogs(fd, cameraId);
         }
 
     }
@@ -3894,9 +4015,55 @@
             }
         }
     }
+
+    bool serviceLocked = tryLock(mServiceLock);
+
+    // Dump info from previous open sessions.
+    // Reposition the offset to beginning of the file before reading
+
+    if ((mMemFd >= 0) && (lseek(mMemFd, 0, SEEK_SET) != -1)) {
+        dprintf(fd, "\n**********Dumpsys from previous open session**********\n");
+        ssize_t size_read;
+        char buf[4096];
+        while ((size_read = read(mMemFd, buf, (sizeof(buf) - 1))) > 0) {
+            // Read data from file to a small buffer and write it to fd.
+            write(fd, buf, size_read);
+            if (size_read == -1) {
+                ALOGE("%s: Error during reading the file: %s", __FUNCTION__, sFileName);
+                break;
+            }
+        }
+        dprintf(fd, "\n**********End of Dumpsys from previous open session**********\n");
+    } else {
+        ALOGE("%s: Error during reading the file: %s", __FUNCTION__, sFileName);
+    }
+
+    if (serviceLocked) mServiceLock.unlock();
     return NO_ERROR;
 }
 
+void CameraService::dumpOpenSessionClientLogs(int fd,
+        const Vector<String16>& args, const String8& cameraId) {
+    auto clientDescriptor = mActiveClientManager.get(cameraId);
+    dprintf(fd, "  Device %s is open. Client instance dump:\n",
+        cameraId.string());
+    dprintf(fd, "    Client priority score: %d state: %d\n",
+        clientDescriptor->getPriority().getScore(),
+        clientDescriptor->getPriority().getState());
+    dprintf(fd, "    Client PID: %d\n", clientDescriptor->getOwnerId());
+
+    auto client = clientDescriptor->getValue();
+    dprintf(fd, "    Client package: %s\n",
+        String8(client->getPackageName()).string());
+
+    client->dumpClient(fd, args);
+}
+
+void CameraService::dumpClosedSessionClientLogs(int fd, const String8& cameraId) {
+    dprintf(fd, "  Device %s is closed, no client instance\n",
+                    cameraId.string());
+}
+
 void CameraService::dumpEventLog(int fd) {
     dprintf(fd, "\n== Camera service events log (most recent at top): ==\n");
 
@@ -3976,25 +4143,13 @@
         ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
         return;
     }
-    bool supportsHAL3 = false;
-    // supportsCameraApi also holds mInterfaceMutex, we can't call it in the
-    // HIDL onStatusChanged wrapper call (we'll hold mStatusListenerLock and
-    // mInterfaceMutex together, which can lead to deadlocks)
-    binder::Status sRet =
-            supportsCameraApi(String16(cameraId), hardware::ICameraService::API_VERSION_2,
-                    &supportsHAL3);
-    if (!sRet.isOk()) {
-        ALOGW("%s: Failed to determine if device supports HAL3 %s, supportsCameraApi call failed",
-                __FUNCTION__, cameraId.string());
-        return;
-    }
 
     // Collect the logical cameras without holding mStatusLock in updateStatus
     // as that can lead to a deadlock(b/162192331).
     auto logicalCameraIds = getLogicalCameras(cameraId);
     // Update the status for this camera state, then send the onStatusChangedCallbacks to each
     // of the listeners with both the mStatusLock and mStatusListenerLock held
-    state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3,
+    state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind,
                         &logicalCameraIds]
             (const String8& cameraId, StatusInternal status) {
 
@@ -4022,8 +4177,8 @@
                 bool isVendorListener = listener->isVendorListener();
                 if (shouldSkipStatusUpdates(deviceKind, isVendorListener,
                         listener->getListenerPid(), listener->getListenerUid()) ||
-                        (isVendorListener && !supportsHAL3)) {
-                    ALOGV("Skipping discovery callback for system-only camera/HAL1 device %s",
+                        isVendorListener) {
+                    ALOGV("Skipping discovery callback for system-only camera device %s",
                             cameraId.c_str());
                     continue;
                 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 10e1748..1fb7104 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -121,7 +121,7 @@
     virtual binder::Status     getCameraInfo(int cameraId,
             hardware::CameraInfo* cameraInfo);
     virtual binder::Status     getCameraCharacteristics(const String16& cameraId,
-            CameraMetadata* cameraInfo);
+            int targetSdkVersion, CameraMetadata* cameraInfo);
     virtual binder::Status     getCameraVendorTagDescriptor(
             /*out*/
             hardware::camera2::params::VendorTagDescriptor* desc);
@@ -131,14 +131,14 @@
 
     virtual binder::Status     connect(const sp<hardware::ICameraClient>& cameraClient,
             int32_t cameraId, const String16& clientPackageName,
-            int32_t clientUid, int clientPid,
+            int32_t clientUid, int clientPid, int targetSdkVersion,
             /*out*/
             sp<hardware::ICamera>* device);
 
     virtual binder::Status     connectDevice(
             const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId,
             const String16& clientPackageName, const std::optional<String16>& clientFeatureId,
-            int32_t clientUid,
+            int32_t clientUid, int scoreOffset, int targetSdkVersion,
             /*out*/
             sp<hardware::camera2::ICameraDeviceUser>* device);
 
@@ -154,7 +154,7 @@
 
     virtual binder::Status isConcurrentSessionConfigurationSupported(
         const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>& sessions,
-        /*out*/bool* supported);
+        int targetSdkVersion, /*out*/bool* supported);
 
     virtual binder::Status    getLegacyParameters(
             int32_t cameraId,
@@ -205,6 +205,9 @@
     // Monitored UIDs availability notification
     void                notifyMonitoredUids();
 
+    // Stores current open session device info in temp file.
+    void cacheDump();
+
     // Register an offline client for a given active camera id
     status_t addOfflineClient(String8 cameraId, sp<BasicClient> offlineClient);
 
@@ -510,14 +513,14 @@
          */
         static DescriptorPtr makeClientDescriptor(const String8& key, const sp<BasicClient>& value,
                 int32_t cost, const std::set<String8>& conflictingKeys, int32_t score,
-                int32_t ownerId, int32_t state);
+                int32_t ownerId, int32_t state, int oomScoreOffset);
 
         /**
          * Make a ClientDescriptor object wrapping the given BasicClient strong pointer with
          * values intialized from a prior ClientDescriptor.
          */
         static DescriptorPtr makeClientDescriptor(const sp<BasicClient>& value,
-                const CameraService::DescriptorPtr& partial);
+                const CameraService::DescriptorPtr& partial, int oomScoreOffset);
 
     }; // class CameraClientManager
 
@@ -739,6 +742,7 @@
     // Only call with with mServiceLock held.
     status_t handleEvictionsLocked(const String8& cameraId, int clientPid,
         apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const String8& packageName,
+        int scoreOffset,
         /*out*/
         sp<BasicClient>* client,
         std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial);
@@ -772,7 +776,8 @@
     binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
             int api1CameraId, const String16& clientPackageName,
             const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
-            apiLevel effectiveApiLevel, bool shimUpdateOnly, /*out*/sp<CLIENT>& device);
+            apiLevel effectiveApiLevel, bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
+            /*out*/sp<CLIENT>& device);
 
     // Lock guarding camera service state
     Mutex               mServiceLock;
@@ -786,6 +791,12 @@
     // Container for managing currently active application-layer clients
     CameraClientManager mActiveClientManager;
 
+    // Adds client logs during open session to the file pointed by fd.
+    void dumpOpenSessionClientLogs(int fd, const Vector<String16>& args, const String8& cameraId);
+
+    // Adds client logs during closed session to the file pointed by fd.
+    void dumpClosedSessionClientLogs(int fd, const String8& cameraId);
+
     // Mapping from camera ID -> state for each device, map is protected by mCameraStatesLock
     std::map<String8, std::shared_ptr<CameraState>> mCameraStates;
 
@@ -831,7 +842,8 @@
      *
      * This method must be called with mServiceLock held.
      */
-    void finishConnectLocked(const sp<BasicClient>& client, const DescriptorPtr& desc);
+    void finishConnectLocked(const sp<BasicClient>& client, const DescriptorPtr& desc,
+            int oomScoreOffset);
 
     /**
      * Returns the underlying camera Id string mapped to a camera id int
@@ -932,6 +944,15 @@
      */
     void updateCameraNumAndIds();
 
+    /**
+     * Filter camera characteristics for S Performance class primary cameras
+     */
+    void filterSPerfClassCharacteristics();
+
+    // File descriptor to temp file used for caching previous open
+    // session dumpsys info.
+    int mMemFd;
+
     // Number of camera devices (excluding hidden secure cameras)
     int                 mNumberOfCameras;
     // Number of camera devices (excluding hidden secure cameras and
@@ -940,6 +961,7 @@
 
     std::vector<std::string> mNormalDeviceIds;
     std::vector<std::string> mNormalDeviceIdsWithoutSystemCamera;
+    std::set<std::string> mPerfClassPrimaryCameraIds;
 
     // sounds
     sp<MediaPlayer>     newMediaPlayer(const char *file);
@@ -1120,7 +1142,7 @@
             const sp<IInterface>& cameraCb, const String16& packageName,
             const std::optional<String16>& featureId, const String8& cameraId, int api1CameraId,
             int facing, int sensorOrientation, int clientPid, uid_t clientUid, int servicePid,
-            int deviceVersion, apiLevel effectiveApiLevel,
+            int deviceVersion, apiLevel effectiveApiLevel, bool overrideForPerfClass,
             /*out*/sp<BasicClient>* client);
 
     status_t checkCameraAccess(const String16& opPackageName);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 72b3c40..944b8ab 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -58,10 +58,11 @@
         int sensorOrientation,
         int clientPid,
         uid_t clientUid,
-        int servicePid):
+        int servicePid,
+        bool overrideForPerfClass):
         Camera2ClientBase(cameraService, cameraClient, clientPackageName, clientFeatureId,
                 cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation,
-                clientPid, clientUid, servicePid),
+                clientPid, clientUid, servicePid, overrideForPerfClass),
         mParameters(api1CameraId, cameraFacing)
 {
     ATRACE_CALL();
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index d16b242..64ab8ff 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -104,7 +104,8 @@
             int sensorOrientation,
             int clientPid,
             uid_t clientUid,
-            int servicePid);
+            int servicePid,
+            bool overrideForPerfClass);
 
     virtual ~Camera2Client();
 
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index a3e12c7..80508e4 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -2999,7 +2999,7 @@
         const StreamConfiguration &sc = scs[i];
         if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
                 sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
-                sc.width <= limit.width && sc.height <= limit.height) {
+                ((sc.width * sc.height) <= (limit.width * limit.height))) {
             int64_t minFrameDuration = getMinFrameDurationNs(
                     {sc.width, sc.height}, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
             if (minFrameDuration > MAX_PREVIEW_RECORD_DURATION_NS) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 343f4a7..1f3d478 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -52,6 +52,7 @@
 namespace android {
 using namespace camera2;
 using camera3::camera_stream_rotation_t::CAMERA_STREAM_ROTATION_0;
+using camera3::SessionConfigurationUtils;
 
 CameraDeviceClientBase::CameraDeviceClientBase(
         const sp<CameraService>& cameraService,
@@ -91,13 +92,15 @@
         int sensorOrientation,
         int clientPid,
         uid_t clientUid,
-        int servicePid) :
+        int servicePid,
+        bool overrideForPerfClass) :
     Camera2ClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
-                cameraId, /*API1 camera ID*/ -1,
-                cameraFacing, sensorOrientation, clientPid, clientUid, servicePid),
+                cameraId, /*API1 camera ID*/ -1, cameraFacing, sensorOrientation,
+                clientPid, clientUid, servicePid, overrideForPerfClass),
     mInputStream(),
     mStreamingRequestId(REQUEST_ID_NONE),
-    mRequestIdCounter(0) {
+    mRequestIdCounter(0),
+    mOverrideForPerfClass(overrideForPerfClass) {
 
     ATRACE_CALL();
     ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
@@ -537,7 +540,7 @@
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
 
-    res = camera3::SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
+    res = SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
             mCameraIdStr);
     if (!res.isOk()) {
         return res;
@@ -616,7 +619,7 @@
     }
 
     auto operatingMode = sessionConfiguration.getOperatingMode();
-    res = camera3::SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
+    res = SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
             mCameraIdStr);
     if (!res.isOk()) {
         return res;
@@ -627,14 +630,16 @@
         ALOGE("%s: %s", __FUNCTION__, msg.string());
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
+
     hardware::camera::device::V3_7::StreamConfiguration streamConfiguration;
     bool earlyExit = false;
-    metadataGetter getMetadata = [this](const String8 &id) {return mDevice->infoPhysical(id);};
+    camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
+          return mDevice->infoPhysical(id);};
     std::vector<std::string> physicalCameraIds;
     mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
-    res = camera3::SessionConfigurationUtils::convertToHALStreamCombination(sessionConfiguration,
+    res = SessionConfigurationUtils::convertToHALStreamCombination(sessionConfiguration,
             mCameraIdStr, mDevice->info(), getMetadata, physicalCameraIds, streamConfiguration,
-            &earlyExit);
+            mOverrideForPerfClass, &earlyExit);
     if (!res.isOk()) {
         return res;
     }
@@ -790,7 +795,7 @@
     bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
     bool isMultiResolution = outputConfiguration.isMultiResolution();
 
-    res = camera3::SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
+    res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
             outputConfiguration.getSurfaceType());
     if (!res.isOk()) {
         return res;
@@ -799,7 +804,7 @@
     if (!mDevice.get()) {
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
-    res = camera3::SessionConfigurationUtils::checkPhysicalCameraId(mPhysicalCameraIds,
+    res = SessionConfigurationUtils::checkPhysicalCameraId(mPhysicalCameraIds,
             physicalCameraId, mCameraIdStr);
     if (!res.isOk()) {
         return res;
@@ -830,7 +835,7 @@
         }
 
         sp<Surface> surface;
-        res = camera3::SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
+        res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
                 isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
                 mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed);
 
@@ -844,6 +849,11 @@
         binders.push_back(IInterface::asBinder(bufferProducer));
         surfaces.push_back(surface);
     }
+
+    // If mOverrideForPerfClass is true, do not fail createStream() for small
+    // JPEG sizes because existing createSurfaceFromGbp() logic will find the
+    // closest possible supported size.
+
     int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
     std::vector<int> surfaceIds;
     bool isDepthCompositeStream =
@@ -951,7 +961,7 @@
     std::unordered_set<int32_t> overriddenSensorPixelModesUsed;
     const std::vector<int32_t> &sensorPixelModesUsed =
             outputConfiguration.getSensorPixelModesUsed();
-    if (camera3::SessionConfigurationUtils::checkAndOverrideSensorPixelModesUsed(
+    if (SessionConfigurationUtils::checkAndOverrideSensorPixelModesUsed(
             sensorPixelModesUsed, format, width, height, getStaticInfo(cameraIdUsed),
             /*allowRounding*/ false, &overriddenSensorPixelModesUsed) != OK) {
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
@@ -1170,7 +1180,7 @@
     for (size_t i = 0; i < newOutputsMap.size(); i++) {
         OutputStreamInfo outInfo;
         sp<Surface> surface;
-        res = camera3::SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
+        res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
                 /*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
                 mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed);
         if (!res.isOk())
@@ -1539,7 +1549,7 @@
         }
 
         sp<Surface> surface;
-        res = camera3::SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
+        res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
                 true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
                 mDevice->infoPhysical(physicalId), sensorPixelModesUsed);
 
@@ -2034,7 +2044,7 @@
 
 bool CameraDeviceClient::isUltraHighResolutionSensor(const String8 &cameraId) {
     const CameraMetadata &deviceInfo = getStaticInfo(cameraId);
-    return camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(deviceInfo);
+    return SessionConfigurationUtils::isUltraHighResolutionSensor(deviceInfo);
 }
 
 bool CameraDeviceClient::isSensorPixelModeConsistent(
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 44ffeef..76b3f53 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -35,8 +35,6 @@
 
 namespace android {
 
-typedef std::function<CameraMetadata (const String8 &)> metadataGetter;
-
 struct CameraDeviceClientBase :
          public CameraService::BasicClient,
          public hardware::camera2::BnCameraDeviceUser
@@ -185,7 +183,8 @@
             int sensorOrientation,
             int clientPid,
             uid_t clientUid,
-            int servicePid);
+            int servicePid,
+            bool overrideForPerfClass);
     virtual ~CameraDeviceClient();
 
     virtual status_t      initialize(sp<CameraProviderManager> manager,
@@ -334,6 +333,9 @@
     KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
 
     sp<CameraProviderManager> mProviderManager;
+
+    // Override the camera characteristics for performance class primary cameras.
+    bool mOverrideForPerfClass;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 582001d..a73ffb9 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "Camera3-HeicCompositeStream"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 //#define LOG_NDEBUG 0
 
 #include <linux/memfd.h>
@@ -1380,7 +1381,9 @@
     mOutputWidth = width;
     mOutputHeight = height;
     mAppSegmentMaxSize = calcAppSegmentMaxSize(cameraDevice->info());
-    mMaxHeicBufferSize = mOutputWidth * mOutputHeight * 3 / 2 + mAppSegmentMaxSize;
+    mMaxHeicBufferSize =
+        ALIGN(mOutputWidth, HeicEncoderInfoManager::kGridWidth) *
+        ALIGN(mOutputHeight, HeicEncoderInfoManager::kGridHeight) * 3 / 2 + mAppSegmentMaxSize;
 
     return OK;
 }
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
index 58edba2..a65be9c 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
@@ -38,6 +38,7 @@
     bool isSizeSupported(int32_t width, int32_t height,
             bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName) const;
 
+    // kGridWidth and kGridHeight should be 2^n
     static const auto kGridWidth = 512;
     static const auto kGridHeight = 512;
 private:
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index ce479a1..13d044a 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -54,13 +54,14 @@
         int sensorOrientation,
         int clientPid,
         uid_t clientUid,
-        int servicePid):
+        int servicePid,
+        bool overrideForPerfClass):
         TClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
                 cameraId, api1CameraId, cameraFacing, sensorOrientation, clientPid, clientUid,
                 servicePid),
         mSharedCameraCallbacks(remoteCallback),
         mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
-        mDevice(new Camera3Device(cameraId)),
+        mDevice(new Camera3Device(cameraId, overrideForPerfClass)),
         mDeviceActive(false), mApi1CameraId(api1CameraId)
 {
     ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
@@ -195,6 +196,13 @@
 
     ALOGV("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
 
+    // Before detaching the device, cache the info from current open session.
+    // The disconnected check avoids duplication of info and also prevents
+    // deadlock while acquiring service lock in cacheDump.
+    if (!TClientBase::mDisconnected) {
+        Camera2ClientBase::getCameraService()->cacheDump();
+    }
+
     detachDevice();
 
     CameraService::BasicClient::disconnect();
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index b3a38a2..6246f7b 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -55,7 +55,8 @@
                       int sensorOrientation,
                       int clientPid,
                       uid_t clientUid,
-                      int servicePid);
+                      int servicePid,
+                      bool overrideForPerfClass);
     virtual ~Camera2ClientBase();
 
     virtual status_t      initialize(sp<CameraProviderManager> manager, const String8& monitorTags);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 6dffc5d..7045128 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -46,6 +46,7 @@
 
 using namespace ::android::hardware::camera;
 using namespace ::android::hardware::camera::common::V1_0;
+using camera3::SessionConfigurationUtils;
 using std::literals::chrono_literals::operator""s;
 using hardware::camera2::utils::CameraIdAndSessionConfiguration;
 using hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
@@ -278,9 +279,9 @@
 }
 
 status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
-        CameraMetadata* characteristics) const {
+        bool overrideForPerfClass, CameraMetadata* characteristics) const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
-    return getCameraCharacteristicsLocked(id, characteristics);
+    return getCameraCharacteristicsLocked(id, overrideForPerfClass, characteristics);
 }
 
 status_t CameraProviderManager::getHighestSupportedVersion(const std::string &id,
@@ -691,32 +692,32 @@
     const int32_t depthExclTag = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE;
 
     const int32_t scalerSizesTag =
-              camera3::SessionConfigurationUtils::getAppropriateModeTag(
+              SessionConfigurationUtils::getAppropriateModeTag(
                       ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxResolution);
     const int32_t scalerMinFrameDurationsTag =
             ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
     const int32_t scalerStallDurationsTag =
-                 camera3::SessionConfigurationUtils::getAppropriateModeTag(
+                 SessionConfigurationUtils::getAppropriateModeTag(
                         ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, maxResolution);
 
     const int32_t depthSizesTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, maxResolution);
     const int32_t depthStallDurationsTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS, maxResolution);
     const int32_t depthMinFrameDurationsTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS, maxResolution);
 
     const int32_t dynamicDepthSizesTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, maxResolution);
     const int32_t dynamicDepthStallDurationsTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, maxResolution);
     const int32_t dynamicDepthMinFrameDurationsTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                  ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, maxResolution);
 
     auto& c = mCameraCharacteristics;
@@ -1077,20 +1078,20 @@
 
 status_t CameraProviderManager::ProviderInfo::DeviceInfo3::deriveHeicTags(bool maxResolution) {
     int32_t scalerStreamSizesTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxResolution);
     int32_t scalerMinFrameDurationsTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, maxResolution);
 
     int32_t heicStreamSizesTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, maxResolution);
     int32_t heicMinFrameDurationsTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS, maxResolution);
     int32_t heicStallDurationsTag =
-            camera3::SessionConfigurationUtils::getAppropriateModeTag(
+            SessionConfigurationUtils::getAppropriateModeTag(
                     ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS, maxResolution);
 
     auto& c = mCameraCharacteristics;
@@ -1186,6 +1187,17 @@
     return isHiddenPhysicalCameraInternal(cameraId).first;
 }
 
+status_t CameraProviderManager::filterSmallJpegSizes(const std::string& cameraId) {
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            if (deviceInfo->mId == cameraId) {
+                return deviceInfo->filterSmallJpegSizes();
+            }
+        }
+    }
+    return NAME_NOT_FOUND;
+}
+
 std::pair<bool, CameraProviderManager::ProviderInfo::DeviceInfo *>
 CameraProviderManager::isHiddenPhysicalCameraInternal(const std::string& cameraId) const {
     auto falseRet = std::make_pair(false, nullptr);
@@ -1201,14 +1213,6 @@
 
     for (auto& provider : mProviders) {
         for (auto& deviceInfo : provider->mDevices) {
-            CameraMetadata info;
-            status_t res = deviceInfo->getCameraCharacteristics(&info);
-            if (res != OK) {
-                ALOGE("%s: Failed to getCameraCharacteristics for id %s", __FUNCTION__,
-                        deviceInfo->mId.c_str());
-                return falseRet;
-            }
-
             std::vector<std::string> physicalIds;
             if (deviceInfo->mIsLogicalCamera) {
                 if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
@@ -1694,7 +1698,7 @@
             dprintf(fd, "    Orientation: %d\n", info.orientation);
         }
         CameraMetadata info2;
-        res = device->getCameraCharacteristics(&info2);
+        res = device->getCameraCharacteristics(true /*overrideForPerfClass*/, &info2);
         if (res == INVALID_OPERATION) {
             dprintf(fd, "  API2 not directly supported\n");
         } else if (res != OK) {
@@ -2093,9 +2097,6 @@
                         *isSupported = false;
                         return OK;
                     }
-                    camera3::SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
-                            halCameraIdsAndStreamCombinations_2_6[i].streamConfiguration,
-                            combination.streamConfiguration);
                 }
                 ret = interface_2_6->isConcurrentStreamCombinationSupported(
                         halCameraIdsAndStreamCombinations_2_6, cb);
@@ -2302,7 +2303,7 @@
                 __FUNCTION__, strerror(-res), res);
     }
 
-    if (camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
+    if (SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
         status_t status = addDynamicDepthTags(/*maxResolution*/true);
         if (OK != status) {
             ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)",
@@ -2486,10 +2487,15 @@
 }
 
 status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraCharacteristics(
-        CameraMetadata *characteristics) const {
+        bool overrideForPerfClass, CameraMetadata *characteristics) const {
     if (characteristics == nullptr) return BAD_VALUE;
 
-    *characteristics = mCameraCharacteristics;
+    if (!overrideForPerfClass && mCameraCharNoPCOverride != nullptr) {
+        *characteristics = *mCameraCharNoPCOverride;
+    } else {
+        *characteristics = mCameraCharacteristics;
+    }
+
     return OK;
 }
 
@@ -2531,7 +2537,7 @@
         ret = interface_3_7->isStreamCombinationSupported_3_7(configuration, halCb);
     } else if (interface_3_5 != nullptr) {
         hardware::camera::device::V3_4::StreamConfiguration configuration_3_4;
-        bool success = camera3::SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+        bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
                 configuration_3_4, configuration);
         if (!success) {
             *status = false;
@@ -2562,6 +2568,97 @@
     return res;
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::filterSmallJpegSizes() {
+    int32_t thresholdW = SessionConfigurationUtils::PERF_CLASS_JPEG_THRESH_W;
+    int32_t thresholdH = SessionConfigurationUtils::PERF_CLASS_JPEG_THRESH_H;
+
+    if (mCameraCharNoPCOverride != nullptr) return OK;
+
+    mCameraCharNoPCOverride = std::make_unique<CameraMetadata>(mCameraCharacteristics);
+
+    // Remove small JPEG sizes from available stream configurations
+    size_t largeJpegCount = 0;
+    std::vector<int32_t> newStreamConfigs;
+    camera_metadata_entry streamConfigs =
+            mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+    for (size_t i = 0; i < streamConfigs.count; i += 4) {
+        if ((streamConfigs.data.i32[i] == HAL_PIXEL_FORMAT_BLOB) && (streamConfigs.data.i32[i+3] ==
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) {
+            if (streamConfigs.data.i32[i+1] < thresholdW  ||
+                    streamConfigs.data.i32[i+2] < thresholdH) {
+                continue;
+            } else {
+                largeJpegCount ++;
+            }
+        }
+        newStreamConfigs.insert(newStreamConfigs.end(), streamConfigs.data.i32 + i,
+                streamConfigs.data.i32 + i + 4);
+    }
+    if (newStreamConfigs.size() == 0 || largeJpegCount == 0) {
+        return BAD_VALUE;
+    }
+
+    // Remove small JPEG sizes from available min frame durations
+    largeJpegCount = 0;
+    std::vector<int64_t> newMinDurations;
+    camera_metadata_entry minDurations =
+            mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+    for (size_t i = 0; i < minDurations.count; i += 4) {
+        if (minDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) {
+            if (minDurations.data.i64[i+1] < thresholdW ||
+                    minDurations.data.i64[i+2] < thresholdH) {
+                continue;
+            } else {
+                largeJpegCount++;
+            }
+        }
+        newMinDurations.insert(newMinDurations.end(), minDurations.data.i64 + i,
+                minDurations.data.i64 + i + 4);
+    }
+    if (newMinDurations.size() == 0 || largeJpegCount == 0) {
+        return BAD_VALUE;
+    }
+
+    // Remove small JPEG sizes from available stall durations
+    largeJpegCount = 0;
+    std::vector<int64_t> newStallDurations;
+    camera_metadata_entry stallDurations =
+            mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
+    for (size_t i = 0; i < stallDurations.count; i += 4) {
+        if (stallDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) {
+            if (stallDurations.data.i64[i+1] < thresholdW ||
+                    stallDurations.data.i64[i+2] < thresholdH) {
+                continue;
+            } else {
+                largeJpegCount++;
+            }
+        }
+        newStallDurations.insert(newStallDurations.end(), stallDurations.data.i64 + i,
+                stallDurations.data.i64 + i + 4);
+    }
+    if (newStallDurations.size() == 0 || largeJpegCount == 0) {
+        return BAD_VALUE;
+    }
+
+    mCameraCharacteristics.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+            newStreamConfigs.data(), newStreamConfigs.size());
+    mCameraCharacteristics.update(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+            newMinDurations.data(), newMinDurations.size());
+    mCameraCharacteristics.update(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+            newStallDurations.data(), newStallDurations.size());
+
+    // Re-generate metadata tags that have dependencies on BLOB sizes
+    auto res = addDynamicDepthTags();
+    if (OK != res) {
+        ALOGE("%s: Failed to append dynamic depth tags: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        // Allow filtering of small JPEG sizes to succeed even if dynamic depth
+        // tags fail to generate.
+    }
+
+    return OK;
+}
+
 status_t CameraProviderManager::ProviderInfo::parseProviderName(const std::string& name,
         std::string *type, uint32_t *id) {
     // Format must be "<type>/<id>"
@@ -2908,6 +3005,8 @@
 
 status_t CameraProviderManager::convertToHALStreamCombinationAndCameraIdsLocked(
         const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+        const std::set<std::string>& perfClassPrimaryCameraIds,
+        int targetSdkVersion,
         hardware::hidl_vec<CameraIdAndStreamCombination> *halCameraIdsAndStreamCombinations,
         bool *earlyExit) {
     binder::Status bStatus = binder::Status::ok();
@@ -2915,25 +3014,31 @@
     bool shouldExit = false;
     status_t res = OK;
     for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+        const std::string& cameraId = cameraIdAndSessionConfig.mCameraId;
         hardware::camera::device::V3_7::StreamConfiguration streamConfiguration;
         CameraMetadata deviceInfo;
-        res = getCameraCharacteristicsLocked(cameraIdAndSessionConfig.mCameraId, &deviceInfo);
+        bool overrideForPerfClass =
+                SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+                        perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
+        res = getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo);
         if (res != OK) {
             return res;
         }
         camera3::metadataGetter getMetadata =
-                [this](const String8 &id) {
+                [this](const String8 &id, bool overrideForPerfClass) {
                     CameraMetadata physicalDeviceInfo;
-                    getCameraCharacteristicsLocked(id.string(), &physicalDeviceInfo);
+                    getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
+                                                   &physicalDeviceInfo);
                     return physicalDeviceInfo;
                 };
         std::vector<std::string> physicalCameraIds;
-        isLogicalCameraLocked(cameraIdAndSessionConfig.mCameraId, &physicalCameraIds);
+        isLogicalCameraLocked(cameraId, &physicalCameraIds);
         bStatus =
-            camera3::SessionConfigurationUtils::convertToHALStreamCombination(
+            SessionConfigurationUtils::convertToHALStreamCombination(
                     cameraIdAndSessionConfig.mSessionConfiguration,
-                    String8(cameraIdAndSessionConfig.mCameraId.c_str()), deviceInfo, getMetadata,
-                    physicalCameraIds, streamConfiguration, &shouldExit);
+                    String8(cameraId.c_str()), deviceInfo, getMetadata,
+                    physicalCameraIds, streamConfiguration,
+                    overrideForPerfClass, &shouldExit);
         if (!bStatus.isOk()) {
             ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
             return INVALID_OPERATION;
@@ -2943,7 +3048,7 @@
             return OK;
         }
         CameraIdAndStreamCombination halCameraIdAndStream;
-        halCameraIdAndStream.cameraId = cameraIdAndSessionConfig.mCameraId;
+        halCameraIdAndStream.cameraId = cameraId;
         halCameraIdAndStream.streamConfiguration = streamConfiguration;
         halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
     }
@@ -2976,7 +3081,8 @@
 
 status_t CameraProviderManager::isConcurrentSessionConfigurationSupported(
         const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
-        bool *isSupported) {
+        const std::set<std::string>& perfClassPrimaryCameraIds,
+        int targetSdkVersion, bool *isSupported) {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
     // Check if all the devices are a subset of devices advertised by the
     // same provider through getConcurrentStreamingCameraIds()
@@ -2990,8 +3096,8 @@
             hardware::hidl_vec<CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
             bool knowUnsupported = false;
             status_t res = convertToHALStreamCombinationAndCameraIdsLocked(
-                    cameraIdsAndSessionConfigs, &halCameraIdsAndStreamCombinations,
-                    &knowUnsupported);
+                    cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds,
+                    targetSdkVersion, &halCameraIdsAndStreamCombinations, &knowUnsupported);
             if (res != OK) {
                 ALOGE("%s unable to convert session configurations provided to HAL stream"
                       "combinations", __FUNCTION__);
@@ -3013,10 +3119,10 @@
 }
 
 status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
-        CameraMetadata* characteristics) const {
+        bool overrideForPerfClass, CameraMetadata* characteristics) const {
     auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});
     if (deviceInfo != nullptr) {
-        return deviceInfo->getCameraCharacteristics(characteristics);
+        return deviceInfo->getCameraCharacteristics(overrideForPerfClass, characteristics);
     }
 
     // Find hidden physical camera characteristics
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 5531dd7..1bdbb44 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -20,6 +20,7 @@
 #include <vector>
 #include <unordered_map>
 #include <unordered_set>
+#include <set>
 #include <string>
 #include <mutex>
 #include <future>
@@ -226,12 +227,13 @@
      * not have a v3 or newer HAL version.
      */
     status_t getCameraCharacteristics(const std::string &id,
-            CameraMetadata* characteristics) const;
+            bool overrideForPerfClass, CameraMetadata* characteristics) const;
 
     status_t isConcurrentSessionConfigurationSupported(
             const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
                     &cameraIdsAndSessionConfigs,
-            bool *isSupported);
+            const std::set<std::string>& perfClassPrimaryCameraIds,
+            int targetSdkVersion, bool *isSupported);
 
     std::vector<std::unordered_set<std::string>> getConcurrentCameraIds() const;
     /**
@@ -327,6 +329,8 @@
     status_t getSystemCameraKind(const std::string& id, SystemCameraKind *kind) const;
     bool isHiddenPhysicalCamera(const std::string& cameraId) const;
 
+    status_t filterSmallJpegSizes(const std::string& cameraId);
+
     static const float kDepthARTolerance;
 private:
     // All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
@@ -470,7 +474,9 @@
             virtual status_t getCameraInfo(hardware::CameraInfo *info) const = 0;
             virtual bool isAPI1Compatible() const = 0;
             virtual status_t dumpState(int fd) = 0;
-            virtual status_t getCameraCharacteristics(CameraMetadata *characteristics) const {
+            virtual status_t getCameraCharacteristics(bool overrideForPerfClass,
+                    CameraMetadata *characteristics) const {
+                (void) overrideForPerfClass;
                 (void) characteristics;
                 return INVALID_OPERATION;
             }
@@ -486,6 +492,7 @@
                     bool * /*status*/) {
                 return INVALID_OPERATION;
             }
+            virtual status_t filterSmallJpegSizes() = 0;
 
             template<class InterfaceT>
             sp<InterfaceT> startDeviceInterface();
@@ -537,6 +544,7 @@
             virtual bool isAPI1Compatible() const override;
             virtual status_t dumpState(int fd) override;
             virtual status_t getCameraCharacteristics(
+                    bool overrideForPerfClass,
                     CameraMetadata *characteristics) const override;
             virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
                     CameraMetadata *characteristics) const override;
@@ -544,6 +552,7 @@
                     const hardware::camera::device::V3_7::StreamConfiguration &configuration,
                     bool *status /*out*/)
                     override;
+            virtual status_t filterSmallJpegSizes() override;
 
             DeviceInfo3(const std::string& name, const metadata_vendor_id_t tagId,
                     const std::string &id, uint16_t minorVersion,
@@ -553,6 +562,9 @@
             virtual ~DeviceInfo3();
         private:
             CameraMetadata mCameraCharacteristics;
+            // A copy of mCameraCharacteristics without performance class
+            // override
+            std::unique_ptr<CameraMetadata> mCameraCharNoPCOverride;
             std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
             void queryPhysicalCameraIds();
             SystemCameraKind getSystemCameraKind();
@@ -565,11 +577,12 @@
             static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag,
                     android_pixel_format_t format,
                     std::vector<std::tuple<size_t, size_t>> *sizes /*out*/);
-            void getSupportedDurations( const CameraMetadata& ch, uint32_t tag,
+            static void getSupportedDurations( const CameraMetadata& ch, uint32_t tag,
                     android_pixel_format_t format,
                     const std::vector<std::tuple<size_t, size_t>>& sizes,
                     std::vector<int64_t> *durations/*out*/);
-            void getSupportedDynamicDepthDurations(const std::vector<int64_t>& depthDurations,
+            static void getSupportedDynamicDepthDurations(
+                    const std::vector<int64_t>& depthDurations,
                     const std::vector<int64_t>& blobDurations,
                     std::vector<int64_t> *dynamicDepthDurations /*out*/);
             static void getSupportedDynamicDepthSizes(
@@ -686,7 +699,7 @@
     static const char* torchStatusToString(
         const hardware::camera::common::V1_0::TorchModeStatus&);
 
-    status_t getCameraCharacteristicsLocked(const std::string &id,
+    status_t getCameraCharacteristicsLocked(const std::string &id, bool overrideForPerfClass,
             CameraMetadata* characteristics) const;
     void filterLogicalCameraIdsLocked(std::vector<std::string>& deviceIds) const;
 
@@ -700,6 +713,8 @@
     status_t convertToHALStreamCombinationAndCameraIdsLocked(
               const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
                       &cameraIdsAndSessionConfigs,
+              const std::set<std::string>& perfClassPrimaryCameraIds,
+              int targetSdkVersion,
               hardware::hidl_vec<hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
                       *halCameraIdsAndStreamCombinations,
               bool *earlyExit);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index d05a2e1..aefc75e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -75,7 +75,7 @@
 
 namespace android {
 
-Camera3Device::Camera3Device(const String8 &id):
+Camera3Device::Camera3Device(const String8 &id, bool overrideForPerfClass):
         mId(id),
         mOperatingMode(NO_MODE),
         mIsConstrainedHighSpeedConfiguration(false),
@@ -93,7 +93,8 @@
         mListener(NULL),
         mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID),
         mLastTemplateId(-1),
-        mNeedFixupMonochromeTags(false)
+        mNeedFixupMonochromeTags(false),
+        mOverrideForPerfClass(overrideForPerfClass)
 {
     ATRACE_CALL();
     ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
@@ -132,7 +133,7 @@
         return res;
     }
 
-    res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
+    res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
     if (res != OK) {
         SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
         session->close();
@@ -144,8 +145,9 @@
     bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
     if (isLogical) {
         for (auto& physicalId : physicalCameraIds) {
+            // Do not override characteristics for physical cameras
             res = manager->getCameraCharacteristics(
-                    physicalId, &mPhysicalDeviceInfoMap[physicalId]);
+                    physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
             if (res != OK) {
                 SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
                         physicalId.c_str(), strerror(-res), res);
@@ -353,9 +355,15 @@
     camera_metadata_entry_t availableTestPatternModes = mDeviceInfo.find(
             ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES);
     for (size_t i = 0; i < availableTestPatternModes.count; i++) {
-        if (availableTestPatternModes.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
+        if (availableTestPatternModes.data.i32[i] ==
+                ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
             mSupportCameraMute = true;
+            mSupportTestPatternSolidColor = true;
             break;
+        } else if (availableTestPatternModes.data.i32[i] ==
+                ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK) {
+            mSupportCameraMute = true;
+            mSupportTestPatternSolidColor = false;
         }
     }
 
@@ -771,16 +779,21 @@
     }
 
     lines = String8("    In-flight requests:\n");
-    if (mInFlightMap.size() == 0) {
-        lines.append("      None\n");
-    } else {
-        for (size_t i = 0; i < mInFlightMap.size(); i++) {
-            InFlightRequest r = mInFlightMap.valueAt(i);
-            lines.appendFormat("      Frame %d |  Timestamp: %" PRId64 ", metadata"
-                    " arrived: %s, buffers left: %d\n", mInFlightMap.keyAt(i),
-                    r.shutterTimestamp, r.haveResultMetadata ? "true" : "false",
-                    r.numBuffersLeft);
+    if (mInFlightLock.try_lock()) {
+        if (mInFlightMap.size() == 0) {
+            lines.append("      None\n");
+        } else {
+            for (size_t i = 0; i < mInFlightMap.size(); i++) {
+                InFlightRequest r = mInFlightMap.valueAt(i);
+                lines.appendFormat("      Frame %d |  Timestamp: %" PRId64 ", metadata"
+                        " arrived: %s, buffers left: %d\n", mInFlightMap.keyAt(i),
+                        r.shutterTimestamp, r.haveResultMetadata ? "true" : "false",
+                        r.numBuffersLeft);
+            }
         }
+        mInFlightLock.unlock();
+    } else {
+        lines.append("      Failed to acquire In-flight lock!\n");
     }
     write(fd, lines.string(), lines.size());
 
@@ -4163,7 +4176,7 @@
         mCurrentAfTriggerId(0),
         mCurrentPreCaptureTriggerId(0),
         mRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_NONE),
-        mCameraMute(false),
+        mCameraMute(ANDROID_SENSOR_TEST_PATTERN_MODE_OFF),
         mCameraMuteChanged(false),
         mRepeatingLastFrameNumber(
             hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES),
@@ -5265,11 +5278,11 @@
     return OK;
 }
 
-status_t Camera3Device::RequestThread::setCameraMute(bool enabled) {
+status_t Camera3Device::RequestThread::setCameraMute(int32_t muteMode) {
     ATRACE_CALL();
     Mutex::Autolock l(mTriggerMutex);
-    if (enabled != mCameraMute) {
-        mCameraMute = enabled;
+    if (muteMode != mCameraMute) {
+        mCameraMute = muteMode;
         mCameraMuteChanged = true;
     }
     return OK;
@@ -5844,8 +5857,8 @@
         request->mOriginalTestPatternData[3]
     };
 
-    if (mCameraMute) {
-        testPatternMode = ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR;
+    if (mCameraMute != ANDROID_SENSOR_TEST_PATTERN_MODE_OFF) {
+        testPatternMode = mCameraMute;
         testPatternData[0] = 0;
         testPatternData[1] = 0;
         testPatternData[2] = 0;
@@ -6535,7 +6548,11 @@
     if (mRequestThread == nullptr || !mSupportCameraMute) {
         return INVALID_OPERATION;
     }
-    return mRequestThread->setCameraMute(enabled);
+    int32_t muteMode =
+            !enabled                      ? ANDROID_SENSOR_TEST_PATTERN_MODE_OFF :
+            mSupportTestPatternSolidColor ? ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR :
+                                            ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK;
+    return mRequestThread->setCameraMute(muteMode);
 }
 
 status_t Camera3Device::injectCamera(const String8& injectedCamId,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index f962c78..aeae042 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -89,7 +89,7 @@
             public camera3::FlushBufferInterface {
   public:
 
-    explicit Camera3Device(const String8& id);
+    explicit Camera3Device(const String8& id, bool overrideForPerfClass);
 
     virtual ~Camera3Device();
 
@@ -918,7 +918,7 @@
         status_t setRotateAndCropAutoBehavior(
                 camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue);
 
-        status_t setCameraMute(bool enabled);
+        status_t setCameraMute(int32_t muteMode);
 
         status_t setHalInterface(sp<HalInterface> newHalInterface);
 
@@ -1069,7 +1069,7 @@
         uint32_t           mCurrentAfTriggerId;
         uint32_t           mCurrentPreCaptureTriggerId;
         camera_metadata_enum_android_scaler_rotate_and_crop_t mRotateAndCropOverride;
-        bool               mCameraMute;
+        int32_t            mCameraMute; // 0 = no mute, otherwise the TEST_PATTERN_MODE to use
         bool               mCameraMuteChanged;
 
         int64_t            mRepeatingLastFrameNumber;
@@ -1342,6 +1342,12 @@
 
     // Whether the HAL supports camera muting via test pattern
     bool mSupportCameraMute = false;
+    // Whether the HAL supports SOLID_COLOR or BLACK if mSupportCameraMute is true
+    bool mSupportTestPatternSolidColor = false;
+
+    // Whether the camera framework overrides the device characteristics for
+    // performance class.
+    bool mOverrideForPerfClass;
 
     // Injection camera related methods.
     class Camera3DeviceInjectionMethods : public virtual RefBase {
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index aa1e95a..7d1b3cf 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -59,7 +59,8 @@
     android::CameraMetadata cameraMetadata;
     HStatus status = HStatus::NO_ERROR;
     binder::Status serviceRet =
-        mAidlICameraService->getCameraCharacteristics(String16(cameraId.c_str()), &cameraMetadata);
+        mAidlICameraService->getCameraCharacteristics(String16(cameraId.c_str()),
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, &cameraMetadata);
     HCameraMetadata hidlMetadata;
     if (!serviceRet.isOk()) {
         switch(serviceRet.serviceSpecificErrorCode()) {
@@ -104,7 +105,8 @@
     sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = hybridCallbacks;
     binder::Status serviceRet = mAidlICameraService->connectDevice(
             callbacks, String16(cameraId.c_str()), String16(""), {},
-            hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
+            hardware::ICameraService::USE_CALLING_UID, 0/*oomScoreOffset*/,
+            /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*out*/&deviceRemote);
     HStatus status = HStatus::NO_ERROR;
     if (!serviceRet.isOk()) {
         ALOGE("%s: Unable to connect to camera device", __FUNCTION__);
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 985b2f8..e46bf74 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -232,7 +232,8 @@
     mCameraService->getCameraInfo(cameraId, &cameraInfo);
 
     CameraMetadata metadata;
-    mCameraService->getCameraCharacteristics(cameraIdStr, &metadata);
+    mCameraService->getCameraCharacteristics(cameraIdStr,
+            /*targetSdkVersion*/__ANDROID_API_FUTURE__, &metadata);
 }
 
 void CameraFuzzer::invokeCameraSound() {
@@ -319,7 +320,7 @@
 
         rc = mCameraService->connect(this, cameraId, String16(),
                 android::CameraService::USE_CALLING_UID, android::CameraService::USE_CALLING_PID,
-                &cameraDevice);
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, &cameraDevice);
         if (!rc.isOk()) {
             // camera not connected
             return;
@@ -526,7 +527,8 @@
         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
         sp<hardware::camera2::ICameraDeviceUser> device;
         mCameraService->connectDevice(callbacks, String16(s.cameraId), String16(), {},
-                android::CameraService::USE_CALLING_UID, &device);
+                android::CameraService::USE_CALLING_UID, 0/*oomScoreDiff*/,
+                /*targetSdkVersion*/__ANDROID_API_FUTURE__, &device);
         if (device == nullptr) {
             continue;
         }
diff --git a/services/camera/libcameraservice/tests/ClientManagerTest.cpp b/services/camera/libcameraservice/tests/ClientManagerTest.cpp
index 037c5c2..c79ef45 100644
--- a/services/camera/libcameraservice/tests/ClientManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/ClientManagerTest.cpp
@@ -44,7 +44,7 @@
 
 TestDescriptorPtr makeDescFromTestClient(const TestClient& tc) {
     return std::make_shared<TestClientDescriptor>(/*ID*/tc.mId, tc, tc.mCost, tc.mConflictingKeys,
-            tc.mScore, tc.mOwnerId, tc.mState, tc.mIsVendorClient);
+            tc.mScore, tc.mOwnerId, tc.mState, tc.mIsVendorClient, /*oomScoreOffset*/0);
 }
 
 class TestClientManager : public ClientManager<int, TestClient> {
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index 09258ef..d164885 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -64,20 +64,26 @@
      * case where the construction is offloaded to another thread which isn't a
      * hwbinder thread.
      */
-    ClientPriority(int32_t score, int32_t state, bool isVendorClient) :
-            mScore((score == INVALID_ADJ) ? UNKNOWN_ADJ : score),
-            mState(state),
-            mIsVendorClient(isVendorClient) { }
+    ClientPriority(int32_t score, int32_t state, bool isVendorClient, int32_t scoreOffset = 0) :
+            mIsVendorClient(isVendorClient), mScoreOffset(scoreOffset) {
+        setScore(score);
+        setState(state);
+    }
 
     int32_t getScore() const { return mScore; }
     int32_t getState() const { return mState; }
+    int32_t isVendorClient() const { return mIsVendorClient; }
 
     void setScore(int32_t score) {
         // For vendor clients, the score is set once and for all during
         // construction. Otherwise, it can get reset each time cameraserver
         // queries ActivityManagerService for oom_adj scores / states .
-        if (!mIsVendorClient) {
-            mScore = (score == INVALID_ADJ) ? UNKNOWN_ADJ : score;
+        // For clients where the score offset is set by the app, add it to the
+        // score provided by ActivityManagerService.
+        if (score == INVALID_ADJ) {
+            mScore = UNKNOWN_ADJ;
+        } else {
+            mScore = mScoreOffset + score;
         }
     }
 
@@ -87,9 +93,7 @@
       // queries ActivityManagerService for oom_adj scores / states
       // (ActivityManagerService returns a vendor process' state as
       // PROCESS_STATE_NONEXISTENT.
-      if (!mIsVendorClient) {
-          mState = state;
-      }
+      mState = state;
     }
 
     bool operator==(const ClientPriority& rhs) const {
@@ -120,6 +124,7 @@
         int32_t mScore;
         int32_t mState;
         bool mIsVendorClient = false;
+        int32_t mScoreOffset = 0;
 };
 
 // --------------------------------------------------------------------------------
@@ -137,9 +142,10 @@
 public:
     ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
             const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
-            bool isVendorClient);
+            bool isVendorClient, int32_t oomScoreOffset);
     ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
-            int32_t score, int32_t ownerId, int32_t state, bool isVendorClient);
+            int32_t score, int32_t ownerId, int32_t state, bool isVendorClient,
+            int32_t oomScoreOffset);
 
     ~ClientDescriptor();
 
@@ -204,18 +210,18 @@
 template<class KEY, class VALUE>
 ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
         const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
-        bool isVendorClient) :
+        bool isVendorClient, int32_t scoreOffset) :
         mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys},
-        mPriority(score, state, isVendorClient),
+        mPriority(score, state, isVendorClient, scoreOffset),
         mOwnerId{ownerId} {}
 
 template<class KEY, class VALUE>
 ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
         std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state,
-        bool isVendorClient) :
+        bool isVendorClient, int32_t scoreOffset) :
         mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
         mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
-        mPriority(score, state, isVendorClient), mOwnerId{ownerId} {}
+        mPriority(score, state, isVendorClient, scoreOffset), mOwnerId{ownerId} {}
 
 template<class KEY, class VALUE>
 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
@@ -266,6 +272,9 @@
     // off in the incoming priority argument since an AIDL thread might have
     // called getCurrentServingCall() == BinderCallType::HWBINDER after refreshing
     // priorities for old clients through ProcessInfoService::getProcessStatesScoresFromPids().
+    if (mPriority.isVendorClient()) {
+        return;
+    }
     mPriority.setScore(priority.getScore());
     mPriority.setState(priority.getState());
 }
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 6dcf440..ed6ee9b 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <cutils/properties.h>
+
 #include "SessionConfigurationUtils.h"
 #include "../api2/DepthCompositeStream.h"
 #include "../api2/HeicCompositeStream.h"
@@ -29,6 +31,11 @@
 namespace android {
 namespace camera3 {
 
+int32_t SessionConfigurationUtils::PERF_CLASS_LEVEL =
+        property_get_int32("ro.odm.build.media_performance_class", 0);
+
+bool SessionConfigurationUtils::IS_PERF_CLASS = (PERF_CLASS_LEVEL == SDK_VERSION_S);
+
 void StreamConfiguration::getStreamConfigurations(
         const CameraMetadata &staticInfo, int configuration,
         std::unordered_map<int, std::vector<StreamConfiguration>> *scm) {
@@ -480,7 +487,8 @@
         const SessionConfiguration& sessionConfiguration,
         const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
         metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
-        hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration, bool *earlyExit) {
+        hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration,
+        bool overrideForPerfClass, bool *earlyExit) {
 
     auto operatingMode = sessionConfiguration.getOperatingMode();
     binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId);
@@ -539,7 +547,8 @@
         String8 physicalCameraId = String8(it.getPhysicalCameraId());
 
         std::vector<int32_t> sensorPixelModesUsed = it.getSensorPixelModesUsed();
-        const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId);
+        const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId,
+                overrideForPerfClass);
         const CameraMetadata &metadataChosen =
                 physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo;
 
@@ -669,15 +678,22 @@
         const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
         const CameraMetadata &staticInfo, bool flexibleConsumer,
         std::unordered_set<int32_t> *overriddenSensorPixelModesUsed) {
+
+    const std::unordered_set<int32_t> &sensorPixelModesUsedSet =
+            convertToSet(sensorPixelModesUsed);
     if (!isUltraHighResolutionSensor(staticInfo)) {
+        if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
+                sensorPixelModesUsedSet.end()) {
+            // invalid value for non ultra high res sensors
+            return BAD_VALUE;
+        }
         overriddenSensorPixelModesUsed->clear();
         overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
         return OK;
     }
 
     StreamConfigurationPair streamConfigurationPair = getStreamConfigurationPair(staticInfo);
-    const std::unordered_set<int32_t> &sensorPixelModesUsedSet =
-            convertToSet(sensorPixelModesUsed);
+
     bool isInDefaultStreamConfigurationMap =
             inStreamConfigurationMap(format, width, height,
                     streamConfigurationPair.mDefaultStreamConfigurationMap);
@@ -761,5 +777,13 @@
     return true;
 }
 
+bool SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+        const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
+        int targetSdkVersion) {
+    bool isPerfClassPrimaryCamera =
+            perfClassPrimaryCameraIds.find(cameraId) != perfClassPrimaryCameraIds.end();
+    return targetSdkVersion >= SDK_VERSION_S && isPerfClassPrimaryCamera;
+}
+
 } // namespace camera3
 } // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 863a0cd..b4814b6 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -27,6 +27,7 @@
 
 #include <device3/Camera3StreamInterface.h>
 
+#include <set>
 #include <stdint.h>
 
 // Convenience methods for constructing binder::Status objects for error returns
@@ -43,7 +44,7 @@
 namespace android {
 namespace camera3 {
 
-typedef std::function<CameraMetadata (const String8 &)> metadataGetter;
+typedef std::function<CameraMetadata (const String8 &, int targetSdkVersion)> metadataGetter;
 
 class StreamConfiguration {
 public:
@@ -114,7 +115,7 @@
             const String8 &cameraId, const CameraMetadata &deviceInfo,
             metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
             hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration,
-            bool *earlyExit);
+            bool overrideForPerfClass, bool *earlyExit);
 
     // Utility function to convert a V3_7::StreamConfiguration to
     // V3_4::StreamConfiguration. Return false if the original V3_7 configuration cannot
@@ -134,10 +135,19 @@
 
     static int32_t getAppropriateModeTag(int32_t defaultTag, bool maxResolution = false);
 
+    static bool targetPerfClassPrimaryCamera(
+            const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
+            int32_t targetSdkVersion);
+
     static const int32_t MAX_SURFACES_PER_STREAM = 4;
 
     static const int32_t ROUNDING_WIDTH_CAP = 1920;
 
+    static const int32_t SDK_VERSION_S = 31;
+    static int32_t PERF_CLASS_LEVEL;
+    static bool IS_PERF_CLASS;
+    static const int32_t PERF_CLASS_JPEG_THRESH_W = 1920;
+    static const int32_t PERF_CLASS_JPEG_THRESH_H = 1080;
 };
 
 } // camera3
diff --git a/services/mediametrics/statsd_audiopolicy.cpp b/services/mediametrics/statsd_audiopolicy.cpp
index f44b7c4..3d9376e 100644
--- a/services/mediametrics/statsd_audiopolicy.cpp
+++ b/services/mediametrics/statsd_audiopolicy.cpp
@@ -32,7 +32,7 @@
 #include <statslog.h>
 
 #include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
 #include "iface_statsd.h"
 
 namespace android {
@@ -50,7 +50,7 @@
 
     // the rest into our own proto
     //
-    ::android::stats::mediametrics::AudioPolicyData metrics_proto;
+    ::android::stats::mediametrics_message::AudioPolicyData metrics_proto;
 
     // flesh out the protobuf we'll hand off with our data
     //
diff --git a/services/mediametrics/statsd_audiorecord.cpp b/services/mediametrics/statsd_audiorecord.cpp
index 70a67ae..41efcaa 100644
--- a/services/mediametrics/statsd_audiorecord.cpp
+++ b/services/mediametrics/statsd_audiorecord.cpp
@@ -33,7 +33,7 @@
 
 #include "MediaMetricsService.h"
 #include "StringUtils.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
 #include "iface_statsd.h"
 
 namespace android {
@@ -50,7 +50,7 @@
 
     // the rest into our own proto
     //
-    ::android::stats::mediametrics::AudioRecordData metrics_proto;
+    ::android::stats::mediametrics_message::AudioRecordData metrics_proto;
 
     // flesh out the protobuf we'll hand off with our data
     //
diff --git a/services/mediametrics/statsd_audiothread.cpp b/services/mediametrics/statsd_audiothread.cpp
index 34cc923..e9b6dd6 100644
--- a/services/mediametrics/statsd_audiothread.cpp
+++ b/services/mediametrics/statsd_audiothread.cpp
@@ -32,7 +32,7 @@
 #include <statslog.h>
 
 #include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
 #include "iface_statsd.h"
 
 namespace android {
@@ -50,7 +50,7 @@
 
     // the rest into our own proto
     //
-    ::android::stats::mediametrics::AudioThreadData metrics_proto;
+    ::android::stats::mediametrics_message::AudioThreadData metrics_proto;
 
 #define	MM_PREFIX "android.media.audiothread."
 
diff --git a/services/mediametrics/statsd_audiotrack.cpp b/services/mediametrics/statsd_audiotrack.cpp
index fe269a1..59627ae 100644
--- a/services/mediametrics/statsd_audiotrack.cpp
+++ b/services/mediametrics/statsd_audiotrack.cpp
@@ -33,7 +33,7 @@
 
 #include "MediaMetricsService.h"
 #include "StringUtils.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
 #include "iface_statsd.h"
 
 namespace android {
@@ -51,7 +51,7 @@
 
     // the rest into our own proto
     //
-    ::android::stats::mediametrics::AudioTrackData metrics_proto;
+    ::android::stats::mediametrics_message::AudioTrackData metrics_proto;
 
     // flesh out the protobuf we'll hand off with our data
     //
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index 2cfdf24..065c594 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include <statslog.h>
+#include <stats_event.h>
 
 #include "cleaner.h"
 #include "MediaMetricsService.h"
@@ -43,11 +44,20 @@
 {
     if (item == nullptr) return false;
 
-    // these go into the statsd wrapper
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, android::util::MEDIA_CODEC_REPORTED);
+
     const nsecs_t timestamp_nanos = MediaMetricsService::roundTime(item->getTimestamp());
-    const std::string package_name = item->getPkgName();
-    const int64_t package_version_code = item->getPkgVersionCode();
-    const int64_t media_apex_version = 0;
+    AStatsEvent_writeInt64(event, timestamp_nanos);
+
+    std::string package_name = item->getPkgName();
+    AStatsEvent_writeString(event, package_name.c_str());
+
+    int64_t package_version_code = item->getPkgVersionCode();
+    AStatsEvent_writeInt64(event, package_version_code);
+
+    int64_t media_apex_version = 0;
+    AStatsEvent_writeInt64(event, media_apex_version);
 
     // the rest into our own proto
     //
@@ -55,250 +65,334 @@
 
     // flesh out the protobuf we'll hand off with our data
     //
-    // android.media.mediacodec.codec   string
     std::string codec;
     if (item->getString("android.media.mediacodec.codec", &codec)) {
         metrics_proto.set_codec(codec);
     }
+    AStatsEvent_writeString(event, codec.c_str());
 
     std::string mime;
     if (item->getString("android.media.mediacodec.mime", &mime)) {
         metrics_proto.set_mime(mime);
     }
+    AStatsEvent_writeString(event, mime.c_str());
 
     std::string mode;
-    if ( item->getString("android.media.mediacodec.mode", &mode)) {
+    if (item->getString("android.media.mediacodec.mode", &mode)) {
         metrics_proto.set_mode(mode);
     }
+    AStatsEvent_writeString(event, mode.c_str());
 
     int32_t encoder = -1;
-    if ( item->getInt32("android.media.mediacodec.encoder", &encoder)) {
+    if (item->getInt32("android.media.mediacodec.encoder", &encoder)) {
         metrics_proto.set_encoder(encoder);
     }
+    AStatsEvent_writeInt32(event, encoder);
 
     int32_t secure = -1;
-    if ( item->getInt32("android.media.mediacodec.secure", &secure)) {
+    if (item->getInt32("android.media.mediacodec.secure", &secure)) {
         metrics_proto.set_secure(secure);
     }
+    AStatsEvent_writeInt32(event, secure);
 
     int32_t width = -1;
-    if ( item->getInt32("android.media.mediacodec.width", &width)) {
+    if (item->getInt32("android.media.mediacodec.width", &width)) {
         metrics_proto.set_width(width);
     }
+    AStatsEvent_writeInt32(event, width);
 
     int32_t height = -1;
-    if ( item->getInt32("android.media.mediacodec.height", &height)) {
+    if (item->getInt32("android.media.mediacodec.height", &height)) {
         metrics_proto.set_height(height);
     }
+    AStatsEvent_writeInt32(event, height);
 
     int32_t rotation = -1;
-    if ( item->getInt32("android.media.mediacodec.rotation-degrees", &rotation)) {
+    if (item->getInt32("android.media.mediacodec.rotation-degrees", &rotation)) {
         metrics_proto.set_rotation(rotation);
     }
-    // android.media.mediacodec.crypto  int32 (although missing if not needed)
+    AStatsEvent_writeInt32(event, rotation);
+
     int32_t crypto = -1;
-    if ( item->getInt32("android.media.mediacodec.crypto", &crypto)) {
+    if (item->getInt32("android.media.mediacodec.crypto", &crypto)) {
         metrics_proto.set_crypto(crypto);
     }
+    AStatsEvent_writeInt32(event, crypto);
 
     int32_t profile = -1;
-    if ( item->getInt32("android.media.mediacodec.profile", &profile)) {
+    if (item->getInt32("android.media.mediacodec.profile", &profile)) {
         metrics_proto.set_profile(profile);
     }
+    AStatsEvent_writeInt32(event, profile);
 
     int32_t level = -1;
-    if ( item->getInt32("android.media.mediacodec.level", &level)) {
+    if (item->getInt32("android.media.mediacodec.level", &level)) {
         metrics_proto.set_level(level);
     }
+    AStatsEvent_writeInt32(event, level);
+
 
     int32_t max_width = -1;
     if ( item->getInt32("android.media.mediacodec.maxwidth", &max_width)) {
         metrics_proto.set_max_width(max_width);
     }
+    AStatsEvent_writeInt32(event, max_width);
 
     int32_t max_height = -1;
     if ( item->getInt32("android.media.mediacodec.maxheight", &max_height)) {
         metrics_proto.set_max_height(max_height);
     }
+    AStatsEvent_writeInt32(event, max_height);
 
     int32_t error_code = -1;
     if ( item->getInt32("android.media.mediacodec.errcode", &error_code)) {
         metrics_proto.set_error_code(error_code);
     }
+    AStatsEvent_writeInt32(event, error_code);
 
     std::string error_state;
     if ( item->getString("android.media.mediacodec.errstate", &error_state)) {
         metrics_proto.set_error_state(error_state);
     }
+    AStatsEvent_writeString(event, error_state.c_str());
 
     int64_t latency_max = -1;
-    if ( item->getInt64("android.media.mediacodec.latency.max", &latency_max)) {
+    if (item->getInt64("android.media.mediacodec.latency.max", &latency_max)) {
         metrics_proto.set_latency_max(latency_max);
     }
+    AStatsEvent_writeInt64(event, latency_max);
 
     int64_t latency_min = -1;
-    if ( item->getInt64("android.media.mediacodec.latency.min", &latency_min)) {
+    if (item->getInt64("android.media.mediacodec.latency.min", &latency_min)) {
         metrics_proto.set_latency_min(latency_min);
     }
+    AStatsEvent_writeInt64(event, latency_min);
 
     int64_t latency_avg = -1;
-    if ( item->getInt64("android.media.mediacodec.latency.avg", &latency_avg)) {
+    if (item->getInt64("android.media.mediacodec.latency.avg", &latency_avg)) {
         metrics_proto.set_latency_avg(latency_avg);
     }
+    AStatsEvent_writeInt64(event, latency_avg);
 
     int64_t latency_count = -1;
-    if ( item->getInt64("android.media.mediacodec.latency.n", &latency_count)) {
+    if (item->getInt64("android.media.mediacodec.latency.n", &latency_count)) {
         metrics_proto.set_latency_count(latency_count);
     }
+    AStatsEvent_writeInt64(event, latency_count);
 
     int64_t latency_unknown = -1;
-    if ( item->getInt64("android.media.mediacodec.latency.unknown", &latency_unknown)) {
+    if (item->getInt64("android.media.mediacodec.latency.unknown", &latency_unknown)) {
         metrics_proto.set_latency_unknown(latency_unknown);
     }
+    AStatsEvent_writeInt64(event, latency_unknown);
 
     int32_t queue_secure_input_buffer_error = -1;
     if (item->getInt32("android.media.mediacodec.queueSecureInputBufferError",
-                &queue_secure_input_buffer_error)) {
+            &queue_secure_input_buffer_error)) {
         metrics_proto.set_queue_secure_input_buffer_error(queue_secure_input_buffer_error);
     }
+    AStatsEvent_writeInt32(event, queue_secure_input_buffer_error);
 
     int32_t queue_input_buffer_error = -1;
     if (item->getInt32("android.media.mediacodec.queueInputBufferError",
-                &queue_input_buffer_error)) {
+            &queue_input_buffer_error)) {
         metrics_proto.set_queue_input_buffer_error(queue_input_buffer_error);
     }
-    // android.media.mediacodec.latency.hist    NOT EMITTED
+    AStatsEvent_writeInt32(event, queue_input_buffer_error);
 
     std::string bitrate_mode;
     if (item->getString("android.media.mediacodec.bitrate_mode", &bitrate_mode)) {
         metrics_proto.set_bitrate_mode(bitrate_mode);
     }
+    AStatsEvent_writeString(event, bitrate_mode.c_str());
 
     int32_t bitrate = -1;
     if (item->getInt32("android.media.mediacodec.bitrate", &bitrate)) {
         metrics_proto.set_bitrate(bitrate);
     }
+    AStatsEvent_writeInt32(event, bitrate);
 
     int64_t lifetime_millis = -1;
     if (item->getInt64("android.media.mediacodec.lifetimeMs", &lifetime_millis)) {
         lifetime_millis = mediametrics::bucket_time_minutes(lifetime_millis);
         metrics_proto.set_lifetime_millis(lifetime_millis);
     }
+    AStatsEvent_writeInt64(event, lifetime_millis);
 
-    // android.media.mediacodec.channelCount
+    int64_t playback_duration_sec = -1;
+    item->getInt64("android.media.mediacodec.playback-duration-sec", &playback_duration_sec);
+    // DO NOT record  playback-duration in the metrics_proto - it should only
+    // exist in the flattened atom
+    AStatsEvent_writeInt64(event, playback_duration_sec);
+
+    std::string sessionId;
+    if (item->getString("android.media.mediacodec.log-session-id", &sessionId)) {
+        metrics_proto.set_log_session_id(sessionId);
+    }
+    AStatsEvent_writeString(event, codec.c_str());
+
     int32_t channelCount = -1;
-    if ( item->getInt32("android.media.mediacodec.channelCount", &channelCount)) {
+    if (item->getInt32("android.media.mediacodec.channelCount", &channelCount)) {
         metrics_proto.set_channel_count(channelCount);
     }
+    AStatsEvent_writeInt32(event, channelCount);
 
-    // android.media.mediacodec.sampleRate
     int32_t sampleRate = -1;
-    if ( item->getInt32("android.media.mediacodec.sampleRate", &sampleRate)) {
+    if (item->getInt32("android.media.mediacodec.sampleRate", &sampleRate)) {
         metrics_proto.set_sample_rate(sampleRate);
     }
+    AStatsEvent_writeInt32(event, sampleRate);
 
     // TODO PWG may want these fuzzed up a bit to obscure some precision
-    // android.media.mediacodec.vencode.bytes
     int64_t bytes = -1;
-    if ( item->getInt64("android.media.mediacodec.vencode.bytes", &bytes)) {
+    if (item->getInt64("android.media.mediacodec.vencode.bytes", &bytes)) {
         metrics_proto.set_video_encode_bytes(bytes);
     }
+    AStatsEvent_writeInt64(event, bytes);
 
-    // android.media.mediacodec.vencode.frames
     int64_t frames = -1;
-    if ( item->getInt64("android.media.mediacodec.vencode.frames", &frames)) {
+    if (item->getInt64("android.media.mediacodec.vencode.frames", &frames)) {
         metrics_proto.set_video_encode_frames(frames);
     }
+    AStatsEvent_writeInt64(event, frames);
 
-    // android.media.mediacodec.vencode.durationUs
-    int64_t durationUs = -1;
-    if ( item->getInt64("android.media.mediacodec.vencode.durationUs", &durationUs)) {
-        metrics_proto.set_video_encode_duration_us(durationUs);
-    }
-
-    // android.media.mediacodec.color-format
-    int32_t colorFormat = -1;
-    if ( item->getInt32("android.media.mediacodec.color-format", &colorFormat)) {
-        metrics_proto.set_color_format(colorFormat);
-    }
-
-    // android.media.mediacodec.frame-rate
-    double frameRate = -1.0;
-    if ( item->getDouble("android.media.mediacodec.frame-rate", &frameRate)) {
-        metrics_proto.set_frame_rate(frameRate);
-    }
-
-    // android.media.mediacodec.capture-rate
-    double captureRate = -1.0;
-    if ( item->getDouble("android.media.mediacodec.capture-rate", &captureRate)) {
-        metrics_proto.set_capture_rate(captureRate);
-    }
-
-    // android.media.mediacodec.operating-rate
-    double operatingRate = -1.0;
-    if ( item->getDouble("android.media.mediacodec.operating-rate", &operatingRate)) {
-        metrics_proto.set_operating_rate(operatingRate);
-    }
-
-    // android.media.mediacodec.priority
-    int32_t priority = -1;
-    if ( item->getInt32("android.media.mediacodec.priority", &priority)) {
-        metrics_proto.set_priority(priority);
-    }
-
-    // android.media.mediacodec.video-qp-i-min
-    int32_t qpIMin = -1;
-    if ( item->getInt32("android.media.mediacodec.video-qp-i-min", &qpIMin)) {
-        metrics_proto.set_video_qp_i_min(qpIMin);
-    }
-
-    // android.media.mediacodec.video-qp-i-max
-    int32_t qpIMax = -1;
-    if ( item->getInt32("android.media.mediacodec.video-qp-i-max", &qpIMax)) {
-        metrics_proto.set_video_qp_i_max(qpIMax);
-    }
-
-    // android.media.mediacodec.video-qp-p-min
-    int32_t qpPMin = -1;
-    if ( item->getInt32("android.media.mediacodec.video-qp-p-min", &qpPMin)) {
-        metrics_proto.set_video_qp_p_min(qpPMin);
-    }
-
-    // android.media.mediacodec.video-qp-p-max
-    int32_t qpPMax = -1;
-    if ( item->getInt32("android.media.mediacodec.video-qp-p-max", &qpPMax)) {
-        metrics_proto.set_video_qp_p_max(qpPMax);
-    }
-
-    // android.media.mediacodec.video-qp-b-min
-    int32_t qpBMin = -1;
-    if ( item->getInt32("android.media.mediacodec.video-qp-b-min", &qpBMin)) {
-        metrics_proto.set_video_qp_b_min(qpIMin);
-    }
-
-    // android.media.mediacodec.video-qp-b-max
-    int32_t qpBMax = -1;
-    if ( item->getInt32("android.media.mediacodec.video-qp-b-max", &qpBMax)) {
-        metrics_proto.set_video_qp_b_max(qpBMax);
-    }
-
-    // android.media.mediacodec.video.input.bytes
     int64_t inputBytes = -1;
-    if ( item->getInt64("android.media.mediacodec.video.input.bytes", &inputBytes)) {
+    if (item->getInt64("android.media.mediacodec.video.input.bytes", &inputBytes)) {
         metrics_proto.set_video_input_bytes(inputBytes);
     }
+    AStatsEvent_writeInt64(event, inputBytes);
 
-    // android.media.mediacodec.video.input.frames
     int64_t inputFrames = -1;
-    if ( item->getInt64("android.media.mediacodec.video.input.frames", &inputFrames)) {
+    if (item->getInt64("android.media.mediacodec.video.input.frames", &inputFrames)) {
         metrics_proto.set_video_input_frames(inputFrames);
     }
+    AStatsEvent_writeInt64(event, inputFrames);
 
-    // android.media.mediacodec.original.bitrate
+    int64_t durationUs = -1;
+    if (item->getInt64("android.media.mediacodec.vencode.durationUs", &durationUs)) {
+        metrics_proto.set_video_encode_duration_us(durationUs);
+    }
+    AStatsEvent_writeInt64(event, durationUs);
+
+    int32_t colorFormat = -1;
+    if (item->getInt32("android.media.mediacodec.color-format", &colorFormat)) {
+        metrics_proto.set_color_format(colorFormat);
+    }
+    AStatsEvent_writeInt32(event, colorFormat);
+
+    double frameRate = -1.0;
+    if (item->getDouble("android.media.mediacodec.frame-rate", &frameRate)) {
+        metrics_proto.set_frame_rate(frameRate);
+    }
+    AStatsEvent_writeFloat(event, (float) frameRate);
+
+    double captureRate = -1.0;
+    if (item->getDouble("android.media.mediacodec.capture-rate", &captureRate)) {
+        metrics_proto.set_capture_rate(captureRate);
+    }
+    AStatsEvent_writeFloat(event, (float) captureRate);
+
+    double operatingRate = -1.0;
+    if (item->getDouble("android.media.mediacodec.operating-rate", &operatingRate)) {
+        metrics_proto.set_operating_rate(operatingRate);
+    }
+    AStatsEvent_writeFloat(event, (float) operatingRate);
+
+    int32_t priority = -1;
+    if (item->getInt32("android.media.mediacodec.priority", &priority)) {
+        metrics_proto.set_priority(priority);
+    }
+    AStatsEvent_writeInt32(event, priority);
+
+    int32_t qpIMin = -1;
+    if (item->getInt32("android.media.mediacodec.video-qp-i-min", &qpIMin)) {
+        metrics_proto.set_video_qp_i_min(qpIMin);
+    }
+    AStatsEvent_writeInt32(event, qpIMin);
+
+    int32_t qpIMax = -1;
+    if (item->getInt32("android.media.mediacodec.video-qp-i-max", &qpIMax)) {
+        metrics_proto.set_video_qp_i_max(qpIMax);
+    }
+    AStatsEvent_writeInt32(event, qpIMax);
+
+    int32_t qpPMin = -1;
+    if (item->getInt32("android.media.mediacodec.video-qp-p-min", &qpPMin)) {
+        metrics_proto.set_video_qp_p_min(qpPMin);
+    }
+    AStatsEvent_writeInt32(event, qpPMin);
+
+    int32_t qpPMax = -1;
+    if (item->getInt32("android.media.mediacodec.video-qp-p-max", &qpPMax)) {
+        metrics_proto.set_video_qp_p_max(qpPMax);
+    }
+    AStatsEvent_writeInt32(event, qpPMax);
+
+    int32_t qpBMin = -1;
+    if (item->getInt32("android.media.mediacodec.video-qp-b-min", &qpBMin)) {
+        metrics_proto.set_video_qp_b_min(qpBMin);
+    }
+    AStatsEvent_writeInt32(event, qpBMin);
+
+    int32_t qpBMax = -1;
+    if (item->getInt32("android.media.mediacodec.video-qp-b-max", &qpBMax)) {
+        metrics_proto.set_video_qp_b_max(qpBMax);
+    }
+    AStatsEvent_writeInt32(event, qpBMax);
+
     int32_t originalBitrate = -1;
-    if ( item->getInt32("android.media.mediacodec.original.bitrate", &originalBitrate)) {
+    if (item->getInt32("android.media.mediacodec.original.bitrate", &originalBitrate)) {
         metrics_proto.set_original_bitrate(originalBitrate);
     }
+    AStatsEvent_writeInt32(event, originalBitrate);
+
+    int32_t shapingEnhanced = -1;
+    if ( item->getInt32("android.media.mediacodec.shaped", &shapingEnhanced)) {
+        metrics_proto.set_shaping_enhanced(shapingEnhanced);
+    }
+    AStatsEvent_writeInt32(event, shapingEnhanced);
+
+    int32_t qpIMinOri = -1;
+    if ( item->getInt32("android.media.mediacodec.original-video-qp-i-min", &qpIMinOri)) {
+        metrics_proto.set_original_video_qp_i_min(qpIMinOri);
+    }
+    AStatsEvent_writeInt32(event, qpIMinOri);
+
+    int32_t qpIMaxOri = -1;
+    if ( item->getInt32("android.media.mediacodec.original-video-qp-i-max", &qpIMaxOri)) {
+        metrics_proto.set_original_video_qp_i_max(qpIMaxOri);
+    }
+    AStatsEvent_writeInt32(event, qpIMaxOri);
+
+    int32_t qpPMinOri = -1;
+    if ( item->getInt32("android.media.mediacodec.original-video-qp-p-min", &qpPMinOri)) {
+        metrics_proto.set_original_video_qp_p_min(qpPMinOri);
+    }
+    AStatsEvent_writeInt32(event, qpPMinOri);
+
+    int32_t qpPMaxOri = -1;
+    if ( item->getInt32("android.media.mediacodec.original-video-qp-p-max", &qpPMaxOri)) {
+        metrics_proto.set_original_video_qp_p_max(qpPMaxOri);
+    }
+    AStatsEvent_writeInt32(event, qpPMaxOri);
+
+    int32_t qpBMinOri = -1;
+    if ( item->getInt32("android.media.mediacodec.original-video-qp-b-min", &qpBMinOri)) {
+        metrics_proto.set_original_video_qp_b_min(qpBMinOri);
+    }
+    AStatsEvent_writeInt32(event, qpBMinOri);
+
+    int32_t qpBMaxOri = -1;
+    if ( item->getInt32("android.media.mediacodec.original-video-qp-b-max", &qpBMaxOri)) {
+        metrics_proto.set_original_video_qp_b_max(qpBMaxOri);
+    }
+    AStatsEvent_writeInt32(event, qpBMaxOri);
+
+    int err = AStatsEvent_write(event);
+    if (err < 0) {
+      ALOGE("Failed to write codec metrics to statsd (%d)", err);
+    }
+    AStatsEvent_release(event);
 
     std::string serialized;
     if (!metrics_proto.SerializeToString(&serialized)) {
@@ -310,6 +404,7 @@
                                timestamp_nanos, package_name.c_str(), package_version_code,
                                media_apex_version,
                                bf_serialized);
+
     std::stringstream log;
     log << "result:" << result << " {"
             << " mediametrics_codec_reported:"
@@ -345,11 +440,38 @@
             << " queue_secure_input_buffer_error:" << queue_secure_input_buffer_error
             << " bitrate_mode:" << bitrate_mode
             << " bitrate:" << bitrate
+            << " original_bitrate:" << originalBitrate
             << " lifetime_millis:" << lifetime_millis
-            // TODO: add when log_session_id is merged.
-            // << " log_session_id:" << log_session_id
+            << " playback_duration_seconds:" << playback_duration_sec
+            << " log_session_id:" << sessionId
+            << " channel_count:" << channelCount
+            << " sample_rate:" << sampleRate
+            << " encode_bytes:" << bytes
+            << " encode_frames:" << frames
+            << " encode_duration_us:" << durationUs
+            << " color_format:" << colorFormat
+            << " frame_rate:" << frameRate
+            << " capture_rate:" << captureRate
+            << " operating_rate:" << operatingRate
+            << " priority:" << priority
+            << " shaping_enhanced:" << shapingEnhanced
+
+            << " qp_i_min:" << qpIMin
+            << " qp_i_max:" << qpIMax
+            << " qp_p_min:" << qpPMin
+            << " qp_p_max:" << qpPMax
+            << " qp_b_min:" << qpBMin
+            << " qp_b_max:" << qpBMax
+            << " original_qp_i_min:" << qpIMinOri
+            << " original_qp_i_max:" << qpIMaxOri
+            << " original_qp_p_min:" << qpPMinOri
+            << " original_qp_p_max:" << qpPMaxOri
+            << " original_qp_b_min:" << qpBMinOri
+            << " original_qp_b_max:" << qpBMaxOri
             << " }";
     statsdLog->log(android::util::MEDIAMETRICS_CODEC_REPORTED, log.str());
+
+
     return true;
 }
 
diff --git a/services/mediametrics/statsd_extractor.cpp b/services/mediametrics/statsd_extractor.cpp
index 2378f33..4ac5621 100644
--- a/services/mediametrics/statsd_extractor.cpp
+++ b/services/mediametrics/statsd_extractor.cpp
@@ -32,7 +32,7 @@
 #include <statslog.h>
 
 #include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
 #include "iface_statsd.h"
 
 namespace android {
@@ -50,7 +50,7 @@
 
     // the rest into our own proto
     //
-    ::android::stats::mediametrics::ExtractorData metrics_proto;
+    ::android::stats::mediametrics_message::ExtractorData metrics_proto;
 
     std::string format;
     if (item->getString("android.media.mediaextractor.fmt", &format)) {
@@ -68,17 +68,17 @@
     }
 
     std::string entry_point_string;
-    stats::mediametrics::ExtractorData::EntryPoint entry_point =
-            stats::mediametrics::ExtractorData_EntryPoint_OTHER;
+    stats::mediametrics_message::ExtractorData::EntryPoint entry_point =
+            stats::mediametrics_message::ExtractorData_EntryPoint_OTHER;
     if (item->getString("android.media.mediaextractor.entry", &entry_point_string)) {
       if (entry_point_string == "sdk") {
-        entry_point = stats::mediametrics::ExtractorData_EntryPoint_SDK;
+        entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_SDK;
       } else if (entry_point_string == "ndk-with-jvm") {
-        entry_point = stats::mediametrics::ExtractorData_EntryPoint_NDK_WITH_JVM;
+        entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_NDK_WITH_JVM;
       } else if (entry_point_string == "ndk-no-jvm") {
-        entry_point = stats::mediametrics::ExtractorData_EntryPoint_NDK_NO_JVM;
+        entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_NDK_NO_JVM;
       } else {
-        entry_point = stats::mediametrics::ExtractorData_EntryPoint_OTHER;
+        entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_OTHER;
       }
       metrics_proto.set_entry_point(entry_point);
     }
diff --git a/services/mediametrics/statsd_nuplayer.cpp b/services/mediametrics/statsd_nuplayer.cpp
index 33da81e..bdee1f2 100644
--- a/services/mediametrics/statsd_nuplayer.cpp
+++ b/services/mediametrics/statsd_nuplayer.cpp
@@ -32,7 +32,7 @@
 #include <statslog.h>
 
 #include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
 #include "iface_statsd.h"
 
 namespace android {
@@ -54,7 +54,7 @@
 
     // the rest into our own proto
     //
-    ::android::stats::mediametrics::NuPlayerData metrics_proto;
+    ::android::stats::mediametrics_message::NuPlayerData metrics_proto;
 
     // flesh out the protobuf we'll hand off with our data
     //
diff --git a/services/mediametrics/statsd_recorder.cpp b/services/mediametrics/statsd_recorder.cpp
index 6edad7c..1b312b5 100644
--- a/services/mediametrics/statsd_recorder.cpp
+++ b/services/mediametrics/statsd_recorder.cpp
@@ -57,8 +57,8 @@
 
     // string kRecorderLogSessionId = "android.media.mediarecorder.log-session-id";
     std::string log_session_id;
-    if (item->getString("android.media.mediarecorder.log_session_id", &log_session_id)) {
-        metrics_proto.set_log_session_id(std::move(log_session_id));
+    if (item->getString("android.media.mediarecorder.log-session-id", &log_session_id)) {
+        metrics_proto.set_log_session_id(log_session_id);
     }
     // string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
     std::string audio_mime;
@@ -214,8 +214,7 @@
             << " video_bitrate:" << video_bitrate
 
             << " iframe_interval:" << iframe_interval
-            // TODO Recorder - add log_session_id
-            // << " log_session_id:" << log_session_id
+            << " log_session_id:" << log_session_id
             << " }";
     statsdLog->log(android::util::MEDIAMETRICS_RECORDER_REPORTED, log.str());
     return true;
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index db61061..f31202b 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -65,6 +65,7 @@
             enabled: true,
         },
     },
+    versions: ["1"],
 }
 
 cc_library {
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/.hash b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/.hash
new file mode 100644
index 0000000..df90ffb
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/.hash
@@ -0,0 +1 @@
+7e198281434e9c679b02265e95c51ea25ed180d3
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserver.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserver.aidl
new file mode 100644
index 0000000..73e0e0b
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserver.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2020, 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;
+/* @hide */
+interface IResourceObserver {
+  oneway void onStatusChanged(android.media.MediaObservableEvent event, int uid, int pid, in android.media.MediaObservableParcel[] observables);
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserverService.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserverService.aidl
new file mode 100644
index 0000000..c2d60af
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserverService.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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;
+/* @hide */
+interface IResourceObserverService {
+  void registerObserver(android.media.IResourceObserver observer, in android.media.MediaObservableFilter[] filters);
+  void unregisterObserver(android.media.IResourceObserver observer);
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableEvent.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableEvent.aidl
new file mode 100644
index 0000000..a45f0ba
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableEvent.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2020, 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;
+/* @hide */
+@Backing(type="long")
+enum MediaObservableEvent {
+  kBusy = 1,
+  kIdle = 2,
+  kAll = -1,
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableFilter.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableFilter.aidl
new file mode 100644
index 0000000..22ae284
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableFilter.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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;
+/* @hide */
+parcelable MediaObservableFilter {
+  android.media.MediaObservableType type;
+  android.media.MediaObservableEvent eventFilter;
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableParcel.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableParcel.aidl
new file mode 100644
index 0000000..2270d87
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableParcel.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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;
+/* @hide */
+parcelable MediaObservableParcel {
+  android.media.MediaObservableType type;
+  long value = 0;
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableType.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableType.aidl
new file mode 100644
index 0000000..eab3f3f
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableType.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2020, 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;
+/* @hide */
+@Backing(type="int")
+enum MediaObservableType {
+  kInvalid = 0,
+  kVideoSecureCodec = 1000,
+  kVideoNonSecureCodec = 1001,
+}
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index b80fe57..2a20981 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -24,6 +24,7 @@
 #include <cutils/properties.h>
 #include <media/TranscoderWrapper.h>
 #include <media/TranscodingClientManager.h>
+#include <media/TranscodingDefs.h>
 #include <media/TranscodingLogger.h>
 #include <media/TranscodingResourcePolicy.h>
 #include <media/TranscodingSessionController.h>
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 3224cfc..20e4cc5 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -184,7 +184,7 @@
             // An app can avoid having this happen by closing their streams when
             // the app is paused.
             pid_t pid = VALUE_OR_FATAL(
-                aidl2legacy_int32_t_pid_t(request.getIdentity().pid));
+                aidl2legacy_int32_t_pid_t(request.getAttributionSource().pid));
             AAudioClientTracker::getInstance().setExclusiveEnabled(pid, false);
             endpointToSteal = endpoint; // return it to caller
         }
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 0b69bf6..40a664e 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -22,7 +22,7 @@
 #include <iostream>
 #include <sstream>
 
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 #include <aaudio/AAudio.h>
 #include <media/AidlConversion.h>
 #include <mediautils/ServiceUtilities.h>
@@ -47,18 +47,18 @@
        std::move(_tmp.value()); })
 
 using android::AAudioService;
-using android::media::permission::Identity;
+using android::content::AttributionSourceState;
 using binder::Status;
 
 android::AAudioService::AAudioService()
     : BnAAudioService(),
       mAdapter(this) {
     // TODO consider using geteuid()
-    // TODO b/182392769: use identity util
-    mAudioClient.identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
-    mAudioClient.identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
-    mAudioClient.identity.packageName = std::nullopt;
-    mAudioClient.identity.attributionTag = std::nullopt;
+    // TODO b/182392769: use attribution source util
+    mAudioClient.attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+    mAudioClient.attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
+    mAudioClient.attributionSource.packageName = std::nullopt;
+    mAudioClient.attributionSource.attributionTag = std::nullopt;
     AAudioClientTracker::getInstance().setAAudioService(this);
 }
 
@@ -115,13 +115,14 @@
     aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
 
     // Enforce limit on client processes.
-    Identity callingIdentity = request.getIdentity();
+    AttributionSourceState attributionSource = request.getAttributionSource();
     pid_t pid = IPCThreadState::self()->getCallingPid();
-    callingIdentity.pid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
+    attributionSource.pid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
         legacy2aidl_pid_t_int32_t(pid));
-    callingIdentity.uid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
+    attributionSource.uid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
         legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
-    if (callingIdentity.pid != mAudioClient.identity.pid) {
+    attributionSource.token = sp<BBinder>::make();
+    if (attributionSource.pid != mAudioClient.attributionSource.pid) {
         int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
         if (count >= MAX_STREAMS_PER_PROCESS) {
             ALOGE("openStream(): exceeded max streams per process %d >= %d",
@@ -280,8 +281,8 @@
 }
 
 bool AAudioService::isCallerInService() {
-    pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAudioClient.identity.pid));
-    uid_t clientUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAudioClient.identity.uid));
+    pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAudioClient.attributionSource.pid));
+    uid_t clientUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAudioClient.attributionSource.uid));
     return clientPid == IPCThreadState::self()->getCallingPid() &&
         clientUid == IPCThreadState::self()->getCallingUid();
 }
@@ -307,7 +308,7 @@
         const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
         const uid_t ownerUserId = serviceStream->getOwnerUserId();
         const uid_t clientUid = VALUE_OR_FATAL(
-            aidl2legacy_int32_t_uid_t(mAudioClient.identity.uid));
+            aidl2legacy_int32_t_uid_t(mAudioClient.attributionSource.uid));
         bool callerOwnsIt = callingUserId == ownerUserId;
         bool serverCalling = callingUserId == clientUid;
         bool serverOwnsIt = ownerUserId == clientUid;
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index b4efd1a..a08098c 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -71,11 +71,11 @@
 aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
     aaudio_result_t result = AAUDIO_OK;
     copyFrom(request.getConstantConfiguration());
-    mMmapClient.identity = request.getIdentity();
-    // TODO b/182392769: use identity util
-    mMmapClient.identity.uid = VALUE_OR_FATAL(
+    mMmapClient.attributionSource = request.getAttributionSource();
+    // TODO b/182392769: use attribution source util
+    mMmapClient.attributionSource.uid = VALUE_OR_FATAL(
         legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
-    mMmapClient.identity.pid = VALUE_OR_FATAL(
+    mMmapClient.attributionSource.pid = VALUE_OR_FATAL(
         legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
 
     audio_format_t audioFormat = getFormat();
@@ -165,8 +165,8 @@
                                                           this, // callback
                                                           mMmapStream,
                                                           &mPortHandle);
-    ALOGD("%s() mMapClient.identity = %s => portHandle = %d\n",
-          __func__, mMmapClient.identity.toString().c_str(), mPortHandle);
+    ALOGD("%s() mMapClient.attributionSource = %s => portHandle = %d\n",
+          __func__, mMmapClient.attributionSource.toString().c_str(), mPortHandle);
     if (status != OK) {
         // This can happen if the resource is busy or the config does
         // not match the hardware.
@@ -216,7 +216,7 @@
         // Exclusive mode can only be used by the service because the FD cannot be shared.
         int32_t audioServiceUid =
             VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
-        if ((mMmapClient.identity.uid != audioServiceUid) &&
+        if ((mMmapClient.attributionSource.uid != audioServiceUid) &&
             getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
             ALOGW("%s() - exclusive FD cannot be used by client", __func__);
             result = AAUDIO_ERROR_UNAVAILABLE;
@@ -237,6 +237,12 @@
         result = AAUDIO_ERROR_INTERNAL;
         goto error;
     }
+    // Call to HAL to make sure the transport FD was able to be closed by binder.
+    // This is a tricky workaround for a problem in Binder.
+    // TODO:[b/192048842] When that problem is fixed we may be able to remove or change this code.
+    struct audio_mmap_position position;
+    mMmapStream->getMmapPosition(&position);
+
     mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
     setFormat(config.format);
     setSampleRate(config.sample_rate);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index dbacd75..34ddd4d 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -39,7 +39,7 @@
 using namespace android;  // TODO just import names needed
 using namespace aaudio;   // TODO just import names needed
 
-using media::permission::Identity;
+using content::AttributionSourceState;
 
 /**
  * Base class for streams in the service.
@@ -50,7 +50,7 @@
         : mTimestampThread("AATime")
         , mAtomicStreamTimestamp()
         , mAudioService(audioService) {
-    mMmapClient.identity = Identity();
+    mMmapClient.attributionSource = AttributionSourceState();
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
@@ -81,7 +81,7 @@
 
     result << "    0x" << std::setfill('0') << std::setw(8) << std::hex << mHandle
            << std::dec << std::setfill(' ') ;
-    result << std::setw(6) << mMmapClient.identity.uid;
+    result << std::setw(6) << mMmapClient.attributionSource.uid;
     result << std::setw(7) << mClientHandle;
     result << std::setw(4) << (isRunning() ? "yes" : " no");
     result << std::setw(6) << getState();
@@ -127,11 +127,11 @@
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
     aaudio_result_t result = AAUDIO_OK;
 
-    mMmapClient.identity = request.getIdentity();
-    // TODO b/182392769: use identity util
-    mMmapClient.identity.uid = VALUE_OR_FATAL(
+    mMmapClient.attributionSource = request.getAttributionSource();
+    // TODO b/182392769: use attribution source util
+    mMmapClient.attributionSource.uid = VALUE_OR_FATAL(
         legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
-    mMmapClient.identity.pid = VALUE_OR_FATAL(
+    mMmapClient.attributionSource.pid = VALUE_OR_FATAL(
         legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
 
     // Limit scope of lock to avoid recursive lock in close().
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index c42df0f..976996d 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -160,11 +160,13 @@
     }
 
     uid_t getOwnerUserId() const {
-        return VALUE_OR_FATAL(android::aidl2legacy_int32_t_uid_t(mMmapClient.identity.uid));
+        return VALUE_OR_FATAL(android::aidl2legacy_int32_t_uid_t(
+                mMmapClient.attributionSource.uid));
     }
 
     pid_t getOwnerProcessId() const {
-        return VALUE_OR_FATAL(android::aidl2legacy_int32_t_pid_t(mMmapClient.identity.pid));
+        return VALUE_OR_FATAL(android::aidl2legacy_int32_t_pid_t(
+                mMmapClient.attributionSource.pid));
     }
 
     aaudio_handle_t getHandle() const {
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index a419dd5..4c58040 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -66,13 +66,13 @@
         "liblog",
         "libutils",
         "aaudio-aidl-cpp",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
     ],
 
     export_shared_lib_headers: [
         "libaaudio_internal",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
     ],
 
     header_libs: [
diff --git a/services/oboeservice/fuzzer/Android.bp b/services/oboeservice/fuzzer/Android.bp
index f4e8a81..605ac01 100644
--- a/services/oboeservice/fuzzer/Android.bp
+++ b/services/oboeservice/fuzzer/Android.bp
@@ -46,7 +46,7 @@
         "liblog",
         "libutils",
         "aaudio-aidl-cpp",
-        "media_permission-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
     ],
     static_libs: [
diff --git a/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp b/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
index 8e508d3..4bc661c 100644
--- a/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
+++ b/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
@@ -23,7 +23,7 @@
 #include <AAudioService.h>
 #include <aaudio/AAudio.h>
 #include "aaudio/BnAAudioClient.h"
-#include <android/media/permission/Identity.h>
+#include <android/content/AttributionSourceState.h>
 
 #define UNUSED_PARAM __attribute__((unused))
 
@@ -295,11 +295,12 @@
             ? fdp.ConsumeIntegral<int32_t>()
             : kAAudioFormats[fdp.ConsumeIntegralInRange<int32_t>(0, kNumAAudioFormats - 1)]));
 
-    // TODO b/182392769: use identity util
-    media::permission::Identity identity;
-    identity.uid = getuid();
-    identity.pid = getpid();
-    request.setIdentity(identity);
+    // TODO b/182392769: use attribution source util
+    android::content::AttributionSourceState attributionSource;
+    attributionSource.uid = getuid();
+    attributionSource.pid = getpid();
+    attributionSource.token = sp<BBinder>::make();
+    request.setAttributionSource(attributionSource);
     request.setInService(fdp.ConsumeBool());
 
     request.getConfiguration().setDeviceId(fdp.ConsumeIntegral<int32_t>());
diff --git a/services/tuner/Android.bp b/services/tuner/Android.bp
index df2b4a3..cd11c88 100644
--- a/services/tuner/Android.bp
+++ b/services/tuner/Android.bp
@@ -32,8 +32,8 @@
         ":tv_tuner_aidl",
     ],
     imports: [
-        "android.hardware.common",
-        "android.hardware.common.fmq",
+        "android.hardware.common-V2",
+        "android.hardware.common.fmq-V1",
     ],
 
     backend: {
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 77e1c40..5b4129a 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -445,90 +445,118 @@
     TunerFrontendCapabilities caps;
     switch (halInfo.type) {
         case FrontendType::ANALOG: {
-            TunerFrontendAnalogCapabilities analogCaps{
-                .typeCap = (int)halInfo.frontendCaps.analogCaps().typeCap,
-                .sifStandardCap = (int)halInfo.frontendCaps.analogCaps().sifStandardCap,
-            };
-            caps.set<TunerFrontendCapabilities::analogCaps>(analogCaps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendAnalogCapabilities analogCaps{
+                    .typeCap = (int)halInfo.frontendCaps.analogCaps().typeCap,
+                    .sifStandardCap = (int)halInfo.frontendCaps.analogCaps().sifStandardCap,
+                };
+                caps.set<TunerFrontendCapabilities::analogCaps>(analogCaps);
+            }
             break;
         }
         case FrontendType::ATSC: {
-            TunerFrontendAtscCapabilities atscCaps{
-                .modulationCap = (int)halInfo.frontendCaps.atscCaps().modulationCap,
-            };
-            caps.set<TunerFrontendCapabilities::atscCaps>(atscCaps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atscCaps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendAtscCapabilities atscCaps{
+                    .modulationCap = (int)halInfo.frontendCaps.atscCaps().modulationCap,
+                };
+                caps.set<TunerFrontendCapabilities::atscCaps>(atscCaps);
+            }
             break;
         }
         case FrontendType::ATSC3: {
-            TunerFrontendAtsc3Capabilities atsc3Caps{
-                .bandwidthCap = (int)halInfo.frontendCaps.atsc3Caps().bandwidthCap,
-                .modulationCap = (int)halInfo.frontendCaps.atsc3Caps().modulationCap,
-                .timeInterleaveModeCap =
-                        (int)halInfo.frontendCaps.atsc3Caps().timeInterleaveModeCap,
-                .codeRateCap = (int)halInfo.frontendCaps.atsc3Caps().codeRateCap,
-                .demodOutputFormatCap = (int)halInfo.frontendCaps.atsc3Caps().demodOutputFormatCap,
-                .fecCap = (int)halInfo.frontendCaps.atsc3Caps().fecCap,
-            };
-            caps.set<TunerFrontendCapabilities::atsc3Caps>(atsc3Caps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atsc3Caps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendAtsc3Capabilities atsc3Caps{
+                    .bandwidthCap = (int)halInfo.frontendCaps.atsc3Caps().bandwidthCap,
+                    .modulationCap = (int)halInfo.frontendCaps.atsc3Caps().modulationCap,
+                    .timeInterleaveModeCap =
+                            (int)halInfo.frontendCaps.atsc3Caps().timeInterleaveModeCap,
+                    .codeRateCap = (int)halInfo.frontendCaps.atsc3Caps().codeRateCap,
+                    .demodOutputFormatCap
+                        = (int)halInfo.frontendCaps.atsc3Caps().demodOutputFormatCap,
+                    .fecCap = (int)halInfo.frontendCaps.atsc3Caps().fecCap,
+                };
+                caps.set<TunerFrontendCapabilities::atsc3Caps>(atsc3Caps);
+            }
             break;
         }
         case FrontendType::DVBC: {
-            TunerFrontendCableCapabilities cableCaps{
-                .modulationCap = (int)halInfo.frontendCaps.dvbcCaps().modulationCap,
-                .codeRateCap = (int64_t)halInfo.frontendCaps.dvbcCaps().fecCap,
-                .annexCap = (int)halInfo.frontendCaps.dvbcCaps().annexCap,
-            };
-            caps.set<TunerFrontendCapabilities::cableCaps>(cableCaps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbcCaps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendCableCapabilities cableCaps{
+                    .modulationCap = (int)halInfo.frontendCaps.dvbcCaps().modulationCap,
+                    .codeRateCap = (int64_t)halInfo.frontendCaps.dvbcCaps().fecCap,
+                    .annexCap = (int)halInfo.frontendCaps.dvbcCaps().annexCap,
+                };
+                caps.set<TunerFrontendCapabilities::cableCaps>(cableCaps);
+            }
             break;
         }
         case FrontendType::DVBS: {
-            TunerFrontendDvbsCapabilities dvbsCaps{
-                .modulationCap = (int)halInfo.frontendCaps.dvbsCaps().modulationCap,
-                .codeRateCap = (long)halInfo.frontendCaps.dvbsCaps().innerfecCap,
-                .standard = (int)halInfo.frontendCaps.dvbsCaps().standard,
-            };
-            caps.set<TunerFrontendCapabilities::dvbsCaps>(dvbsCaps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbsCaps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendDvbsCapabilities dvbsCaps{
+                    .modulationCap = (int)halInfo.frontendCaps.dvbsCaps().modulationCap,
+                    .codeRateCap = (long)halInfo.frontendCaps.dvbsCaps().innerfecCap,
+                    .standard = (int)halInfo.frontendCaps.dvbsCaps().standard,
+                };
+                caps.set<TunerFrontendCapabilities::dvbsCaps>(dvbsCaps);
+            }
             break;
         }
         case FrontendType::DVBT: {
-            TunerFrontendDvbtCapabilities dvbtCaps{
-                .transmissionModeCap = (int)halInfo.frontendCaps.dvbtCaps().transmissionModeCap,
-                .bandwidthCap = (int)halInfo.frontendCaps.dvbtCaps().bandwidthCap,
-                .constellationCap = (int)halInfo.frontendCaps.dvbtCaps().constellationCap,
-                .codeRateCap = (int)halInfo.frontendCaps.dvbtCaps().coderateCap,
-                .hierarchyCap = (int)halInfo.frontendCaps.dvbtCaps().hierarchyCap,
-                .guardIntervalCap = (int)halInfo.frontendCaps.dvbtCaps().guardIntervalCap,
-                .isT2Supported = (bool)halInfo.frontendCaps.dvbtCaps().isT2Supported,
-                .isMisoSupported = (bool)halInfo.frontendCaps.dvbtCaps().isMisoSupported,
-            };
-            caps.set<TunerFrontendCapabilities::dvbtCaps>(dvbtCaps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbtCaps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendDvbtCapabilities dvbtCaps{
+                    .transmissionModeCap = (int)halInfo.frontendCaps.dvbtCaps().transmissionModeCap,
+                    .bandwidthCap = (int)halInfo.frontendCaps.dvbtCaps().bandwidthCap,
+                    .constellationCap = (int)halInfo.frontendCaps.dvbtCaps().constellationCap,
+                    .codeRateCap = (int)halInfo.frontendCaps.dvbtCaps().coderateCap,
+                    .hierarchyCap = (int)halInfo.frontendCaps.dvbtCaps().hierarchyCap,
+                    .guardIntervalCap = (int)halInfo.frontendCaps.dvbtCaps().guardIntervalCap,
+                    .isT2Supported = (bool)halInfo.frontendCaps.dvbtCaps().isT2Supported,
+                    .isMisoSupported = (bool)halInfo.frontendCaps.dvbtCaps().isMisoSupported,
+                };
+                caps.set<TunerFrontendCapabilities::dvbtCaps>(dvbtCaps);
+            }
             break;
         }
         case FrontendType::ISDBS: {
-            TunerFrontendIsdbsCapabilities isdbsCaps{
-                .modulationCap = (int)halInfo.frontendCaps.isdbsCaps().modulationCap,
-                .codeRateCap = (int)halInfo.frontendCaps.isdbsCaps().coderateCap,
-            };
-            caps.set<TunerFrontendCapabilities::isdbsCaps>(isdbsCaps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbsCaps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendIsdbsCapabilities isdbsCaps{
+                    .modulationCap = (int)halInfo.frontendCaps.isdbsCaps().modulationCap,
+                    .codeRateCap = (int)halInfo.frontendCaps.isdbsCaps().coderateCap,
+                };
+                caps.set<TunerFrontendCapabilities::isdbsCaps>(isdbsCaps);
+            }
             break;
         }
         case FrontendType::ISDBS3: {
-            TunerFrontendIsdbs3Capabilities isdbs3Caps{
-                .modulationCap = (int)halInfo.frontendCaps.isdbs3Caps().modulationCap,
-                .codeRateCap = (int)halInfo.frontendCaps.isdbs3Caps().coderateCap,
-            };
-            caps.set<TunerFrontendCapabilities::isdbs3Caps>(isdbs3Caps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbs3Caps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendIsdbs3Capabilities isdbs3Caps{
+                    .modulationCap = (int)halInfo.frontendCaps.isdbs3Caps().modulationCap,
+                    .codeRateCap = (int)halInfo.frontendCaps.isdbs3Caps().coderateCap,
+                };
+                caps.set<TunerFrontendCapabilities::isdbs3Caps>(isdbs3Caps);
+            }
             break;
         }
         case FrontendType::ISDBT: {
-            TunerFrontendIsdbtCapabilities isdbtCaps{
-                .modeCap = (int)halInfo.frontendCaps.isdbtCaps().modeCap,
-                .bandwidthCap = (int)halInfo.frontendCaps.isdbtCaps().bandwidthCap,
-                .modulationCap = (int)halInfo.frontendCaps.isdbtCaps().modulationCap,
-                .codeRateCap = (int)halInfo.frontendCaps.isdbtCaps().coderateCap,
-                .guardIntervalCap = (int)halInfo.frontendCaps.isdbtCaps().guardIntervalCap,
-            };
-            caps.set<TunerFrontendCapabilities::isdbtCaps>(isdbtCaps);
+            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbtCaps
+                    == halInfo.frontendCaps.getDiscriminator()) {
+                TunerFrontendIsdbtCapabilities isdbtCaps{
+                    .modeCap = (int)halInfo.frontendCaps.isdbtCaps().modeCap,
+                    .bandwidthCap = (int)halInfo.frontendCaps.isdbtCaps().bandwidthCap,
+                    .modulationCap = (int)halInfo.frontendCaps.isdbtCaps().modulationCap,
+                    .codeRateCap = (int)halInfo.frontendCaps.isdbtCaps().coderateCap,
+                    .guardIntervalCap = (int)halInfo.frontendCaps.isdbtCaps().guardIntervalCap,
+                };
+                caps.set<TunerFrontendCapabilities::isdbtCaps>(isdbtCaps);
+            }
             break;
         }
         default: