[automerger skipped] Merge changes from topic "24d1_effect_chain_improvement" into 24D1-dev am: 99fbd7c238 -s ours

am skip reason: Merged-In I9b6d6c350106b233d3ea856bfa4df81ce35a54ec with SHA-1 7eb61b87a3 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/av/+/26683329

Change-Id: I41c5d740ef0905554934dbc0f1ab4944397e1ee9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 73b153c..2d1af32 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -25,6 +25,7 @@
 #include <binder/Parcel.h>
 #include <gui/view/Surface.h>
 #include <system/camera_metadata.h>
+#include <system/graphics.h>
 #include <utils/String8.h>
 
 
@@ -102,6 +103,25 @@
     return mUseReadoutTimestamp;
 }
 
+int OutputConfiguration::getFormat() const {
+    return mFormat;
+}
+
+int OutputConfiguration::getDataspace() const {
+    return mDataspace;
+}
+
+int64_t OutputConfiguration::getUsage() const {
+    return mUsage;
+}
+
+bool OutputConfiguration::isComplete() const {
+    return !((mSurfaceType == SURFACE_TYPE_MEDIA_RECORDER ||
+             mSurfaceType == SURFACE_TYPE_MEDIA_CODEC ||
+             mSurfaceType == SURFACE_TYPE_IMAGE_READER) &&
+             mGbps.empty());
+}
+
 OutputConfiguration::OutputConfiguration() :
         mRotation(INVALID_ROTATION),
         mSurfaceSetID(INVALID_SET_ID),
@@ -116,7 +136,10 @@
         mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
         mTimestampBase(TIMESTAMP_BASE_DEFAULT),
         mMirrorMode(MIRROR_MODE_AUTO),
-        mUseReadoutTimestamp(false) {
+        mUseReadoutTimestamp(false),
+        mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+        mDataspace(0),
+        mUsage(0) {
 }
 
 OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
@@ -234,6 +257,24 @@
         return err;
     }
 
+    int format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    if ((err = parcel->readInt32(&format)) != OK) {
+        ALOGE("%s: Failed to read format from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int dataspace = 0;
+    if ((err = parcel->readInt32(&dataspace)) != OK) {
+        ALOGE("%s: Failed to read dataspace from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int64_t usage = 0;
+    if ((err = parcel->readInt64(&usage)) != OK) {
+        ALOGE("%s: Failed to read usage flag from parcel", __FUNCTION__);
+        return err;
+    }
+
     mRotation = rotation;
     mSurfaceSetID = setID;
     mSurfaceType = surfaceType;
@@ -256,13 +297,17 @@
     mSensorPixelModesUsed = std::move(sensorPixelModesUsed);
     mDynamicRangeProfile = dynamicProfile;
     mColorSpace = colorSpace;
+    mFormat = format;
+    mDataspace = dataspace;
+    mUsage = usage;
 
     ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d,"
           " physicalCameraId = %s, isMultiResolution = %d, streamUseCase = %" PRId64
-          ", timestampBase = %d, mirrorMode = %d, useReadoutTimestamp = %d",
+          ", timestampBase = %d, mirrorMode = %d, useReadoutTimestamp = %d, format = %d, "
+          "dataspace = %d, usage = %" PRId64,
           __FUNCTION__, mRotation, mSurfaceSetID, mSurfaceType,
           mPhysicalCameraId.c_str(), mIsMultiResolution, mStreamUseCase, timestampBase,
-          mMirrorMode, mUseReadoutTimestamp);
+          mMirrorMode, mUseReadoutTimestamp, mFormat, mDataspace, mUsage);
 
     return err;
 }
@@ -283,6 +328,9 @@
     mTimestampBase = TIMESTAMP_BASE_DEFAULT;
     mMirrorMode = MIRROR_MODE_AUTO;
     mUseReadoutTimestamp = false;
+    mFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    mDataspace = 0;
+    mUsage = 0;
 }
 
 OutputConfiguration::OutputConfiguration(
@@ -296,7 +344,9 @@
     mColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
     mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
     mTimestampBase(TIMESTAMP_BASE_DEFAULT),
-    mMirrorMode(MIRROR_MODE_AUTO), mUseReadoutTimestamp(false) { }
+    mMirrorMode(MIRROR_MODE_AUTO), mUseReadoutTimestamp(false),
+    mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), mDataspace(0),
+    mUsage(0) { }
 
 status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
 
@@ -362,6 +412,15 @@
     err = parcel->writeInt32(mUseReadoutTimestamp ? 1 : 0);
     if (err != OK) return err;
 
+    err = parcel->writeInt32(mFormat);
+    if (err != OK) return err;
+
+    err = parcel->writeInt32(mDataspace);
+    if (err != OK) return err;
+
+    err = parcel->writeInt64(mUsage);
+    if (err != OK) return err;
+
     return OK;
 }
 
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 1f50570..0dd5df2 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -4,6 +4,7 @@
 flag {
      namespace: "camera_platform"
      name: "camera_hsum_permission"
+     is_exported: true
      description: "Camera access by headless system user"
      bug: "273539631"
 }
@@ -11,6 +12,7 @@
 flag {
      namespace: "camera_platform"
      name: "concert_mode"
+     is_exported: true
      description: "Introduces a new concert mode camera extension type"
      bug: "297083874"
 }
@@ -18,6 +20,7 @@
 flag {
      namespace: "camera_platform"
      name: "feature_combination_query"
+     is_exported: true
      description: "Query feature combination support and session specific characteristics"
      bug: "309627704"
 }
@@ -39,6 +42,7 @@
 flag {
      namespace: "camera_platform"
      name: "camera_manual_flash_strength_control"
+     is_exported: true
      description: "Flash brightness level control in manual flash mode"
      bug: "238348881"
 }
@@ -74,6 +78,7 @@
 flag {
      namespace: "camera_platform"
      name: "camera_ae_mode_low_light_boost"
+     is_exported: true
      description: "An AE mode that enables increased brightening in low light scenes"
      bug: "312803148"
 }
@@ -95,6 +100,7 @@
 flag {
      namespace: "camera_platform"
      name: "camera_extensions_characteristics_get"
+     is_exported: true
      description: "Enable get extension specific camera characteristics API"
      bug: "280649914"
 }
@@ -116,6 +122,7 @@
 flag {
      namespace: "camera_platform"
      name: "camera_device_setup"
+     is_exported: true
      description: "Create an intermediate Camera Device class for limited CameraDevice access."
      bug: "320741775"
 }
@@ -123,13 +130,53 @@
 flag {
      namespace: "camera_platform"
      name: "camera_privacy_allowlist"
+     is_exported: true
      description: "Allowlisting to exempt safety-relevant cameras from privacy control for automotive devices"
      bug: "282814430"
 }
 
 flag {
      namespace: "camera_platform"
+     name: "surface_ipc"
+     description: "Optimize Surface binder IPC"
+     bug: "323292530"
+     metadata {
+       purpose: PURPOSE_BUGFIX
+     }
+}
+
+flag {
+     namespace: "camera_platform"
      name: "extension_10_bit"
+     is_exported: true
      description: "Enables 10-bit support in the camera extensions."
      bug: "316375635"
 }
+
+flag {
+     namespace: "camera_platform"
+     name: "surface_leak_fix"
+     description: "Address Surface release leaks in CaptureRequest"
+     bug: "324071855"
+     metadata {
+       purpose: PURPOSE_BUGFIX
+     }
+}
+
+flag {
+     namespace: "camera_platform"
+     name: "concert_mode_api"
+     description: "Covers the eyes free videography public facing API"
+     bug: "297083874"
+}
+
+
+flag {
+     namespace: "camera_platform"
+     name: "cache_permission_services"
+     description: "Cache IPermissionController and IPermissionChecker in CameraService to reduce query latency."
+     bug: "326139956"
+     metadata {
+       purpose: PURPOSE_BUGFIX
+     }
+}
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index e307653..63fa2b0 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -5,5 +5,6 @@
     ioprio rt 4
     task_profiles CameraServiceCapacity MaxPerformance
     rlimit rtprio 10 10
+    capabilities SYS_NICE
     onrestart class_restart cameraWatchdog
     interface aidl android.frameworks.cameraservice.service.ICameraService/default
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 3f74b4a..83ce39d 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -35,10 +35,13 @@
 
     static const int INVALID_ROTATION;
     static const int INVALID_SET_ID;
-    enum SurfaceType{
+    enum SurfaceType {
         SURFACE_TYPE_UNKNOWN = -1,
         SURFACE_TYPE_SURFACE_VIEW = 0,
-        SURFACE_TYPE_SURFACE_TEXTURE = 1
+        SURFACE_TYPE_SURFACE_TEXTURE = 1,
+        SURFACE_TYPE_MEDIA_RECORDER = 2,
+        SURFACE_TYPE_MEDIA_CODEC = 3,
+        SURFACE_TYPE_IMAGE_READER = 4
     };
     enum TimestampBaseType {
         TIMESTAMP_BASE_DEFAULT = 0,
@@ -71,6 +74,10 @@
     int                        getTimestampBase() const;
     int                        getMirrorMode() const;
     bool                       useReadoutTimestamp() const;
+    int                        getFormat() const;
+    int                        getDataspace() const;
+    int64_t                    getUsage() const;
+    bool                       isComplete() const;
 
     // set of sensor pixel mode resolutions allowed {MAX_RESOLUTION, DEFAULT_MODE};
     const std::vector<int32_t>&            getSensorPixelModesUsed() const;
@@ -98,7 +105,7 @@
     OutputConfiguration(const std::vector<sp<IGraphicBufferProducer>>& gbps,
                         int rotation, const std::string& physicalCameraId,
                         int surfaceSetID = INVALID_SET_ID,
-                        int surfaceType = OutputConfiguration::SURFACE_TYPE_UNKNOWN, int width = 0,
+                        int surfaceType = SURFACE_TYPE_UNKNOWN, int width = 0,
                         int height = 0, bool isShared = false);
 
     bool operator == (const OutputConfiguration& other) const {
@@ -118,7 +125,10 @@
                 mStreamUseCase == other.mStreamUseCase &&
                 mTimestampBase == other.mTimestampBase &&
                 mMirrorMode == other.mMirrorMode &&
-                mUseReadoutTimestamp == other.mUseReadoutTimestamp);
+                mUseReadoutTimestamp == other.mUseReadoutTimestamp &&
+                mFormat == other.mFormat &&
+                mDataspace == other.mDataspace &&
+                mUsage == other.mUsage);
     }
     bool operator != (const OutputConfiguration& other) const {
         return !(*this == other);
@@ -173,6 +183,15 @@
         if (mUseReadoutTimestamp != other.mUseReadoutTimestamp) {
             return mUseReadoutTimestamp < other.mUseReadoutTimestamp;
         }
+        if (mFormat != other.mFormat) {
+            return mFormat < other.mFormat;
+        }
+        if (mDataspace != other.mDataspace) {
+            return mDataspace < other.mDataspace;
+        }
+        if (mUsage != other.mUsage) {
+            return mUsage < other.mUsage;
+        }
         return gbpsLessThan(other);
     }
 
@@ -203,6 +222,9 @@
     int                        mTimestampBase;
     int                        mMirrorMode;
     bool                       mUseReadoutTimestamp;
+    int                        mFormat;
+    int                        mDataspace;
+    int64_t                    mUsage;
 };
 } // namespace params
 } // namespace camera2
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
index 7d3a53e..a2dfaee 100644
--- a/camera/ndk/NdkCameraMetadata.cpp
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -121,6 +121,18 @@
 }
 
 EXPORT
+camera_status_t ACameraMetadata_getTagFromName(
+        const ACameraMetadata* acm, const char* name, uint32_t* tag) {
+    ATRACE_CALL();
+    if (acm == nullptr || name == nullptr || tag == nullptr) {
+        ALOGE("%s: invalid argument! metadata %p, name %p, tag %p",
+               __FUNCTION__, acm, name, tag);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return acm->getTagFromName(name, tag);
+}
+
+EXPORT
 ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) {
     ATRACE_CALL();
     if (src == nullptr) {
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index b6b8012..69b30f7 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "ACameraMetadata"
 
 #include "ACameraMetadata.h"
+
+#include <camera_metadata_hidden.h>
 #include <utils/Vector.h>
 #include <system/graphics.h>
 #include <media/NdkImage.h>
@@ -85,6 +87,19 @@
         filterDurations(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
     }
     // TODO: filter request/result keys
+    const CameraMetadata& metadata = *mData;
+    const camera_metadata_t *rawMetadata = metadata.getAndLock();
+    metadata_vendor_id_t vendorTagId = get_camera_metadata_vendor_id(rawMetadata);
+    metadata.unlock(rawMetadata);
+    sp<VendorTagDescriptorCache> vtCache = VendorTagDescriptorCache::getGlobalVendorTagCache();
+    if (vtCache == nullptr) {
+        ALOGE("%s: error vendor tag descriptor cache is not initialized", __FUNCTION__);
+        return;
+    }
+    vtCache->getVendorTagDescriptor(vendorTagId, &mVTags);
+    if (mVTags == nullptr) {
+        ALOGE("%s: error retrieving vendor tag descriptor", __FUNCTION__);
+    }
 }
 
 bool
@@ -473,6 +488,13 @@
     return (*mData);
 }
 
+camera_status_t
+ACameraMetadata::getTagFromName(const char *name, uint32_t *tag) const {
+    Mutex::Autolock _l(mLock);
+    status_t status = CameraMetadata::getTagFromName(name, mVTags.get(), tag);
+    return status == OK ? ACAMERA_OK : ACAMERA_ERROR_METADATA_NOT_FOUND;
+}
+
 bool
 ACameraMetadata::isLogicalMultiCamera(size_t* count, const char*const** physicalCameraIds) const {
     if (mType != ACM_CHARACTERISTICS) {
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index 084a60b..e89e620 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -27,9 +27,17 @@
 
 #ifdef __ANDROID_VNDK__
 #include <CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/common/VendorTag.h>
+#include <aidl/android/frameworks/cameraservice/common/VendorTagSection.h>
+#include <aidl/android/frameworks/cameraservice/common/ProviderIdAndVendorTagSections.h>
+#include <VendorTagDescriptor.h>
 using CameraMetadata = android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using ::aidl::android::frameworks::cameraservice::common::ProviderIdAndVendorTagSections;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
 #else
 #include <camera/CameraMetadata.h>
+#include <camera/VendorTagDescriptor.h>
 #endif
 
 #include <camera/NdkCameraMetadata.h>
@@ -73,6 +81,8 @@
 
     camera_status_t getTags(/*out*/int32_t* numTags,
                             /*out*/const uint32_t** tags) const;
+    camera_status_t
+    getTagFromName(const char *name, uint32_t *tag) const;
 
     const CameraMetadata& getInternalData() const;
     bool isLogicalMultiCamera(size_t* count, const char* const** physicalCameraIds) const;
@@ -134,6 +144,7 @@
 
     std::vector<const char*> mStaticPhysicalCameraIds;
     std::vector<String8> mStaticPhysicalCameraIdValues;
+    sp<VendorTagDescriptor> mVTags = nullptr;
 };
 
 #endif // _ACAMERA_METADATA_H
diff --git a/camera/ndk/include/camera/NdkCameraMetadata.h b/camera/ndk/include/camera/NdkCameraMetadata.h
index cf29736..237d07b 100644
--- a/camera/ndk/include/camera/NdkCameraMetadata.h
+++ b/camera/ndk/include/camera/NdkCameraMetadata.h
@@ -221,6 +221,24 @@
         /*out*/int32_t* numEntries, /*out*/const uint32_t** tags) __INTRODUCED_IN(24);
 
 /**
+ * Look up tag ID value for device-specific custom tags that are usable only
+ * for the particular device, by name. The name and type of the tag need to be
+ * discovered from some other source, such as the manufacturer. The ID value is
+ * stable during the lifetime of an application, but should be queried again after
+ * process restarts. This method can also be used to query tag values using the names
+ * for public tags which exist in the Java API, however it is just simpler and faster to
+ * use the values of the tags which exist in the ndk.
+ * @param metadata The {@link ACameraMetadata} of to query the tag value from.
+ * @param name The name of the tag being queried.
+ * @param tag The output tag assigned by this method.
+ *
+ * @return ACAMERA_OK only if the function call was successful.
+ */
+
+camera_status_t
+ACameraMetadata_getTagFromName(const ACameraMetadata* metadata, const char *name, uint32_t *tag)  __INTRODUCED_IN(35);
+
+/**
  * Create a copy of input {@link ACameraMetadata}.
  *
  * <p>The returned ACameraMetadata must be freed by the application by {@link ACameraMetadata_free}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 1ed17a3..6c58bcf 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2149,7 +2149,7 @@
      * </ul>
      */
     ACAMERA_CONTROL_SETTINGS_OVERRIDE =                         // int32 (acamera_metadata_enum_android_control_settings_override_t)
-            ACAMERA_CONTROL_START + 49,
+            ACAMERA_CONTROL_START + 52,
     /**
      * <p>List of available settings overrides supported by the camera device that can
      * be used to speed up certain controls.</p>
@@ -2175,7 +2175,7 @@
      * @see ACAMERA_CONTROL_SETTINGS_OVERRIDE
      */
     ACAMERA_CONTROL_AVAILABLE_SETTINGS_OVERRIDES =              // int32[n]
-            ACAMERA_CONTROL_START + 50,
+            ACAMERA_CONTROL_START + 53,
     /**
      * <p>Automatic crop, pan and zoom to keep objects in the center of the frame.</p>
      *
@@ -2202,7 +2202,7 @@
      * @see ACAMERA_SCALER_CROP_REGION
      */
     ACAMERA_CONTROL_AUTOFRAMING =                               // byte (acamera_metadata_enum_android_control_autoframing_t)
-            ACAMERA_CONTROL_START + 52,
+            ACAMERA_CONTROL_START + 55,
     /**
      * <p>Whether the camera device supports ACAMERA_CONTROL_AUTOFRAMING.</p>
      *
@@ -2218,7 +2218,7 @@
      * <p>Will be <code>false</code> if auto-framing is not available.</p>
      */
     ACAMERA_CONTROL_AUTOFRAMING_AVAILABLE =                     // byte (acamera_metadata_enum_android_control_autoframing_available_t)
-            ACAMERA_CONTROL_START + 53,
+            ACAMERA_CONTROL_START + 56,
     /**
      * <p>Current state of auto-framing.</p>
      *
@@ -2245,7 +2245,7 @@
      * @see ACAMERA_CONTROL_AUTOFRAMING_AVAILABLE
      */
     ACAMERA_CONTROL_AUTOFRAMING_STATE =                         // byte (acamera_metadata_enum_android_control_autoframing_state_t)
-            ACAMERA_CONTROL_START + 54,
+            ACAMERA_CONTROL_START + 57,
     /**
      * <p>The operating luminance range of low light boost measured in lux (lx).</p>
      *
@@ -2258,7 +2258,7 @@
      *
      */
     ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE =      // float[2]
-            ACAMERA_CONTROL_START + 55,
+            ACAMERA_CONTROL_START + 58,
     /**
      * <p>Current state of the low light boost AE mode.</p>
      *
@@ -2278,7 +2278,7 @@
      * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
      */
     ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE =                     // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
-            ACAMERA_CONTROL_START + 56,
+            ACAMERA_CONTROL_START + 59,
     ACAMERA_CONTROL_END,
 
     /**
@@ -2688,7 +2688,9 @@
      * upright.</p>
      * <p>Camera devices may either encode this value into the JPEG EXIF header, or
      * rotate the image data to match this orientation. When the image data is rotated,
-     * the thumbnail data will also be rotated.</p>
+     * the thumbnail data will also be rotated. Additionally, in the case where the image data
+     * is rotated, <a href="https://developer.android.com/reference/android/media/Image.html#getWidth">Image#getWidth</a> and <a href="https://developer.android.com/reference/android/media/Image.html#getHeight">Image#getHeight</a>
+     * will not be updated to reflect the height and width of the rotated image.</p>
      * <p>Note that this orientation is relative to the orientation of the camera sensor, given
      * by ACAMERA_SENSOR_ORIENTATION.</p>
      * <p>To translate from the device orientation given by the Android sensor APIs for camera
@@ -4671,7 +4673,7 @@
      * application should leave stream use cases within the session as DEFAULT.</p>
      */
     ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES =                 // int64[n] (acamera_metadata_enum_android_scaler_available_stream_use_cases_t)
-            ACAMERA_SCALER_START + 25,
+            ACAMERA_SCALER_START + 26,
     /**
      * <p>The region of the sensor that corresponds to the RAW read out for this
      * capture when the stream use case of a RAW stream is set to CROPPED_RAW.</p>
@@ -4727,7 +4729,7 @@
      * @see ACAMERA_STATISTICS_HOT_PIXEL_MAP
      */
     ACAMERA_SCALER_RAW_CROP_REGION =                            // int32[4]
-            ACAMERA_SCALER_START + 26,
+            ACAMERA_SCALER_START + 27,
     ACAMERA_SCALER_END,
 
     /**
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 4c54658..7d7868b 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -35,6 +35,7 @@
     ACameraMetadata_copy;
     ACameraMetadata_free;
     ACameraMetadata_getAllTags;
+    ACameraMetadata_getTagFromName; #introduced=35
     ACameraMetadata_getConstEntry;
     ACameraMetadata_isLogicalMultiCamera; # introduced=29
     ACameraMetadata_fromCameraMetadata; # introduced=30
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index a6b20cf..28670b1 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -117,6 +117,7 @@
 static bool gSizeSpecified = false;     // was size explicitly requested?
 static bool gWantInfoScreen = false;    // do we want initial info screen?
 static bool gWantFrameTime = false;     // do we want times on each frame?
+static bool gSecureDisplay = false;     // should we create a secure virtual display?
 static uint32_t gVideoWidth = 0;        // default width+height
 static uint32_t gVideoHeight = 0;
 static uint32_t gBitRate = 20000000;     // 20Mbps
@@ -362,7 +363,7 @@
         const sp<IGraphicBufferProducer>& bufferProducer,
         sp<IBinder>* pDisplayHandle, sp<SurfaceControl>* mirrorRoot) {
     sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
-            String8("ScreenRecorder"), false /*secure*/);
+            String8("ScreenRecorder"), gSecureDisplay);
     SurfaceComposerClient::Transaction t;
     t.setDisplaySurface(dpy, bufferProducer);
     setDisplayProjection(t, dpy, displayState);
@@ -1253,6 +1254,7 @@
         { "persistent-surface", no_argument,        NULL, 'p' },
         { "bframes",            required_argument,  NULL, 'B' },
         { "display-id",         required_argument,  NULL, 'd' },
+        { "capture-secure",     no_argument,        NULL, 'S' },
         { NULL,                 0,                  NULL, 0 }
     };
 
@@ -1372,6 +1374,9 @@
 
             fprintf(stderr, "Invalid physical display ID\n");
             return 2;
+        case 'S':
+            gSecureDisplay = true;
+            break;
         default:
             if (ic != '?') {
                 fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
index 0b0d46a..9a06bd2 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -107,6 +107,17 @@
     installable: false, // installed in APEX
 }
 
+cc_binary {
+    name: "android.hardware.drm-service-lazy.clearkey.apex",
+    stem: "android.hardware.drm-service-lazy.clearkey",
+    defaults: [
+        "aidl_clearkey_service_defaults",
+        "aidl_clearkey_service_defaults-use-static-deps",
+    ],
+    srcs: ["ServiceLazy.cpp"],
+    installable: false, // installed in APEX
+}
+
 phony {
     name: "android.hardware.drm@latest-service.clearkey",
     required: [
@@ -183,17 +194,63 @@
         "android.hardware.drm-service.clearkey.apex.rc",
         "android.hardware.drm-service.clearkey.xml"
     ],
+    overrides: [
+        "android.hardware.drm-service.clearkey",
+    ],
 }
 
 prebuilt_etc {
     name: "android.hardware.drm-service.clearkey.apex.rc",
-    src: "android.hardware.drm-service.clearkey.apex.rc",
+    src: ":gen-android.hardware.drm-service.clearkey.apex.rc",
     installable: false,
 }
 
+genrule {
+    name: "gen-android.hardware.drm-service.clearkey.apex.rc",
+    srcs: ["android.hardware.drm-service.clearkey.rc"],
+    out: ["android.hardware.drm-service.clearkey.apex.rc"],
+    cmd: "sed -E 's%/vendor/bin/%/apex/com.android.hardware.drm.clearkey/bin/%' $(in) > $(out)",
+}
+
 prebuilt_etc {
     name: "android.hardware.drm-service.clearkey.xml",
     src: "android.hardware.drm-service.clearkey.xml",
     sub_dir: "vintf",
     installable: false,
 }
+
+apex {
+    name: "com.android.hardware.drm.clearkey.lazy",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.drm-service-lazy.clearkey.apex",
+    ],
+    prebuilts: [
+        "android.hardware.drm-service-lazy.clearkey.apex.rc",
+        "android.hardware.drm-service.clearkey.xml"
+    ],
+    overrides: [
+        "android.hardware.drm-service.clearkey",
+        "android.hardware.drm-service-lazy.clearkey",
+        "com.android.hardware.drm.clearkey",
+    ],
+}
+
+prebuilt_etc {
+    name: "android.hardware.drm-service-lazy.clearkey.apex.rc",
+    src: ":gen-android.hardware.drm-service-lazy.clearkey.apex.rc",
+    installable: false,
+}
+
+genrule {
+    name: "gen-android.hardware.drm-service-lazy.clearkey.apex.rc",
+    srcs: ["android.hardware.drm-service-lazy.clearkey.rc"],
+    out: ["android.hardware.drm-service-lazy.clearkey.apex.rc"],
+    cmd: "sed -E 's%/vendor/bin/%/apex/com.android.hardware.drm.clearkey/bin/%' $(in) > $(out)",
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.apex.rc b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.apex.rc
deleted file mode 100644
index f4645b3..0000000
--- a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.apex.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service vendor.drm-clearkey-service /apex/com.android.hardware.drm.clearkey/bin/hw/android.hardware.drm-service.clearkey
-    class hal
-    user media
-    group mediadrm drmrpc
-    ioprio rt 4
-    task_profiles ProcessCapacityHigh
-    interface aidl android.hardware.drm.IDrmFactory/clearkey
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index 3092091..a2b6a82 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -14,6 +14,7 @@
 
 flag {
   name: "dynamic_color_aspects"
+  is_exported: true
   namespace: "codec_fwk"
   description: "Feature flag for dynamic color aspect support"
   bug: "297914560"
@@ -21,6 +22,7 @@
 
 flag {
   name: "hlg_editing"
+  is_exported: true
   namespace: "codec_fwk"
   description: "Feature flag for HLG editing support"
   bug: "316397061"
@@ -28,6 +30,7 @@
 
 flag {
   name: "in_process_sw_audio_codec"
+  is_exported: true
   namespace: "codec_fwk"
   description: "Feature flag for in-process software audio codec API"
   bug: "297922713"
@@ -48,7 +51,15 @@
 }
 
 flag {
+  name: "native_capabilites"
+  namespace: "codec_fwk"
+  description: "Feature flag for native codec capabilities"
+  bug: "306023029"
+}
+
+flag {
   name: "null_output_surface"
+  is_exported: true
   namespace: "codec_fwk"
   description: "Feature flag for null output Surface API"
   bug: "297920102"
@@ -63,6 +74,7 @@
 
 flag {
   name: "region_of_interest"
+  is_exported: true
   namespace: "codec_fwk"
   description: "Feature flag for region of interest API"
   bug: "299191092"
@@ -74,3 +86,10 @@
   description: "Feature flag for region of interest support"
   bug: "325549730"
 }
+
+flag {
+  name: "teamfood"
+  namespace: "codec_fwk"
+  description: "Feature flag to track teamfood population"
+  bug: "328770262"
+}
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
index 4d1e5ca..3cc9a1a 100644
--- a/media/aconfig/mediacodec_flags.aconfig
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -7,22 +7,23 @@
 # ******************************************************************
 
 flag {
-  name: "large_audio_frame"
+  name: "aidl_hal"
   namespace: "codec_fwk"
-  description: "Feature flags for large audio frame support"
-  bug: "297219557"
+  description: "Feature flags for enabling AIDL HAL handling"
+  bug: "251850069"
 }
 
 flag {
   name: "codec_importance"
+  is_exported: true
   namespace: "codec_fwk"
   description: "Feature flags for media codec importance"
   bug: "297929011"
 }
 
 flag {
-  name: "aidl_hal"
+  name: "large_audio_frame"
   namespace: "codec_fwk"
-  description: "Feature flags for enabling AIDL HAL handling"
-  bug: "251850069"
+  description: "Feature flags for large audio frame support"
+  bug: "297219557"
 }
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index 6d21e97..ec45e2f 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -6,6 +6,13 @@
 }
 
 aconfig_declarations {
+    name: "com.android.media.audioclient-aconfig",
+    package: "com.android.media.audioclient",
+    container: "system",
+    srcs: ["audioclient.aconfig"],
+}
+
+aconfig_declarations {
     name: "com.android.media.audioserver-aconfig",
     package: "com.android.media.audioserver",
     container: "system",
@@ -53,9 +60,9 @@
     // TODO(b/316909431) native_bridge_supported: true,
     apex_available: [
         "//apex_available:platform",
+        "com.android.btservices",
         "com.android.media",
         "com.android.media.swcodec",
-        "com.android.btservices",
     ],
     min_sdk_version: "29",
 }
@@ -66,6 +73,12 @@
     defaults: ["audio-aconfig-cc-defaults"],
 }
 
+cc_aconfig_library {
+    name: "com.android.media.audioclient-aconfig-cc",
+    aconfig_declarations: "com.android.media.audioclient-aconfig",
+    defaults: ["audio-aconfig-cc-defaults"],
+}
+
 java_aconfig_library {
     name: "com.android.media.audio-aconfig-java",
     aconfig_declarations: "com.android.media.audio-aconfig",
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index cdbadc2..02367dc 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -53,6 +53,15 @@
 }
 
 flag {
+    name: "set_stream_volume_order"
+    namespace: "media_audio"
+    description:
+        "Fix race condition by adjusting the order when"
+        "setStreamVolume is calling into the BT stack"
+    bug: "329202581"
+}
+
+flag {
     name: "spatializer_offload"
     namespace: "media_audio"
     description: "Enable spatializer offload"
@@ -60,6 +69,13 @@
 }
 
 flag {
+    name: "spatializer_upmix"
+    namespace: "media_audio"
+    description: "Enable spatializer upmix"
+    bug: "323985367"
+}
+
+flag {
     name: "stereo_spatialization"
     namespace: "media_audio"
     description: "Enable stereo channel mask for spatialization."
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index cfdf1ab..0209e28 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -4,6 +4,7 @@
 # Please add flags in alphabetical order.
 
 package: "android.media.audio"
+container: "system"
 
 flag {
     name: "auto_public_volume_api_hardening"
@@ -23,6 +24,7 @@
 
 flag {
     name: "feature_spatial_audio_headtracking_low_latency"
+    is_exported: true
     namespace: "media_audio"
     description: "Define feature for low latency headtracking for SA"
     bug: "324291076"
@@ -30,6 +32,7 @@
 
 flag {
     name: "focus_exclusive_with_recording"
+    is_exported: true
     namespace: "media_audio"
     description:
         "Audio focus GAIN_TRANSIENT_EXCLUSIVE only mutes"
@@ -37,18 +40,22 @@
     bug: "316414750"
 }
 
+# TODO remove
 flag {
     name: "foreground_audio_control"
+    is_exported: true
     namespace: "media_audio"
     description:
         "Audio focus gain requires FGS or delegation to "
-	"take effect"
+        "take effect"
     bug: "296232417"
+    is_fixed_read_only: true
 }
 
 # TODO remove
 flag {
     name: "focus_freeze_test_api"
+    is_exported: true
     namespace: "media_audio"
     description: "\
  AudioManager audio focus test APIs:\
@@ -62,6 +69,7 @@
 
 flag {
     name: "loudness_configurator_api"
+    is_exported: true
     namespace: "media_audio"
     description: "\
 Enable the API for providing loudness metadata and CTA-2075 \
@@ -79,6 +87,7 @@
 
 flag {
     name: "sco_managed_by_audio"
+    is_exported: true
     namespace: "media_audio"
     description: "\
 Enable new implementation of headset profile device connection and\
@@ -88,14 +97,37 @@
 
 flag {
     name: "supported_device_types_api"
+    is_exported: true
     namespace: "media_audio"
     description: "Surface new API method AudioManager.getSupportedDeviceTypes()"
     bug: "307537538"
 }
 
 flag {
+    name: "ro_foreground_audio_control"
+    is_exported: true
+    namespace: "media_audio"
+    description:
+        "Audio focus gain requires FGS or delegation to "
+        "take effect"
+    bug: "296232417"
+    is_fixed_read_only: true
+}
+
+flag {
+    name: "ro_volume_ringer_api_hardening"
+    namespace: "media_audio"
+    description: "Limit access to volume and ringer SDK APIs in AudioManager"
+    bug: "296232417"
+    is_fixed_read_only: true
+}
+
+
+# TODO remove
+flag {
     name: "volume_ringer_api_hardening"
     namespace: "media_audio"
     description: "Limit access to volume and ringer SDK APIs in AudioManager"
     bug: "296232417"
+    is_fixed_read_only: true
 }
diff --git a/media/audio/aconfig/audioclient.aconfig b/media/audio/aconfig/audioclient.aconfig
new file mode 100644
index 0000000..a804834
--- /dev/null
+++ b/media/audio/aconfig/audioclient.aconfig
@@ -0,0 +1,16 @@
+# Flags for libaudioclient, and other native client libraries.
+#
+# Please add flags in alphabetical order.
+
+package: "com.android.media.audioclient"
+container: "system"
+
+flag {
+    name: "audiosystem_service_acquisition"
+    namespace: "media_audio"
+    description: "Clean up audiosystem service acquisition."
+    bug: "330358287"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/media/audio/aconfig/audiopolicy_framework.aconfig b/media/audio/aconfig/audiopolicy_framework.aconfig
index 72a1e6c..28b6c7f 100644
--- a/media/audio/aconfig/audiopolicy_framework.aconfig
+++ b/media/audio/aconfig/audiopolicy_framework.aconfig
@@ -24,6 +24,7 @@
 
 flag {
     name: "audio_mix_test_api"
+    is_exported: true
     namespace: "media_audio"
     description: "Enable new Test APIs that provide access to registered AudioMixes on system server and native side."
     bug: "309080867"
@@ -32,6 +33,7 @@
 
 flag {
     name: "audio_policy_update_mixing_rules_api"
+    is_exported: true
     namespace: "media_audio"
     description: "Enable AudioPolicy.updateMixingRules API for hot-swapping audio mixing rules."
     bug: "293874525"
@@ -39,6 +41,7 @@
 
 flag {
     name: "enable_fade_manager_configuration"
+    is_exported: true
     namespace: "media_audio"
     description: "Enable Fade Manager Configuration support to determine fade properties"
     bug: "307354764"
diff --git a/media/audio/aconfig/midi_flags.aconfig b/media/audio/aconfig/midi_flags.aconfig
index efb643f..1620e1b 100644
--- a/media/audio/aconfig/midi_flags.aconfig
+++ b/media/audio/aconfig/midi_flags.aconfig
@@ -8,6 +8,7 @@
 
 flag {
     name: "virtual_ump"
+    is_exported: true
     namespace: "media_audio"
     description: "Enable virtual UMP MIDI."
     bug: "291115176"
diff --git a/media/audioaidlconversion/Android.bp b/media/audioaidlconversion/Android.bp
index 07c59c7..2e1eb8c 100644
--- a/media/audioaidlconversion/Android.bp
+++ b/media/audioaidlconversion/Android.bp
@@ -58,10 +58,10 @@
 cc_defaults {
     name: "audio_aidl_conversion_common_default_cpp",
     shared_libs: [
+        "framework-permission-aidl-cpp",
         "libbinder",
         "libshmemcompat",
         "shared-file-region-aidl-cpp",
-        "framework-permission-aidl-cpp",
     ],
     export_shared_lib_headers: [
         "shared-file-region-aidl-cpp",
@@ -94,8 +94,8 @@
     ],
     sanitize: {
         misc_undefined: [
-            "unsigned-integer-overflow",
             "signed-integer-overflow",
+            "unsigned-integer-overflow",
         ],
     },
     target: {
@@ -148,8 +148,8 @@
         "latest_android_media_audio_common_types_ndk_shared",
     ],
     shared_libs: [
-        "libbinder_ndk",
         "libbase",
+        "libbinder_ndk",
     ],
     static_libs: [
         "libaudioaidlcommon",
@@ -182,8 +182,8 @@
     ],
     shared_libs: [
         "libaudio_aidl_conversion_common_ndk",
-        "libbinder_ndk",
         "libbase",
+        "libbinder_ndk",
     ],
     cflags: [
         "-DBACKEND_NDK",
@@ -213,8 +213,8 @@
     ],
     shared_libs: [
         "libaudio_aidl_conversion_common_ndk",
-        "libbinder_ndk",
         "libbase",
+        "libbinder_ndk",
     ],
     cflags: [
         "-DBACKEND_NDK",
@@ -238,8 +238,8 @@
         "latest_android_media_audio_common_types_ndk_shared",
     ],
     shared_libs: [
-        "libbinder_ndk",
         "libbase",
+        "libbinder_ndk",
     ],
     cflags: [
         "-DBACKEND_CPP_NDK",
diff --git a/media/audioaidlconversion/tests/Android.bp b/media/audioaidlconversion/tests/Android.bp
index 88b2cc9..bca4dd0 100644
--- a/media/audioaidlconversion/tests/Android.bp
+++ b/media/audioaidlconversion/tests/Android.bp
@@ -16,8 +16,8 @@
     ],
     sanitize: {
         misc_undefined: [
-            "unsigned-integer-overflow",
             "signed-integer-overflow",
+            "unsigned-integer-overflow",
         ],
     },
 }
@@ -26,8 +26,8 @@
     name: "audio_aidl_ndk_conversion_tests",
 
     defaults: [
-        "latest_android_media_audio_common_types_ndk_static",
         "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
         "libaudio_aidl_conversion_tests_defaults",
     ],
     srcs: ["audio_aidl_ndk_conversion_tests.cpp"],
diff --git a/media/audioserver/Android.bp b/media/audioserver/Android.bp
index 479e13a..e74fb91 100644
--- a/media/audioserver/Android.bp
+++ b/media/audioserver/Android.bp
@@ -27,11 +27,11 @@
     ],
 
     defaults: [
+        "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_media_audio_common_types_cpp_shared",
         "libaaudioservice_dependencies",
         "libaudioflinger_dependencies",
         "libaudiopolicyservice_dependencies",
-        "latest_android_media_audio_common_types_cpp_shared",
-        "latest_android_hardware_audio_core_sounddose_ndk_shared",
     ],
 
     static_libs: [
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 7c9d3e8..128e16e 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -605,7 +605,7 @@
     mCodecConfiguration->g_timebase.den = 1000000;
     // rc_target_bitrate is in kbps, mBitrate in bps
     mCodecConfiguration->rc_target_bitrate = (mBitrate->value + 500) / 1000;
-    mCodecConfiguration->rc_end_usage = mBitrateControlMode == AOM_Q ? AOM_Q : AOM_CBR;
+    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
     // Disable frame drop - not allowed in MediaCodec now.
     mCodecConfiguration->rc_dropframe_thresh = 0;
     // Disable lagged encoding.
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 785cdf2..e6782a9 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -164,6 +164,9 @@
     kParamIndexLargeFrame,
     kParamIndexAccessUnitInfos, // struct
 
+    /* Region of Interest Encoding parameters */
+    kParamIndexQpOffsetMapBuffer, // info-buffer, used to signal qp-offset map for a frame
+
     // deprecated
     kParamIndexDelayRequest = kParamIndexDelay | C2Param::CoreIndex::IS_REQUEST_FLAG,
 
@@ -201,6 +204,8 @@
     kParamIndexPictureQuantization,
     kParamIndexHdrDynamicMetadata,
     kParamIndexHdrFormat,
+    kParamIndexQpOffsetRect,
+    kParamIndexQpOffsetRects,
 
     /* ------------------------------------ video components ------------------------------------ */
 
@@ -1394,6 +1399,47 @@
 constexpr char C2_PARAMKEY_VUI_ROTATION[] = "coded.vui.rotation";
 
 /**
+ * Region of Interest of an image/video frame communicated as an array of C2QpOffsetRectStruct
+ *
+ * Fields width, height, left and top of C2QpOffsetRectStruct form a bounding box contouring RoI.
+ * Field qpOffset of C2QpOffsetRectStruct indicates the qp bias to be used for quantizing the
+ * coding units of the bounding box.
+ *
+ * If Roi rect is not valid that is bounding box width is < 0 or bounding box height is < 0,
+ * components may ignore the configuration silently. If Roi rect extends outside frame
+ * boundaries, then rect shall be clamped to the frame boundaries.
+ *
+ * The scope of this key is throughout the encoding session until it is reconfigured with a
+ * different value.
+ *
+ * The number of elements in C2StreamQpOffset array is not limited by C2 specification.
+ * However components may mandate a limit. Implementations may drop the rectangles that are beyond
+ * the supported limits. Hence it is preferable to place the rects in descending order of
+ * importance. Transitively, if the bounding boxes overlap, then the most preferred
+ * rectangle's qp offset (earlier rectangle qp offset) will be used to quantize the block.
+ */
+struct C2QpOffsetRectStruct : C2Rect {
+    C2QpOffsetRectStruct() = default;
+    C2QpOffsetRectStruct(const C2Rect &rect, int32_t offset) : C2Rect(rect), qpOffset(offset) {}
+
+    bool operator==(const C2QpOffsetRectStruct &) = delete;
+    bool operator!=(const C2QpOffsetRectStruct &) = delete;
+
+    int32_t qpOffset;
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(QpOffsetRect)
+    C2FIELD(width, "width")
+    C2FIELD(height, "height")
+    C2FIELD(left, "left")
+    C2FIELD(top, "top")
+    C2FIELD(qpOffset, "qp-offset")
+};
+
+typedef C2StreamParam<C2Info, C2SimpleArrayStruct<C2QpOffsetRectStruct>, kParamIndexQpOffsetRects>
+        C2StreamQpOffsetRects;
+constexpr char C2_PARAMKEY_QP_OFFSET_RECTS[] = "coding.qp-offset-rects";
+
+/**
  * Pixel (sample) aspect ratio.
  */
 typedef C2StreamParam<C2Info, C2PictureSizeStruct, kParamIndexPixelAspectRatio>
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index eb64a4a..87c9d87 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -487,7 +487,19 @@
     if (__builtin_available(android __ANDROID_API_T__, *)) {
         std::shared_ptr<C2Component::Listener> c2listener;
         if (mMultiAccessUnitIntf) {
-            mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+            std::shared_ptr<C2Allocator> allocator;
+            std::shared_ptr<C2BlockPool> linearPool;
+            std::shared_ptr<C2AllocatorStore> store = ::android::GetCodec2PlatformAllocatorStore();
+            if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator) == C2_OK) {
+                ::android::C2PlatformAllocatorDesc desc;
+                desc.allocatorId = allocator->getId();
+                if (C2_OK == CreateCodec2BlockPool(desc, mComponent, &linearPool)) {
+                    if (linearPool) {
+                        mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(
+                                mMultiAccessUnitIntf, linearPool);
+                    }
+                }
+            }
         }
         c2listener = mMultiAccessUnitHelper ?
                 std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
diff --git a/media/codec2/hal/aidl/ComponentInterface.cpp b/media/codec2/hal/aidl/ComponentInterface.cpp
index 8ae9fa8..8c7a986 100644
--- a/media/codec2/hal/aidl/ComponentInterface.cpp
+++ b/media/codec2/hal/aidl/ComponentInterface.cpp
@@ -79,6 +79,26 @@
         }
         c2_status_t err2 = C2_OK;
         if (paramsToLargeFrameIntf.size() > 0) {
+            C2ComponentKindSetting kind;
+            C2StreamMaxBufferSizeInfo::input maxInputSize(0);
+            c2_status_t err = mIntf->query_vb(
+                    {&kind, &maxInputSize}, {}, C2_MAY_BLOCK, nullptr);
+            if ((err == C2_OK) && (kind.value == C2Component::KIND_ENCODER)) {
+                for (int i = 0 ; i < paramsToLargeFrameIntf.size(); i++) {
+                    if (paramsToLargeFrameIntf[i]->index() ==
+                            C2LargeFrame::output::PARAM_TYPE) {
+                        C2LargeFrame::output *lfp = C2LargeFrame::output::From(
+                                    paramsToLargeFrameIntf[i]);
+                        // This is assuming a worst case compression ratio of 1:1
+                        // In no case the encoder should give an output more than
+                        // what is being provided to the encoder in a single call.
+                        if (lfp && (lfp->maxSize < maxInputSize.value)) {
+                            lfp->maxSize = maxInputSize.value;
+                        }
+                        break;
+                    }
+                }
+            }
             err2 = mMultiAccessUnitIntf->config(
                     paramsToLargeFrameIntf, mayBlock, failures);
         }
diff --git a/media/codec2/hal/common/MultiAccessUnitHelper.cpp b/media/codec2/hal/common/MultiAccessUnitHelper.cpp
index 3a71520..8086ef2 100644
--- a/media/codec2/hal/common/MultiAccessUnitHelper.cpp
+++ b/media/codec2/hal/common/MultiAccessUnitHelper.cpp
@@ -96,18 +96,23 @@
     return (C2Component::kind_t)(mKind.value);
 }
 
-void MultiAccessUnitInterface::getDecoderSampleRateAndChannelCount(
-        uint32_t &sampleRate_, uint32_t &channelCount_) const {
+bool MultiAccessUnitInterface::getDecoderSampleRateAndChannelCount(
+        uint32_t * const sampleRate_, uint32_t * const channelCount_) const {
+    if (sampleRate_ == nullptr || channelCount_ == nullptr) {
+        return false;
+    }
     if (mC2ComponentIntf) {
         C2StreamSampleRateInfo::output sampleRate;
         C2StreamChannelCountInfo::output channelCount;
         c2_status_t res = mC2ComponentIntf->query_vb(
                 {&sampleRate, &channelCount}, {}, C2_MAY_BLOCK, nullptr);
-        if (res == C2_OK) {
-            sampleRate_ = sampleRate.value;
-            channelCount_ = channelCount.value;
+        if (res == C2_OK && sampleRate.value > 0 && channelCount.value > 0) {
+            *sampleRate_ = sampleRate.value;
+            *channelCount_ = channelCount.value;
+            return true;
         }
     }
+    return false;
 }
 
 //C2MultiAccessUnitBuffer
@@ -121,12 +126,12 @@
 
 //MultiAccessUnitHelper
 MultiAccessUnitHelper::MultiAccessUnitHelper(
-        const std::shared_ptr<MultiAccessUnitInterface>& intf):
+        const std::shared_ptr<MultiAccessUnitInterface>& intf,
+        std::shared_ptr<C2BlockPool>& linearPool):
         mInit(false),
-        mInterface(intf) {
-    std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
-    if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator) == C2_OK) {
-        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, ++mBlockPoolId);
+        mInterface(intf),
+        mLinearPool(linearPool) {
+    if (mLinearPool) {
         mInit = true;
     }
 }
@@ -164,6 +169,7 @@
         std::list<std::unique_ptr<C2Work>> * const worklist) {
     if (worklist == nullptr) {
         LOG(ERROR) << "Provided null worklist for error()";
+        mFrameHolder.clear();
         return C2_OK;
     }
     std::unique_lock<std::mutex> l(mLock);
@@ -272,6 +278,7 @@
                 LOG(ERROR) << "ERROR: Work has Large frame info but has no linear blocks.";
                 return C2_CORRUPTED;
             }
+            frameInfo.mInputC2Ref = inBuffers;
             const std::vector<C2ConstLinearBlock>& multiAU =
                     inBuffers.front()->data().linearBlocks();
             std::shared_ptr<const C2AccessUnitInfos::input> auInfo =
@@ -320,26 +327,10 @@
             }
         }
         if (!processedWork->empty()) {
-            {
-                C2LargeFrame::output multiAccessParams = mInterface->getLargeFrameParam();
-                if (mInterface->kind() == C2Component::KIND_DECODER) {
-                    uint32_t sampleRate = 0;
-                    uint32_t channelCount = 0;
-                    uint32_t frameSize = 0;
-                    mInterface->getDecoderSampleRateAndChannelCount(
-                            sampleRate, channelCount);
-                    if (sampleRate > 0 && channelCount > 0) {
-                        frameSize = channelCount * 2;
-                        multiAccessParams.maxSize =
-                                (multiAccessParams.maxSize / frameSize) * frameSize;
-                        multiAccessParams.thresholdSize =
-                                (multiAccessParams.thresholdSize / frameSize) * frameSize;
-                    }
-                }
-                frameInfo.mLargeFrameTuning = multiAccessParams;
-                std::lock_guard<std::mutex> l(mLock);
-                mFrameHolder.push_back(std::move(frameInfo));
-            }
+            C2LargeFrame::output multiAccessParams = mInterface->getLargeFrameParam();
+            frameInfo.mLargeFrameTuning = multiAccessParams;
+            std::lock_guard<std::mutex> l(mLock);
+            mFrameHolder.push_back(std::move(frameInfo));
         }
     }
     return C2_OK;
@@ -506,6 +497,20 @@
             frame.reset();
             return C2_OK;
         }
+        int64_t sampleTimeUs = 0;
+        uint32_t frameSize = 0;
+        uint32_t sampleRate = 0;
+        uint32_t channelCount = 0;
+        if (mInterface->getDecoderSampleRateAndChannelCount(&sampleRate, &channelCount)) {
+            sampleTimeUs = (1000000u) / (sampleRate * channelCount * 2);
+            frameSize = channelCount * 2;
+            if (mInterface->kind() == C2Component::KIND_DECODER) {
+                frame.mLargeFrameTuning.maxSize =
+                        (frame.mLargeFrameTuning.maxSize / frameSize) * frameSize;
+                frame.mLargeFrameTuning.thresholdSize =
+                        (frame.mLargeFrameTuning.thresholdSize / frameSize) * frameSize;
+            }
+        }
         c2_status_t c2ret = allocateWork(frame, true);
         if (c2ret != C2_OK) {
             return c2ret;
@@ -520,15 +525,7 @@
         outputFramedata.infoBuffers.insert(outputFramedata.infoBuffers.begin(),
                 (*worklet)->output.infoBuffers.begin(),
                 (*worklet)->output.infoBuffers.end());
-        int64_t sampleTimeUs = 0;
-        uint32_t frameSize = 0;
-        uint32_t sampleRate = 0;
-        uint32_t channelCount = 0;
-        mInterface->getDecoderSampleRateAndChannelCount(sampleRate, channelCount);
-        if (sampleRate > 0 && channelCount > 0) {
-            sampleTimeUs = (1000000u) / (sampleRate * channelCount * 2);
-            frameSize = channelCount * 2;
-        }
+
         LOG(DEBUG) << "maxOutSize " << frame.mLargeFrameTuning.maxSize
                 << " threshold " << frame.mLargeFrameTuning.thresholdSize;
         if ((*worklet)->output.buffers.size() > 0) {
diff --git a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
index a90ae56..bb4464c 100644
--- a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
+++ b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
@@ -44,8 +44,8 @@
     bool isValidField(const C2ParamField &field) const;
 
 protected:
-    void getDecoderSampleRateAndChannelCount(
-            uint32_t &sampleRate_, uint32_t &channelCount_) const;
+    bool getDecoderSampleRateAndChannelCount(
+            uint32_t * const sampleRate_, uint32_t * const channelCount_) const;
     const std::shared_ptr<C2ComponentInterface> mC2ComponentIntf;
     std::shared_ptr<C2LargeFrame::output> mLargeFrameParams;
     C2ComponentKindSetting mKind;
@@ -58,7 +58,8 @@
 struct MultiAccessUnitHelper {
 public:
     MultiAccessUnitHelper(
-            const std::shared_ptr<MultiAccessUnitInterface>& intf);
+            const std::shared_ptr<MultiAccessUnitInterface>& intf,
+            std::shared_ptr<C2BlockPool> &linearPool);
 
     virtual ~MultiAccessUnitHelper();
 
@@ -153,6 +154,11 @@
          */
         std::unique_ptr<C2Work> mLargeWork;
 
+        /*
+         * For holding a reference to the incoming buffer
+         */
+        std::vector<std::shared_ptr<C2Buffer>> mInputC2Ref;
+
         MultiAccessUnitInfo(C2WorkOrdinalStruct ordinal):inOrdinal(ordinal) {
 
         }
@@ -197,8 +203,6 @@
     C2BlockPool::local_id_t mBlockPoolId;
     // C2Blockpool for output buffer allocation
     std::shared_ptr<C2BlockPool> mLinearPool;
-    // Allocator for output buffer allocation
-    std::shared_ptr<C2Allocator> mLinearAllocator;
     // FrameIndex for the current outgoing work
     std::atomic_uint64_t mFrameIndex;
     // Mutex to protect mFrameHolder
diff --git a/media/codec2/hal/hidl/1.0/utils/Component.cpp b/media/codec2/hal/hidl/1.0/utils/Component.cpp
index e32e6ae..0259d90 100644
--- a/media/codec2/hal/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/Component.cpp
@@ -570,7 +570,19 @@
 void Component::initListener(const sp<Component>& self) {
     std::shared_ptr<C2Component::Listener> c2listener;
     if (mMultiAccessUnitIntf) {
-        mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+        std::shared_ptr<C2Allocator> allocator;
+        std::shared_ptr<C2BlockPool> linearPool;
+        std::shared_ptr<C2AllocatorStore> store = ::android::GetCodec2PlatformAllocatorStore();
+        if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator) == C2_OK) {
+            ::android::C2PlatformAllocatorDesc desc;
+            desc.allocatorId = allocator->getId();
+            if (C2_OK == CreateCodec2BlockPool(desc, mComponent, &linearPool)) {
+                if (linearPool) {
+                    mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(
+                            mMultiAccessUnitIntf, linearPool);
+                }
+            }
+        }
     }
     c2listener = mMultiAccessUnitHelper ?
             std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp
index 41a8904..08f1ae2 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp
@@ -78,6 +78,26 @@
         }
         c2_status_t err2 = C2_OK;
         if (paramsToLargeFrameIntf.size() > 0) {
+            C2ComponentKindSetting kind;
+            C2StreamMaxBufferSizeInfo::input maxInputSize(0);
+            c2_status_t err = mIntf->query_vb(
+                    {&kind, &maxInputSize}, {}, C2_MAY_BLOCK, nullptr);
+            if ((err == C2_OK) && (kind.value == C2Component::KIND_ENCODER)) {
+                for (int i = 0 ; i < paramsToLargeFrameIntf.size(); i++) {
+                    if (paramsToLargeFrameIntf[i]->index() ==
+                            C2LargeFrame::output::PARAM_TYPE) {
+                        C2LargeFrame::output *lfp = C2LargeFrame::output::From(
+                                    paramsToLargeFrameIntf[i]);
+                        // This is assuming a worst case compression ratio of 1:1
+                        // In no case the encoder should give an output more than
+                        // what is being provided to the encoder in a single call.
+                        if (lfp && (lfp->maxSize < maxInputSize.value)) {
+                            lfp->maxSize = maxInputSize.value;
+                        }
+                        break;
+                    }
+                }
+            }
             err2 = mMultiAccessUnitIntf->config(
                     paramsToLargeFrameIntf, mayBlock, failures);
         }
diff --git a/media/codec2/hal/hidl/1.1/utils/Component.cpp b/media/codec2/hal/hidl/1.1/utils/Component.cpp
index 09e5709..d34d84e 100644
--- a/media/codec2/hal/hidl/1.1/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/Component.cpp
@@ -583,7 +583,19 @@
 void Component::initListener(const sp<Component>& self) {
     std::shared_ptr<C2Component::Listener> c2listener;
     if (mMultiAccessUnitIntf) {
-        mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+        std::shared_ptr<C2Allocator> allocator;
+        std::shared_ptr<C2BlockPool> linearPool;
+        std::shared_ptr<C2AllocatorStore> store = ::android::GetCodec2PlatformAllocatorStore();
+        if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator) == C2_OK) {
+            ::android::C2PlatformAllocatorDesc desc;
+            desc.allocatorId = allocator->getId();
+            if (C2_OK == CreateCodec2BlockPool(desc, mComponent, &linearPool)) {
+                if (linearPool) {
+                    mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(
+                            mMultiAccessUnitIntf, linearPool);
+                }
+            }
+        }
     }
     c2listener = mMultiAccessUnitHelper ?
             std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
diff --git a/media/codec2/hal/hidl/1.2/utils/Component.cpp b/media/codec2/hal/hidl/1.2/utils/Component.cpp
index 0fe16e3..f78e827 100644
--- a/media/codec2/hal/hidl/1.2/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/Component.cpp
@@ -610,7 +610,19 @@
 void Component::initListener(const sp<Component>& self) {
     std::shared_ptr<C2Component::Listener> c2listener;
     if (mMultiAccessUnitIntf) {
-        mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+        std::shared_ptr<C2Allocator> allocator;
+        std::shared_ptr<C2BlockPool> linearPool;
+        std::shared_ptr<C2AllocatorStore> store = ::android::GetCodec2PlatformAllocatorStore();
+        if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator) == C2_OK) {
+            ::android::C2PlatformAllocatorDesc desc;
+            desc.allocatorId = allocator->getId();
+            if (C2_OK == CreateCodec2BlockPool(desc, mComponent, &linearPool)) {
+                if (linearPool) {
+                    mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(
+                            mMultiAccessUnitIntf, linearPool);
+                }
+            }
+        }
     }
     c2listener = mMultiAccessUnitHelper ?
             std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 18c2468..4de2347 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -45,6 +45,7 @@
 
     static_libs: [
         "libSurfaceFlingerProperties",
+        "aconfig_mediacodec_flags_c_lib",
         "android.media.codec-aconfig-cc",
     ],
 
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 40656ff..f58dc65 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -552,8 +552,7 @@
     }
 
     ssize_t result = -1;
-    ssize_t codecDataOffset = 0;
-    size_t inBufferOffset = 0;
+    size_t srcOffset = offset;
     size_t outBufferSize = 0;
     uint32_t cryptoInfoIdx = 0;
     int32_t heapSeqNum = getHeapSeqNum(memory);
@@ -565,18 +564,20 @@
     for (int i = 0; i < bufferInfos->value.size(); i++) {
         if (bufferInfos->value[i].mSize > 0) {
             std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[cryptoInfoIdx++]);
+            src.offset = srcOffset;
+            src.size = bufferInfos->value[i].mSize;
             result = mCrypto->decrypt(
                     (uint8_t*)info->mKey,
                     (uint8_t*)info->mIv,
                     info->mMode,
                     info->mPattern,
                     src,
-                    inBufferOffset,
+                    0,
                     info->mSubSamples,
                     info->mNumSubSamples,
                     dst,
                     errorDetailMsg);
-            inBufferOffset += bufferInfos->value[i].mSize;
+            srcOffset += bufferInfos->value[i].mSize;
             if (result < 0) {
                 ALOGI("[%s] attachEncryptedBuffers: decrypt failed: result = %zd",
                         mName, result);
@@ -599,7 +600,7 @@
         wView.setOffset(0);
     }
     std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
-            block->share(codecDataOffset, outBufferSize - codecDataOffset, C2Fence{}))};
+            block->share(0, outBufferSize, C2Fence{}))};
     if (!buffer->copy(c2Buffer)) {
         ALOGI("[%s] attachEncryptedBuffers: buffer copy failed", mName);
         return -ENOSYS;
@@ -980,8 +981,7 @@
     }
     // size of cryptoInfo and accessUnitInfo should be the same?
     ssize_t result = -1;
-    ssize_t codecDataOffset = 0;
-    size_t inBufferOffset = 0;
+    size_t srcOffset = 0;
     size_t outBufferSize = 0;
     uint32_t cryptoInfoIdx = 0;
     {
@@ -994,6 +994,7 @@
         encryptedBuffer->getMappedBlock(&mappedBlock);
         hardware::drm::V1_0::SharedBuffer source;
         encryptedBuffer->fillSourceBuffer(&source);
+        srcOffset = source.offset;
         for (int i = 0 ; i < bufferInfos->value.size(); i++) {
             if (bufferInfos->value[i].mSize > 0) {
                 std::unique_ptr<CodecCryptoInfo> info =
@@ -1004,18 +1005,20 @@
                     // no data so we only populate the bufferInfo
                     result = 0;
                 } else {
+                    source.offset = srcOffset;
+                    source.size = bufferInfos->value[i].mSize;
                     result = mCrypto->decrypt(
                             (uint8_t*)info->mKey,
                             (uint8_t*)info->mIv,
                             info->mMode,
                             info->mPattern,
                             source,
-                            inBufferOffset,
+                            buffer->offset(),
                             info->mSubSamples,
                             info->mNumSubSamples,
                             destination,
                             errorDetailMsg);
-                    inBufferOffset += bufferInfos->value[i].mSize;
+                    srcOffset += bufferInfos->value[i].mSize;
                     if (result < 0) {
                         ALOGI("[%s] decrypt failed: result=%zd", mName, result);
                         return result;
@@ -1028,7 +1031,7 @@
                 }
             }
         }
-        buffer->setRange(codecDataOffset, outBufferSize - codecDataOffset);
+        buffer->setRange(0, outBufferSize);
     }
     return queueInputBufferInternal(buffer, block, bufferSize);
 }
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 8dce789..37a7a4f 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -20,6 +20,7 @@
 
 #include <strings.h>
 
+#include <com_android_media_codec_flags.h>
 #include <android_media_codec.h>
 
 #include <C2Component.h>
@@ -755,7 +756,8 @@
                 addSupportedColorFormats(
                         intf, caps.get(), trait, mediaType, it->second);
 
-                if (android::media::codec::provider_->large_audio_frame_finish()) {
+                if (com::android::media::codec::flags::provider_->large_audio_frame()
+                        && android::media::codec::provider_->large_audio_frame_finish()) {
                     // Adding feature-multiple-frames when C2LargeFrame param is present
                     if (trait.domain == C2Component::DOMAIN_AUDIO) {
                         std::vector<std::shared_ptr<C2ParamDescriptor>> params;
diff --git a/media/libaaudio/fuzzer/Android.bp b/media/libaaudio/fuzzer/Android.bp
index 6d94f38..fc8ad77 100644
--- a/media/libaaudio/fuzzer/Android.bp
+++ b/media/libaaudio/fuzzer/Android.bp
@@ -36,37 +36,37 @@
         "libaaudio_headers",
     ],
     shared_libs: [
-        "libbinder",
+        "com.android.media.aaudio-aconfig-cc",
+        "libaudio_aidl_conversion_common_cpp",
+        "libaudioclient_aidl_conversion",
         "libaudiomanager",
         "libaudiopolicy",
-        "libaudioclient_aidl_conversion",
-        "libaudio_aidl_conversion_common_cpp",
+        "libbinder",
         "libutils",
-        "com.android.media.aaudio-aconfig-cc",
     ],
     static_libs: [
-        "liblog",
-        "libcutils",
+        "aaudio-aidl-cpp",
+        "audioclient-types-aidl-cpp",
+        "audioflinger-aidl-cpp",
+        "audiopolicy-aidl-cpp",
+        "audiopolicy-types-aidl-cpp",
+        "av-types-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaaudio",
-        "libjsoncpp",
+        "libaaudio_internal",
+        "libaudioclient",
+        "libaudioutils",
         "libbase_ndk",
         "libcgrouprc",
-        "libaudioutils",
-        "libaudioclient",
-        "aaudio-aidl-cpp",
+        "libcgrouprc_format",
+        "libcutils",
+        "libjsoncpp",
+        "liblog",
         "libmedia_helper",
         "libmediametrics",
         "libprocessgroup",
-        "av-types-aidl-cpp",
-        "libaaudio_internal",
-        "libcgrouprc_format",
-        "audiopolicy-aidl-cpp",
-        "audioflinger-aidl-cpp",
-        "audiopolicy-types-aidl-cpp",
-        "audioclient-types-aidl-cpp",
-        "shared-file-region-aidl-cpp",
-        "framework-permission-aidl-cpp",
         "mediametricsservice-aidl-cpp",
+        "shared-file-region-aidl-cpp",
     ],
     fuzz_config: {
         cc: [
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index d2cb265..398ac5b 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -57,10 +57,10 @@
     "-bugprone-macro-parentheses", // found in SharedMemoryParcelable.h
     "-bugprone-narrowing-conversions", // found in several interface from size_t to int32_t
 
-    "-google-readability-casting", // C++ casts not always necessary and may be verbose
-    "-google-readability-todo", // do not require TODO(info)
     "-google-build-using-namespace", // Reenable and fix later.
     "-google-global-names-in-headers", // found in several files
+    "-google-readability-casting", // C++ casts not always necessary and may be verbose
+    "-google-readability-todo", // do not require TODO(info)
 
     "-misc-non-private-member-variables-in-classes", // found in aidl generated files
 
@@ -90,28 +90,30 @@
     ],
 
     cflags: [
-        "-Wthread-safety",
-        "-Wno-unused-parameter",
         "-Wall",
         "-Werror",
         // By default, all symbols are hidden.
+
         // "-fvisibility=hidden",
         // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+
         "-DAAUDIO_API=__attribute__((visibility(\"default\")))",
     ],
 
     shared_libs: [
+        "framework-permission-aidl-cpp",
         "libaaudio_internal",
         "libaudioclient",
         "libaudioutils",
+        "libbinder",
+        "libcutils",
+        "liblog",
         "libmedia_helper",
         "libmediametrics",
         "libmediautils",
-        "liblog",
-        "libcutils",
         "libutils",
-        "libbinder",
-        "framework-permission-aidl-cpp",
     ],
 
     sanitize: {
@@ -161,56 +163,49 @@
     ],
 
     shared_libs: [
+        "aaudio-aidl-cpp",
+        "audioclient-types-aidl-cpp",
+        "com.android.media.aaudio-aconfig-cc",
+        "framework-permission-aidl-cpp",
         "libaudioclient",
+        "libaudioclient_aidl_conversion",
         "libaudioutils",
+        "libbinder",
+        "libcutils",
+        "liblog",
         "libmedia_helper",
         "libmediametrics",
         "libmediautils",
-        "liblog",
-        "libcutils",
         "libutils",
-        "libbinder",
-        "framework-permission-aidl-cpp",
-        "aaudio-aidl-cpp",
-        "audioclient-types-aidl-cpp",
-        "libaudioclient_aidl_conversion",
-        "com.android.media.aaudio-aconfig-cc",
     ],
 
     cflags: [
-        "-Wno-unused-parameter",
         "-Wall",
         "-Werror",
+        "-Wno-unused-parameter",
     ],
 
     srcs: [
-        "core/AudioGlobal.cpp",
-        "core/AudioStream.cpp",
-        "core/AudioStreamBuilder.cpp",
-        "core/AAudioStreamParameters.cpp",
-        "legacy/AudioStreamLegacy.cpp",
-        "legacy/AudioStreamRecord.cpp",
-        "legacy/AudioStreamTrack.cpp",
-        "utility/AAudioUtilities.cpp",
-        "utility/FixedBlockAdapter.cpp",
-        "utility/FixedBlockReader.cpp",
-        "utility/FixedBlockWriter.cpp",
-        "fifo/FifoBuffer.cpp",
-        "fifo/FifoControllerBase.cpp",
+        "binding/AAudioBinderAdapter.cpp",
+        "binding/AAudioBinderClient.cpp",
+        "binding/AAudioStreamConfiguration.cpp",
+        "binding/AAudioStreamRequest.cpp",
+        "binding/AudioEndpointParcelable.cpp",
+        "binding/RingBufferParcelable.cpp",
+        "binding/SharedMemoryParcelable.cpp",
+        "binding/SharedRegionParcelable.cpp",
         "client/AAudioFlowGraph.cpp",
         "client/AudioEndpoint.cpp",
         "client/AudioStreamInternal.cpp",
         "client/AudioStreamInternalCapture.cpp",
         "client/AudioStreamInternalPlay.cpp",
         "client/IsochronousClockModel.cpp",
-        "binding/AudioEndpointParcelable.cpp",
-        "binding/AAudioBinderAdapter.cpp",
-        "binding/AAudioBinderClient.cpp",
-        "binding/AAudioStreamRequest.cpp",
-        "binding/AAudioStreamConfiguration.cpp",
-        "binding/RingBufferParcelable.cpp",
-        "binding/SharedMemoryParcelable.cpp",
-        "binding/SharedRegionParcelable.cpp",
+        "core/AAudioStreamParameters.cpp",
+        "core/AudioGlobal.cpp",
+        "core/AudioStream.cpp",
+        "core/AudioStreamBuilder.cpp",
+        "fifo/FifoBuffer.cpp",
+        "fifo/FifoControllerBase.cpp",
         "flowgraph/ChannelCountConverter.cpp",
         "flowgraph/ClipToRange.cpp",
         "flowgraph/FlowGraphNode.cpp",
@@ -218,20 +213,20 @@
         "flowgraph/ManyToMultiConverter.cpp",
         "flowgraph/MonoBlend.cpp",
         "flowgraph/MonoToMultiConverter.cpp",
-        "flowgraph/MultiToMonoConverter.cpp",
         "flowgraph/MultiToManyConverter.cpp",
+        "flowgraph/MultiToMonoConverter.cpp",
         "flowgraph/RampLinear.cpp",
         "flowgraph/SampleRateConverter.cpp",
         "flowgraph/SinkFloat.cpp",
+        "flowgraph/SinkI8_24.cpp",
         "flowgraph/SinkI16.cpp",
         "flowgraph/SinkI24.cpp",
         "flowgraph/SinkI32.cpp",
-        "flowgraph/SinkI8_24.cpp",
         "flowgraph/SourceFloat.cpp",
+        "flowgraph/SourceI8_24.cpp",
         "flowgraph/SourceI16.cpp",
         "flowgraph/SourceI24.cpp",
         "flowgraph/SourceI32.cpp",
-        "flowgraph/SourceI8_24.cpp",
         "flowgraph/resampler/IntegerRatio.cpp",
         "flowgraph/resampler/LinearResampler.cpp",
         "flowgraph/resampler/MultiChannelResampler.cpp",
@@ -240,6 +235,13 @@
         "flowgraph/resampler/PolyphaseResamplerStereo.cpp",
         "flowgraph/resampler/SincResampler.cpp",
         "flowgraph/resampler/SincResamplerStereo.cpp",
+        "legacy/AudioStreamLegacy.cpp",
+        "legacy/AudioStreamRecord.cpp",
+        "legacy/AudioStreamTrack.cpp",
+        "utility/AAudioUtilities.cpp",
+        "utility/FixedBlockAdapter.cpp",
+        "utility/FixedBlockReader.cpp",
+        "utility/FixedBlockWriter.cpp",
     ],
     sanitize: {
         integer_overflow: true,
@@ -263,17 +265,17 @@
     ],
     srcs: [
         "binding/aidl/aaudio/Endpoint.aidl",
+        "binding/aidl/aaudio/IAAudioClient.aidl",
+        "binding/aidl/aaudio/IAAudioService.aidl",
         "binding/aidl/aaudio/RingBuffer.aidl",
         "binding/aidl/aaudio/SharedRegion.aidl",
         "binding/aidl/aaudio/StreamParameters.aidl",
         "binding/aidl/aaudio/StreamRequest.aidl",
-        "binding/aidl/aaudio/IAAudioClient.aidl",
-        "binding/aidl/aaudio/IAAudioService.aidl",
     ],
     imports: [
         "audioclient-types-aidl",
-        "shared-file-region-aidl",
         "framework-permission-aidl",
+        "shared-file-region-aidl",
     ],
     backend: {
         java: {
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index e780f4f..cd7679c 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -278,3 +278,9 @@
         mDataQueue->eraseMemory();
     }
 }
+
+void AudioEndpoint::eraseEmptyDataMemory(int32_t numFrames) {
+    if (mDataQueue != nullptr) {
+        mDataQueue->eraseEmptyMemory(numFrames);
+    }
+}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index b117572..7e97c6a 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -107,6 +107,8 @@
      */
     void eraseDataMemory();
 
+    void eraseEmptyDataMemory(int32_t numFrames);
+
     void freeDataQueue() { mDataQueue.reset(); }
 
     void dump() const;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 7648e25..b2e93f0 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -575,10 +575,20 @@
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
+    // For playback, sleep until all the audio data has played.
+    // Then clear the buffer to prevent noise.
+    prepareBuffersForStop();
+
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_STOPPING);
     mAtomicInternalTimestamp.clear();
 
+#if 0
+    // Simulate very slow CPU, force race condition where the
+    // DSP keeps playing after we stop writing.
+    AudioClock::sleepForNanos(800 * AAUDIO_NANOS_PER_MILLISECOND);
+#endif
+
     result = mServiceInterface.stopStream(mServiceStreamHandleInfo);
     if (result == AAUDIO_ERROR_INVALID_HANDLE) {
         ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index a5981b1..20d55f9 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -123,6 +123,8 @@
 
     virtual void prepareBuffersForStart() {}
 
+    virtual void prepareBuffersForStop() {}
+
     virtual void advanceClientToMatchServerPosition(int32_t serverMargin) = 0;
 
     virtual void onFlushFromServer() {}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 5d4c3d4..0427777 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -19,6 +19,8 @@
 
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
+#include <algorithm>
+
 #include <media/MediaMetricsItem.h>
 #include <utils/Trace.h>
 
@@ -108,6 +110,61 @@
     mAudioEndpoint->eraseDataMemory();
 }
 
+void AudioStreamInternalPlay::prepareBuffersForStop() {
+    // If this is a shared stream and the FIFO is being read by the mixer then
+    // we don't have to worry about the DSP reading past the valid data. We can skip all this.
+    if(!mAudioEndpoint->isFreeRunning()) {
+        return;
+    }
+    // Sleep until the DSP has read all of the data written.
+    int64_t validFramesInBuffer = getFramesWritten() - getFramesRead();
+    if (validFramesInBuffer >= 0) {
+        int64_t emptyFramesInBuffer = ((int64_t) getBufferCapacity()) - validFramesInBuffer;
+
+        // Prevent stale data from being played if the DSP is still running.
+        // Erase some of the FIFO memory in front of the DSP read cursor.
+        // Subtract one burst so we do not accidentally erase data that the DSP might be using.
+        int64_t framesToErase = std::max((int64_t) 0,
+                                         emptyFramesInBuffer - getFramesPerBurst());
+        mAudioEndpoint->eraseEmptyDataMemory(framesToErase);
+
+        // Sleep until we are confident the DSP has consumed all of the valid data.
+        // Sleep for one extra burst as a safety margin because the IsochronousClockModel
+        // is not perfectly accurate.
+        int64_t positionInEmptyMemory = getFramesWritten() + getFramesPerBurst();
+        int64_t timeAllConsumed = mClockModel.convertPositionToTime(positionInEmptyMemory);
+        int64_t durationAllConsumed = timeAllConsumed - AudioClock::getNanoseconds();
+        // Prevent sleeping for too long.
+        durationAllConsumed = std::min(200 * AAUDIO_NANOS_PER_MILLISECOND, durationAllConsumed);
+        AudioClock::sleepForNanos(durationAllConsumed);
+    }
+
+    // Erase all of the memory in case the DSP keeps going and wraps around.
+    mAudioEndpoint->eraseDataMemory();
+
+    // Wait for the last buffer to reach the DAC.
+    // This is because the expected behavior of stop() is that all data written to the stream
+    // should be played before the hardware actually shuts down.
+    // This is different than pause(), where we just end as soon as possible.
+    // This can be important when, for example, playing car navigation and
+    // you want the user to hear the complete instruction.
+    if (mAtomicInternalTimestamp.isValid()) {
+        // Use timestamps to calculate the latency between the DSP reading
+        // a frame and when it reaches the DAC.
+        // This code assumes that timestamps are accurate.
+        Timestamp timestamp = mAtomicInternalTimestamp.read();
+        int64_t dacPosition = timestamp.getPosition();
+        int64_t hardwareReadTime = mClockModel.convertPositionToTime(dacPosition);
+        int64_t hardwareLatencyNanos = timestamp.getNanoseconds() - hardwareReadTime;
+        ALOGD("%s() hardwareLatencyNanos = %lld", __func__,
+              (long long) hardwareLatencyNanos);
+        // Prevent sleeping for too long.
+        hardwareLatencyNanos = std::min(30 * AAUDIO_NANOS_PER_MILLISECOND,
+                                        hardwareLatencyNanos);
+        AudioClock::sleepForNanos(hardwareLatencyNanos);
+    }
+}
+
 void AudioStreamInternalPlay::advanceClientToMatchServerPosition(int32_t serverMargin) {
     int64_t readCounter = mAudioEndpoint->getDataReadCounter() + serverMargin;
     int64_t writeCounter = mAudioEndpoint->getDataWriteCounter();
@@ -353,20 +410,26 @@
         // Call application using the AAudio callback interface.
         callbackResult = maybeCallDataCallback(mCallbackBuffer.get(), mCallbackFrames);
 
-        if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
-            // Write audio data to stream. This is a BLOCKING WRITE!
-            result = write(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
-            if ((result != mCallbackFrames)) {
-                if (result >= 0) {
-                    // Only wrote some of the frames requested. The stream can be disconnected
-                    // or timed out.
-                    processCommands();
-                    result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
-                }
-                maybeCallErrorCallback(result);
-                break;
+        // Write audio data to stream. This is a BLOCKING WRITE!
+        // Write data regardless of the callbackResult because we assume the data
+        // is valid even when the callback returns AAUDIO_CALLBACK_RESULT_STOP.
+        // Imagine a callback that is playing a large sound in menory.
+        // When it gets to the end of the sound it can partially fill
+        // the last buffer with the end of the sound, then zero pad the buffer, then return STOP.
+        // If the callback has no valid data then it should zero-fill the entire buffer.
+        result = write(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
+        if ((result != mCallbackFrames)) {
+            if (result >= 0) {
+                // Only wrote some of the frames requested. The stream can be disconnected
+                // or timed out.
+                processCommands();
+                result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
             }
-        } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
+            maybeCallErrorCallback(result);
+            break;
+        }
+
+        if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
             ALOGD("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
             result = systemStopInternal();
             break;
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index b51b5d0..4e14f18 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -66,6 +66,8 @@
 
     void prepareBuffersForStart() override;
 
+    void prepareBuffersForStop() override;
+
     void advanceClientToMatchServerPosition(int32_t serverMargin) override;
 
     void onFlushFromServer() override;
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index 5c11882..f3e3bbd 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -150,7 +150,7 @@
 
     getEmptyRoomAvailable(&wrappingBuffer);
 
-    // Read data in one or two parts.
+    // Write data in one or two parts.
     int partIndex = 0;
     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
         fifo_frames_t framesToWrite = framesLeft;
@@ -192,3 +192,29 @@
         memset(getStorage(), 0, (size_t) numBytes);
     }
 }
+
+fifo_frames_t FifoBuffer::eraseEmptyMemory(fifo_frames_t numFrames) {
+    WrappingBuffer wrappingBuffer;
+    fifo_frames_t framesLeft = numFrames;
+
+    getEmptyRoomAvailable(&wrappingBuffer);
+
+    // Erase data in one or two parts.
+    int partIndex = 0;
+    while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
+        fifo_frames_t framesToWrite = framesLeft;
+        fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+        if (framesAvailable > 0) {
+            if (framesToWrite > framesAvailable) {
+                framesToWrite = framesAvailable;
+            }
+            int32_t numBytes = convertFramesToBytes(framesToWrite);
+            memset(wrappingBuffer.data[partIndex], 0, numBytes);
+            framesLeft -= framesToWrite;
+        } else {
+            break;
+        }
+        partIndex++;
+    }
+    return numFrames - framesLeft; // number erased
+}
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index 7b0aca1..860ccad 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -115,6 +115,13 @@
      */
     void eraseMemory();
 
+    /**
+     * Clear some memory after the write pointer.
+     * This can be used to prevent the reader from accidentally reading stale data
+     * in case it is reading asynchronously.
+     */
+    fifo_frames_t eraseEmptyMemory(fifo_frames_t numFrames);
+
 protected:
 
     virtual uint8_t *getStorage() const = 0;
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 5ec8276..6aa04a8 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -206,9 +206,9 @@
     srcs: ["test_steal_exclusive.cpp"],
     shared_libs: [
         "libaaudio",
-        "liblog",
         "libbinder",
         "libcutils",
+        "liblog",
         "libutils",
     ],
 }
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 90910a1..04a8a45 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -30,14 +30,14 @@
     static_libs: [
         "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
-        "spatializer-aidl-cpp",
         "av-types-aidl-cpp",
+        "spatializer-aidl-cpp",
     ],
     export_static_lib_headers: [
         "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
-        "spatializer-aidl-cpp",
         "av-types-aidl-cpp",
+        "spatializer-aidl-cpp",
     ],
     target: {
         darwin: {
@@ -49,11 +49,11 @@
 cc_library {
     name: "libaudiopolicy",
     srcs: [
-        "VolumeGroupAttributes.cpp",
         "AudioPolicy.cpp",
         "AudioProductStrategy.cpp",
         "AudioVolumeGroup.cpp",
         "PolicyAidlConversion.cpp",
+        "VolumeGroupAttributes.cpp",
     ],
     defaults: [
         "latest_android_media_audio_common_types_cpp_export_shared",
@@ -64,8 +64,9 @@
         "audiopolicy-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
-        "libaudiofoundation",
+        "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
+        "libaudiofoundation",
         "libaudioutils",
         "libbinder",
         "libcutils",
@@ -73,8 +74,8 @@
         "libutils",
     ],
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
     include_dirs: ["system/media/audio_utils/include"],
     export_include_dirs: ["include"],
@@ -84,8 +85,8 @@
         "audiopolicy-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
-        "libaudiofoundation",
         "libaudioclient_aidl_conversion",
+        "libaudiofoundation",
     ],
     header_libs: ["libaudioclient_headers"],
 }
@@ -113,9 +114,9 @@
         "AudioTrack.cpp",
         "AudioTrackShared.cpp",
         "IAudioFlinger.cpp",
-        "ToneGenerator.cpp",
         "PlayerBase.cpp",
         "RecordingActivityTracker.cpp",
+        "ToneGenerator.cpp",
         "TrackPlayerBase.cpp",
     ],
     defaults: [
@@ -126,16 +127,17 @@
         "audioclient-types-aidl-cpp",
         "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
-        "spatializer-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "av-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
+        "com.android.media.audioclient-aconfig-cc",
+        "framework-permission-aidl-cpp",
         "libaudio_aidl_conversion_common_cpp",
         "libaudioclient_aidl_conversion",
         "libaudiofoundation",
-        "libaudioutils",
-        "libaudiopolicy",
         "libaudiomanager",
+        "libaudiopolicy",
+        "libaudioutils",
         "libbinder",
         "libcutils",
         "libdl",
@@ -147,24 +149,24 @@
         "libprocessgroup",
         "libshmemcompat",
         "libutils",
-        "framework-permission-aidl-cpp",
         "packagemanager_aidl-cpp",
+        "spatializer-aidl-cpp",
     ],
     export_shared_lib_headers: [
         "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
-        "spatializer-aidl-cpp",
         "framework-permission-aidl-cpp",
         "libbinder",
         "libmediametrics",
+        "spatializer-aidl-cpp",
     ],
 
     include_dirs: [
         "frameworks/av/media/libnbaio/include_mono/",
     ],
     local_include_dirs: [
-        "include/media",
         "aidl",
+        "include/media",
     ],
     header_libs: [
         "libaudioclient_headers",
@@ -191,8 +193,8 @@
     ],
     sanitize: {
         misc_undefined: [
-            "unsigned-integer-overflow",
             "signed-integer-overflow",
+            "unsigned-integer-overflow",
         ],
     },
 }
@@ -229,8 +231,8 @@
 filegroup {
     name: "libaudioclient_aidl",
     srcs: [
-        "aidl/android/media/IPlayer.aidl",
         "aidl/android/media/AudioHalVersion.aidl",
+        "aidl/android/media/IPlayer.aidl",
     ],
     path: "aidl",
 }
@@ -296,14 +298,14 @@
         "aidl/android/media/AudioIoDescriptor.aidl",
         "aidl/android/media/AudioPatchFw.aidl",
         "aidl/android/media/AudioPolicyConfig.aidl",
-        "aidl/android/media/AudioPortFw.aidl",
-        "aidl/android/media/AudioPortSys.aidl",
         "aidl/android/media/AudioPortConfigFw.aidl",
         "aidl/android/media/AudioPortConfigSys.aidl",
         "aidl/android/media/AudioPortDeviceExtSys.aidl",
         "aidl/android/media/AudioPortExtSys.aidl",
+        "aidl/android/media/AudioPortFw.aidl",
         "aidl/android/media/AudioPortMixExtSys.aidl",
         "aidl/android/media/AudioPortRole.aidl",
+        "aidl/android/media/AudioPortSys.aidl",
         "aidl/android/media/AudioPortType.aidl",
         "aidl/android/media/AudioProfileSys.aidl",
         "aidl/android/media/AudioRoute.aidl",
@@ -312,8 +314,8 @@
         "aidl/android/media/AudioVibratorInfo.aidl",
         "aidl/android/media/DeviceConnectedState.aidl",
         "aidl/android/media/EffectDescriptor.aidl",
-        "aidl/android/media/TrackSecondaryOutputInfo.aidl",
         "aidl/android/media/SurroundSoundConfig.aidl",
+        "aidl/android/media/TrackSecondaryOutputInfo.aidl",
     ],
     defaults: [
         "latest_android_media_audio_common_types_import_interface",
@@ -345,14 +347,14 @@
     srcs: [
         "aidl/android/media/AudioAttributesEx.aidl",
         "aidl/android/media/AudioMix.aidl",
-        "aidl/android/media/AudioMixUpdate.aidl",
-        "aidl/android/media/AudioMixerAttributesInternal.aidl",
-        "aidl/android/media/AudioMixerBehavior.aidl",
         "aidl/android/media/AudioMixCallbackFlag.aidl",
         "aidl/android/media/AudioMixMatchCriterion.aidl",
         "aidl/android/media/AudioMixMatchCriterionValue.aidl",
         "aidl/android/media/AudioMixRouteFlag.aidl",
         "aidl/android/media/AudioMixType.aidl",
+        "aidl/android/media/AudioMixUpdate.aidl",
+        "aidl/android/media/AudioMixerAttributesInternal.aidl",
+        "aidl/android/media/AudioMixerBehavior.aidl",
         "aidl/android/media/AudioOffloadMode.aidl",
         "aidl/android/media/AudioPolicyDeviceState.aidl",
         "aidl/android/media/AudioPolicyForceUse.aidl",
@@ -367,6 +369,7 @@
     ],
     imports: [
         "audioclient-types-aidl",
+        "framework-permission-aidl",
     ],
     backend: {
         cpp: {
@@ -401,8 +404,8 @@
         "aidl/android/media/OpenOutputResponse.aidl",
         "aidl/android/media/RenderPosition.aidl",
 
-        "aidl/android/media/IAudioFlingerService.aidl",
         "aidl/android/media/IAudioFlingerClient.aidl",
+        "aidl/android/media/IAudioFlingerService.aidl",
         "aidl/android/media/IAudioRecord.aidl",
         "aidl/android/media/IAudioTrack.aidl",
         "aidl/android/media/IAudioTrackCallback.aidl",
@@ -418,8 +421,8 @@
         "audioclient-types-aidl",
         "av-types-aidl",
         "effect-aidl",
-        "shared-file-region-aidl",
         "framework-permission-aidl",
+        "shared-file-region-aidl",
     ],
     double_loadable: true,
     backend: {
@@ -446,9 +449,9 @@
         "aidl/android/media/GetInputForAttrResponse.aidl",
         "aidl/android/media/GetOutputForAttrResponse.aidl",
         "aidl/android/media/GetSpatializerResponse.aidl",
-        "aidl/android/media/RecordClientInfo.aidl",
         "aidl/android/media/IAudioPolicyService.aidl",
         "aidl/android/media/IAudioPolicyServiceClient.aidl",
+        "aidl/android/media/RecordClientInfo.aidl",
     ],
     defaults: [
         "latest_android_media_audio_common_types_import_interface",
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index a71bb18..441e329 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -243,6 +243,7 @@
     legacy.mAllowPrivilegedMediaPlaybackCapture = aidl.allowPrivilegedMediaPlaybackCapture;
     legacy.mVoiceCommunicationCaptureAllowed = aidl.voiceCommunicationCaptureAllowed;
     legacy.mToken = aidl.mToken;
+    legacy.mVirtualDeviceId = aidl.mVirtualDeviceId;
     return legacy;
 }
 
@@ -267,6 +268,7 @@
     aidl.allowPrivilegedMediaPlaybackCapture = legacy.mAllowPrivilegedMediaPlaybackCapture;
     aidl.voiceCommunicationCaptureAllowed = legacy.mVoiceCommunicationCaptureAllowed;
     aidl.mToken = legacy.mToken;
+    aidl.mVirtualDeviceId = legacy.mVirtualDeviceId;
     return aidl;
 }
 
diff --git a/media/libaudioclient/aidl/android/media/AudioMix.aidl b/media/libaudioclient/aidl/android/media/AudioMix.aidl
index f0c561c..bb8537d 100644
--- a/media/libaudioclient/aidl/android/media/AudioMix.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioMix.aidl
@@ -41,4 +41,6 @@
     boolean voiceCommunicationCaptureAllowed;
     /** Identifies the owner of the AudioPolicy that this AudioMix belongs to */
     IBinder mToken;
+    /** Indicates the Id of the VirtualDevice this AudioMix was registered for */
+    int mVirtualDeviceId;
 }
diff --git a/media/libaudioclient/aidl/fuzzer/Android.bp b/media/libaudioclient/aidl/fuzzer/Android.bp
index 02c5a3f..6cfccd6 100644
--- a/media/libaudioclient/aidl/fuzzer/Android.bp
+++ b/media/libaudioclient/aidl/fuzzer/Android.bp
@@ -22,44 +22,45 @@
     name: "libaudioclient_aidl_fuzzer_defaults",
     static_libs: [
         "android.hardware.audio.common@7.0-enums",
-        "effect-aidl-cpp",
+        "libaudiomockhal",
         "libcgrouprc",
         "libcgrouprc_format",
         "libfakeservicemanager",
         "libjsoncpp",
         "liblog",
-        "libmediametricsservice",
         "libmedia_helper",
+        "libmediametricsservice",
         "libprocessgroup",
         "shared-file-region-aidl-cpp",
     ],
     shared_libs: [
         "android.hardware.audio.common-util",
         "audioclient-types-aidl-cpp",
+        "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "av-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
+        "effect-aidl-cpp",
         "framework-permission-aidl-cpp",
+        "libactivitymanager_aidl",
         "libaudioclient",
-        "audioflinger-aidl-cpp",
-        "libaudioflinger",
         "libaudioclient_aidl_conversion",
+        "libaudioflinger",
         "libaudiofoundation",
+        "libaudiohal",
         "libaudiomanager",
         "libaudiopolicy",
-        "libaudioutils",
-        "libaudiopolicyservice",
         "libaudiopolicymanagerdefault",
-        "libaudiohal",
+        "libaudiopolicyservice",
         "libaudioprocessing",
-        "libactivitymanager_aidl",
+        "libaudioutils",
         "libdl",
         "libheadtracking",
-        "libmediautils",
         "libmediametrics",
-        "libnblog",
+        "libmediautils",
         "libnbaio",
+        "libnblog",
         "libpowermanager",
         "libvibrator",
         "libvndksupport",
@@ -68,10 +69,10 @@
         "packagemanager_aidl-cpp",
     ],
     header_libs: [
-        "libaudiopolicymanager_interface_headers",
+        "libaudioflinger_headers",
         "libaudiofoundation_headers",
         "libaudiohal_headers",
-        "libaudioflinger_headers",
+        "libaudiopolicymanager_interface_headers",
         "libbinder_headers",
         "libmedia_headers",
     ],
@@ -93,6 +94,9 @@
     name: "audioflinger_aidl_fuzzer",
     srcs: ["audioflinger_aidl_fuzzer.cpp"],
     defaults: [
+        "latest_android_hardware_audio_core_ndk_shared",
+        "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
         "libaudioclient_aidl_fuzzer_defaults",
         "service_fuzzer_defaults",
     ],
diff --git a/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
index f99cc3b..5e4f9a1 100644
--- a/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
+++ b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
@@ -17,8 +17,12 @@
 #include <AudioFlinger.h>
 #include <android-base/logging.h>
 #include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <android/media/IAudioPolicyService.h>
+#include <core-mock/ConfigMock.h>
+#include <core-mock/ModuleMock.h>
+#include <effect-mock/FactoryMock.h>
 #include <fakeservicemanager/FakeServiceManager.h>
 #include <fuzzbinder/libbinder_driver.h>
 #include <fuzzbinder/random_binder.h>
@@ -53,14 +57,26 @@
     });
     gFakeServiceManager->clear();
 
-    for (const char* service :
-         {"activity", "sensor_privacy", "permission", "scheduling_policy",
-          "android.hardware.audio.core.IConfig", "batterystats", "media.metrics"}) {
+    for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
+                                "batterystats", "media.metrics"}) {
         if (!addService(String16(service), gFakeServiceManager, fdp)) {
             return 0;
         }
     }
 
+    auto configService = ndk::SharedRefBase::make<ConfigMock>();
+    CHECK_EQ(NO_ERROR, AServiceManager_addService(configService.get()->asBinder().get(),
+                                                  "android.hardware.audio.core.IConfig/default"));
+
+    auto factoryService = ndk::SharedRefBase::make<FactoryMock>();
+    CHECK_EQ(NO_ERROR,
+             AServiceManager_addService(factoryService.get()->asBinder().get(),
+                                        "android.hardware.audio.effect.IFactory/default"));
+
+    auto moduleService = ndk::SharedRefBase::make<ModuleMock>();
+    CHECK_EQ(NO_ERROR, AServiceManager_addService(moduleService.get()->asBinder().get(),
+                                                  "android.hardware.audio.core.IModule/default"));
+
     const auto audioFlinger = sp<AudioFlinger>::make();
     const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
 
@@ -77,12 +93,7 @@
                                              false /* allowIsolated */,
                                              IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
 
-    sp<IBinder> audioFlingerServiceBinder =
-            gFakeServiceManager->getService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME));
-    sp<media::IAudioFlingerService> audioFlingerService =
-            interface_cast<media::IAudioFlingerService>(audioFlingerServiceBinder);
-
-    fuzzService(media::IAudioFlingerService::asBinder(audioFlingerService), std::move(fdp));
+    fuzzService(media::IAudioFlingerService::asBinder(afAdapter), std::move(fdp));
 
     return 0;
 }
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/Android.bp b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/Android.bp
new file mode 100644
index 0000000..c4afffb
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_library {
+    name: "libaudiomockhal",
+
+    defaults: [
+        "latest_android_hardware_audio_core_ndk_shared",
+        "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    header_libs: [
+        "libbinder_headers",
+    ],
+    static_libs: [
+        "libbinder_random_parcel",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+
+    host_supported: true,
+    srcs: [
+        "FactoryMock.cpp",
+        "ModuleMock.cpp",
+        "StreamInMock.cpp",
+        "StreamOutMock.cpp",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    export_include_dirs: ["include"],
+}
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/FactoryMock.cpp b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/FactoryMock.cpp
new file mode 100644
index 0000000..ea07afc
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/FactoryMock.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "effect-mock/FactoryMock.h"
+#include "effect-mock/EffectMock.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus FactoryMock::createEffect(const AudioUuid&,
+                                             std::shared_ptr<IEffect>* _aidl_return) {
+    *_aidl_return = ndk::SharedRefBase::make<EffectMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/ModuleMock.cpp b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/ModuleMock.cpp
new file mode 100644
index 0000000..711924f
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/ModuleMock.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "core-mock/ModuleMock.h"
+#include "core-mock/BluetoothA2dpMock.h"
+#include "core-mock/BluetoothLeMock.h"
+#include "core-mock/BluetoothMock.h"
+#include "core-mock/StreamInMock.h"
+#include "core-mock/StreamOutMock.h"
+#include "core-mock/TelephonyMock.h"
+#include "sounddose-mock/SoundDoseMock.h"
+
+namespace aidl::android::hardware::audio::core {
+
+ModuleMock::ModuleMock() {
+    // Device ports
+    auto outDevice = createPort(/* PortId */ 0, /* Name */ "Default",
+                                /* Flags */ 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE,
+                                /* isInput */ false,
+                                createDeviceExt(
+                                        /* DeviceType */ AudioDeviceType::OUT_DEFAULT,
+                                        /* Flags */ AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
+    mPorts.push_back(outDevice);
+    auto inDevice = createPort(/* PortId */ 1, /* Name */ "Default",
+                               /* Flags */ 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE,
+                               /* isInput */ true,
+                               createDeviceExt(
+                                       /* DeviceType */ AudioDeviceType::IN_DEFAULT,
+                                       /* Flags */ 0));
+    mPorts.push_back(outDevice);
+}
+
+ndk::ScopedAStatus ModuleMock::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+    *_aidl_return = ndk::SharedRefBase::make<TelephonyMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
+    *_aidl_return = ndk::SharedRefBase::make<BluetoothMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
+    *_aidl_return = ndk::SharedRefBase::make<BluetoothA2dpMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
+    *_aidl_return = ndk::SharedRefBase::make<BluetoothLeMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::openInputStream(const OpenInputStreamArguments&,
+                                               OpenInputStreamReturn* _aidl_return) {
+    _aidl_return->stream = ndk::SharedRefBase::make<StreamInMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::openOutputStream(const OpenOutputStreamArguments&,
+                                                OpenOutputStreamReturn* _aidl_return) {
+    _aidl_return->stream = ndk::SharedRefBase::make<StreamOutMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getMasterMute(bool* _aidl_return) {
+    *_aidl_return = mMasterMute;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::setMasterMute(bool masterMute) {
+    mMasterMute = masterMute;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getMasterVolume(float* _aidl_return) {
+    *_aidl_return = mMasterVolume;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::setMasterVolume(float masterVolume) {
+    mMasterVolume = masterVolume;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getMicMute(bool* _aidl_return) {
+    *_aidl_return = mMicMute;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::setMicMute(bool micMute) {
+    mMicMute = micMute;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) {
+    *_aidl_return = ndk::SharedRefBase::make<SoundDoseMock>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::getMmapPolicyInfos(AudioMMapPolicyType,
+                                                  std::vector<AudioMMapPolicyInfo>* _aidl_return) {
+    AudioMMapPolicyInfo never;
+    never.mmapPolicy = AudioMMapPolicy::NEVER;
+    _aidl_return->push_back(never);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleMock::supportsVariableLatency(bool* _aidl_return) {
+    *_aidl_return = false;
+    return ndk::ScopedAStatus::ok();
+}
+
+AudioPortExt ModuleMock::createDeviceExt(AudioDeviceType devType, int32_t flags) {
+    AudioPortDeviceExt deviceExt;
+    deviceExt.device.type.type = devType;
+    deviceExt.flags = flags;
+    return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
+}
+
+AudioPort ModuleMock::createPort(int32_t id, const std::string& name, int32_t flags, bool isInput,
+                                 const AudioPortExt& ext) {
+    AudioPort port;
+    port.id = id;
+    port.name = name;
+    port.flags = isInput ? AudioIoFlags::make<AudioIoFlags::Tag::input>(flags)
+                         : AudioIoFlags::make<AudioIoFlags::Tag::output>(flags);
+    port.ext = ext;
+    return port;
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/StreamInMock.cpp b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/StreamInMock.cpp
new file mode 100644
index 0000000..093a979
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/StreamInMock.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "core-mock/StreamInMock.h"
+#include "core-mock/StreamCommonMock.h"
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus StreamInMock::getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) {
+    if (!mStreamCommon) {
+        mStreamCommon = ndk::SharedRefBase::make<StreamCommonMock>();
+    }
+    *_aidl_return = mStreamCommon;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInMock::getMicrophoneDirection(
+        IStreamIn::MicrophoneDirection* _aidl_return) {
+    *_aidl_return = mMicrophoneDirection;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInMock::setMicrophoneDirection(
+        IStreamIn::MicrophoneDirection in_direction) {
+    mMicrophoneDirection = in_direction;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInMock::getMicrophoneFieldDimension(float* _aidl_return) {
+    *_aidl_return = mMicrophoneFieldDimension;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInMock::setMicrophoneFieldDimension(float in_zoom) {
+    mMicrophoneFieldDimension = in_zoom;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInMock::getHwGain(std::vector<float>* _aidl_return) {
+    *_aidl_return = mHwGains;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInMock::setHwGain(const std::vector<float>& in_channelGains) {
+    mHwGains = in_channelGains;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/StreamOutMock.cpp b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/StreamOutMock.cpp
new file mode 100644
index 0000000..a71f954
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/StreamOutMock.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "core-mock/StreamOutMock.h"
+#include "core-mock/StreamCommonMock.h"
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus StreamOutMock::getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) {
+    if (!mStreamCommon) {
+        mStreamCommon = ndk::SharedRefBase::make<StreamCommonMock>();
+    }
+    *_aidl_return = mStreamCommon;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamOutMock::getHwVolume(std::vector<float>* _aidl_return) {
+    *_aidl_return = mHwVolume;
+    return ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus StreamOutMock::setHwVolume(const std::vector<float>& in_channelVolumes) {
+    mHwVolume = in_channelVolumes;
+    return ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus StreamOutMock::getAudioDescriptionMixLevel(float* _aidl_return) {
+    *_aidl_return = mAudioDescriptionMixLeveldB;
+    return ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus StreamOutMock::setAudioDescriptionMixLevel(float in_leveldB) {
+    mAudioDescriptionMixLeveldB = in_leveldB;
+    return ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus StreamOutMock::getDualMonoMode(AudioDualMonoMode* _aidl_return) {
+    *_aidl_return = mDualMonoMode;
+    return ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus StreamOutMock::setDualMonoMode(AudioDualMonoMode in_mode) {
+    mDualMonoMode = in_mode;
+    return ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus StreamOutMock::getPlaybackRateParameters(AudioPlaybackRate* _aidl_return) {
+    *_aidl_return = mPlaybackRateParameters;
+    return ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus StreamOutMock::setPlaybackRateParameters(
+        const AudioPlaybackRate& in_playbackRate) {
+    mPlaybackRateParameters = in_playbackRate;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothA2dpMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothA2dpMock.h
new file mode 100644
index 0000000..c4dd0d9
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothA2dpMock.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnBluetoothA2dp.h>
+
+using namespace aidl::android::hardware::audio::core;
+
+namespace aidl::android::hardware::audio::core {
+
+class BluetoothA2dpMock : public BnBluetoothA2dp {
+  public:
+    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override {
+        *_aidl_return = mEnabled;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setEnabled(bool enabled) override {
+        mEnabled = enabled;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override {
+        *_aidl_return = kSupportsOffloadReconfiguration;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus reconfigureOffload(const std::vector<VendorParameter>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    static constexpr bool kSupportsOffloadReconfiguration = true;
+    bool mEnabled = false;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothLeMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothLeMock.h
new file mode 100644
index 0000000..d58695a
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothLeMock.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnBluetoothLe.h>
+
+using namespace aidl::android::hardware::audio::core;
+
+namespace aidl::android::hardware::audio::core {
+
+class BluetoothLeMock : public BnBluetoothLe {
+  public:
+    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override {
+        *_aidl_return = mEnabled;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setEnabled(bool enabled) override {
+        mEnabled = enabled;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override {
+        *_aidl_return = kSupportsOffloadReconfiguration;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus reconfigureOffload(const std::vector<VendorParameter>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    static constexpr bool kSupportsOffloadReconfiguration = true;
+    bool mEnabled = false;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothMock.h
new file mode 100644
index 0000000..e805840
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/BluetoothMock.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnBluetooth.h>
+
+using namespace aidl::android::hardware::audio::core;
+
+namespace aidl::android::hardware::audio::core {
+
+class BluetoothMock : public BnBluetooth {
+  public:
+    ndk::ScopedAStatus setScoConfig(const IBluetooth::ScoConfig&, IBluetooth::ScoConfig*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setHfpConfig(const IBluetooth::HfpConfig&, IBluetooth::HfpConfig*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/ConfigMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/ConfigMock.h
new file mode 100644
index 0000000..f4031b5
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/ConfigMock.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnConfig.h>
+
+using namespace aidl::android::media::audio::common;
+using namespace aidl::android::hardware::audio::core;
+
+namespace aidl::android::hardware::audio::core {
+
+class ConfigMock : public BnConfig {
+  private:
+    ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getEngineConfig(AudioHalEngineConfig*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/ModuleMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/ModuleMock.h
new file mode 100644
index 0000000..d49203d
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/ModuleMock.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnModule.h>
+
+using namespace aidl::android::media::audio::common;
+using namespace aidl::android::hardware::audio::core;
+using namespace aidl::android::hardware::audio::core::sounddose;
+using namespace aidl::android::hardware::audio::effect;
+
+namespace aidl::android::hardware::audio::core {
+
+class ModuleMock : public BnModule {
+  public:
+    ModuleMock();
+
+  private:
+    ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>*) override;
+    ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>*) override;
+    ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>*) override;
+    ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>*) override;
+    ndk::ScopedAStatus openInputStream(const OpenInputStreamArguments&,
+                                       OpenInputStreamReturn*) override;
+    ndk::ScopedAStatus openOutputStream(const OpenOutputStreamArguments&,
+                                        OpenOutputStreamReturn*) override;
+    ndk::ScopedAStatus getMasterMute(bool*) override;
+    ndk::ScopedAStatus setMasterMute(bool) override;
+    ndk::ScopedAStatus getMasterVolume(float*) override;
+    ndk::ScopedAStatus setMasterVolume(float) override;
+    ndk::ScopedAStatus getMicMute(bool*) override;
+    ndk::ScopedAStatus setMicMute(bool) override;
+    ndk::ScopedAStatus getSoundDose(std::shared_ptr<ISoundDose>*) override;
+    ndk::ScopedAStatus getMmapPolicyInfos(AudioMMapPolicyType,
+                                          std::vector<AudioMMapPolicyInfo>*) override;
+    ndk::ScopedAStatus supportsVariableLatency(bool*) override;
+
+    ndk::ScopedAStatus setModuleDebug(const ModuleDebug&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus connectExternalDevice(const AudioPort&, AudioPort*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus disconnectExternalDevice(int32_t) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getAudioPort(int32_t, AudioPort*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getAudioPortConfigs(std::vector<AudioPortConfig>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getAudioPorts(std::vector<AudioPort>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getAudioRoutes(std::vector<AudioRoute>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getAudioRoutesForAudioPort(int32_t, std::vector<AudioRoute>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getSupportedPlaybackRateFactors(SupportedPlaybackRateFactors*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setAudioPatch(const AudioPatch&, AudioPatch*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setAudioPortConfig(const AudioPortConfig&, AudioPortConfig*,
+                                          bool*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus resetAudioPatch(int32_t) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus resetAudioPortConfig(int32_t) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus getMicrophones(std::vector<MicrophoneInfo>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus updateAudioMode(AudioMode) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus updateScreenRotation(ScreenRotation) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus updateScreenState(bool) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus generateHwAvSyncId(int32_t*) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>&,
+                                           std::vector<VendorParameter>*) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>&, bool) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus addDeviceEffect(int32_t, const std::shared_ptr<IEffect>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus removeDeviceEffect(int32_t, const std::shared_ptr<IEffect>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t*) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t*) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus prepareToDisconnectExternalDevice(int32_t) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags);
+    AudioPort createPort(int32_t id, const std::string& name, int32_t flags, bool isInput,
+                         const AudioPortExt& ext);
+
+    bool mMasterMute;
+    float mMasterVolume;
+    bool mMicMute;
+    std::vector<AudioPort> mPorts;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamCommonMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamCommonMock.h
new file mode 100644
index 0000000..25d53f8
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamCommonMock.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnStreamCommon.h>
+
+using namespace aidl::android::hardware::audio::core;
+using namespace aidl::android::hardware::audio::effect;
+
+namespace aidl::android::hardware::audio::core {
+
+class StreamCommonMock : public BnStreamCommon {
+    ndk::ScopedAStatus close() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus prepareToClose() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus updateHwAvSyncId(int32_t) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>&,
+                                           std::vector<VendorParameter>*) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>&, bool) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus addEffect(const std::shared_ptr<IEffect>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus removeEffect(const std::shared_ptr<IEffect>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamInMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamInMock.h
new file mode 100644
index 0000000..5deab5b
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamInMock.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnStreamIn.h>
+
+using namespace aidl::android::hardware::audio::common;
+using namespace aidl::android::hardware::audio::core;
+using namespace aidl::android::media::audio::common;
+
+namespace aidl::android::hardware::audio::core {
+
+class StreamInMock : public BnStreamIn {
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override;
+    ndk::ScopedAStatus getMicrophoneDirection(
+            IStreamIn::MicrophoneDirection* _aidl_return) override;
+    ndk::ScopedAStatus setMicrophoneDirection(IStreamIn::MicrophoneDirection in_direction) override;
+    ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override;
+    ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
+    ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
+
+    ndk::ScopedAStatus getActiveMicrophones(std::vector<MicrophoneDynamicInfo>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus updateMetadata(const SinkMetadata&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    IStreamIn::MicrophoneDirection mMicrophoneDirection;
+    float mMicrophoneFieldDimension;
+    std::vector<float> mHwGains;
+    std::shared_ptr<IStreamCommon> mStreamCommon;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamOutMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamOutMock.h
new file mode 100644
index 0000000..4d12815
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/StreamOutMock.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnStreamOut.h>
+
+using namespace aidl::android::hardware::audio::common;
+using namespace aidl::android::hardware::audio::core;
+using namespace aidl::android::media::audio::common;
+
+namespace aidl::android::hardware::audio::core {
+
+class StreamOutMock : public BnStreamOut {
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override;
+    ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+    ndk::ScopedAStatus getAudioDescriptionMixLevel(float* _aidl_return) override;
+    ndk::ScopedAStatus setAudioDescriptionMixLevel(float in_leveldB) override;
+    ndk::ScopedAStatus getDualMonoMode(AudioDualMonoMode* _aidl_return) override;
+    ndk::ScopedAStatus setDualMonoMode(AudioDualMonoMode in_mode) override;
+    ndk::ScopedAStatus getPlaybackRateParameters(AudioPlaybackRate* _aidl_return) override;
+    ndk::ScopedAStatus setPlaybackRateParameters(const AudioPlaybackRate& in_playbackRate) override;
+
+    ndk::ScopedAStatus updateMetadata(const SourceMetadata&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus updateOffloadMetadata(const AudioOffloadMetadata&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getRecommendedLatencyModes(std::vector<AudioLatencyMode>*) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus setLatencyMode(AudioLatencyMode) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    ndk::ScopedAStatus selectPresentation(int32_t, int32_t) override {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+
+  private:
+    AudioPlaybackRate mPlaybackRateParameters;
+    AudioDualMonoMode mDualMonoMode;
+    float mAudioDescriptionMixLeveldB;
+    std::vector<float> mHwVolume;
+    std::shared_ptr<IStreamCommon> mStreamCommon;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/TelephonyMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/TelephonyMock.h
new file mode 100644
index 0000000..d56dee6
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/core-mock/TelephonyMock.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/BnTelephony.h>
+
+using namespace aidl::android::hardware::audio::core;
+using namespace aidl::android::media::audio::common;
+
+namespace aidl::android::hardware::audio::core {
+
+class TelephonyMock : public BnTelephony {
+  public:
+    ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus switchAudioMode(AudioMode) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus setTelecomConfig(const ITelephony::TelecomConfig&,
+                                        ITelephony::TelecomConfig*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/effect-mock/EffectMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/effect-mock/EffectMock.h
new file mode 100644
index 0000000..db20cd8
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/effect-mock/EffectMock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+
+using namespace aidl::android::hardware::audio::effect;
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectMock : public BnEffect {
+  public:
+    ndk::ScopedAStatus open(const Parameter::Common&, const std::optional<Parameter::Specific>&,
+                            IEffect::OpenEffectReturn*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus close() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus command(CommandId) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus getState(State*) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus getDescriptor(Descriptor*) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus reopen(IEffect::OpenEffectReturn*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setParameter(const Parameter&) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus getParameter(const Parameter::Id&, Parameter*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/effect-mock/FactoryMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/effect-mock/FactoryMock.h
new file mode 100644
index 0000000..57d58d5
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/effect-mock/FactoryMock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/effect/BnFactory.h>
+
+using namespace aidl::android::media::audio::common;
+using namespace aidl::android::hardware::audio::effect;
+
+namespace aidl::android::hardware::audio::effect {
+
+class FactoryMock : public BnFactory {
+    ndk::ScopedAStatus queryEffects(const std::optional<AudioUuid>&,
+                                    const std::optional<AudioUuid>&,
+                                    const std::optional<AudioUuid>&,
+                                    std::vector<Descriptor>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus queryProcessing(const std::optional<Processing::Type>&,
+                                       std::vector<Processing>*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus destroyEffect(const std::shared_ptr<IEffect>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus createEffect(const AudioUuid&, std::shared_ptr<IEffect>*) override;
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/sounddose-mock/SoundDoseMock.h b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/sounddose-mock/SoundDoseMock.h
new file mode 100644
index 0000000..5557b10
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/libaudiomockhal/include/sounddose-mock/SoundDoseMock.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
+
+using namespace aidl::android::hardware::audio::core::sounddose;
+
+namespace aidl::android::hardware::audio::core::sounddose {
+
+class SoundDoseMock : public BnSoundDose {
+    ndk::ScopedAStatus setOutputRs2UpperBound(float in_rs2ValueDbA) override {
+        mOutputRs2UpperBound = in_rs2ValueDbA;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus getOutputRs2UpperBound(float* _aidl_return) override {
+        *_aidl_return = mOutputRs2UpperBound;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus registerSoundDoseCallback(
+            const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    float mOutputRs2UpperBound;
+};
+
+}  // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index f2ad91c..a95c700 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -42,9 +42,9 @@
         "libcutils",
         "libjsoncpp",
         "liblog",
+        "libmedia_helper",
         "libmediametrics",
         "libmediametricsservice",
-        "libmedia_helper",
         "libprocessgroup",
         "shared-file-region-aidl-cpp",
     ],
@@ -56,8 +56,9 @@
         "audiopolicy-types-aidl-cpp",
         "av-types-aidl-cpp",
         "capture_state_listener-aidl-cpp",
-        "libaudioclient_aidl_conversion",
+        "framework-permission-aidl-cpp",
         "libaudio_aidl_conversion_common_cpp",
+        "libaudioclient_aidl_conversion",
         "libaudioflinger",
         "libaudiofoundation",
         "libaudiomanager",
@@ -70,7 +71,6 @@
         "libutils",
         "libxml2",
         "mediametricsservice-aidl-cpp",
-        "framework-permission-aidl-cpp",
     ],
     header_libs: [
         "libaudiofoundation_headers",
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index 9e4ae54..b190fba 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -129,6 +129,7 @@
     String8         mDeviceAddress;
     uint32_t        mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
     sp<IBinder>     mToken;
+    uint32_t        mVirtualDeviceId;
     /** Ignore the AUDIO_FLAG_NO_MEDIA_PROJECTION */
     bool            mAllowPrivilegedMediaPlaybackCapture = false;
     /** Indicates if the caller can capture voice communication output */
diff --git a/media/libaudioclient/include/media/EffectClientAsyncProxy.h b/media/libaudioclient/include/media/EffectClientAsyncProxy.h
new file mode 100644
index 0000000..e7d6d80
--- /dev/null
+++ b/media/libaudioclient/include/media/EffectClientAsyncProxy.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/media/BnEffectClient.h>
+#include <audio_utils/CommandThread.h>
+
+namespace android::media {
+
+class EffectClientAsyncProxy : public IEffectClient {
+public:
+
+    /**
+     * Call this factory method to interpose a worker thread when a binder
+     * callback interface is invoked in-proc.
+     */
+    static sp<IEffectClient> makeIfNeeded(const sp<IEffectClient>& effectClient) {
+        if (isLocalBinder(effectClient)) {
+            return sp<EffectClientAsyncProxy>::make(effectClient);
+        }
+        return effectClient;
+    }
+
+    explicit EffectClientAsyncProxy(const sp<IEffectClient>& effectClient)
+        : mEffectClient(effectClient) {}
+
+    ::android::IBinder* onAsBinder() override {
+        return nullptr;
+    }
+
+    ::android::binder::Status controlStatusChanged(bool controlGranted) override {
+        getThread().add(__func__, [=, effectClient = mEffectClient]() {
+            effectClient->controlStatusChanged(controlGranted);
+        });
+        return ::android::binder::Status::fromStatusT(::android::NO_ERROR);
+    }
+
+    ::android::binder::Status enableStatusChanged(bool enabled) override {
+        getThread().add(__func__, [=, effectClient = mEffectClient]() {
+            effectClient->enableStatusChanged(enabled);
+        });
+        return ::android::binder::Status::fromStatusT(::android::NO_ERROR);
+    }
+
+    ::android::binder::Status commandExecuted(
+            int32_t cmdCode, const ::std::vector<uint8_t>& cmdData,
+            const ::std::vector<uint8_t>& replyData) override {
+        getThread().add(__func__, [=, effectClient = mEffectClient]() {
+            effectClient->commandExecuted(cmdCode, cmdData, replyData);
+        });
+        return ::android::binder::Status::fromStatusT(::android::NO_ERROR);
+    }
+
+    ::android::binder::Status framesProcessed(int32_t frames) override {
+        getThread().add(__func__, [=, effectClient = mEffectClient]() {
+            effectClient->framesProcessed(frames);
+        });
+        return ::android::binder::Status::fromStatusT(::android::NO_ERROR);
+    }
+
+    /**
+     * Returns true if the binder interface is local (in-proc).
+     *
+     * Move to a binder helper class?
+     */
+    static bool isLocalBinder(const sp<IInterface>& interface) {
+        const auto b = IInterface::asBinder(interface);
+        return b && b->localBinder();
+    }
+
+private:
+    const sp<IEffectClient> mEffectClient;
+
+    /**
+     * Returns the per-interface-descriptor CommandThread for in-proc binder transactions.
+     *
+     * Note: Remote RPC transactions to a given binder (kernel) node enter that node's
+     * async_todo list, which serializes all async operations to that binder node.
+     * Each transaction on the async_todo list must complete before the next one
+     * starts, even though there may be available threads in the process threadpool.
+     *
+     * For local transactions, we order all async requests entering
+     * the CommandThread.  We do not maintain a threadpool, though a future implementation
+     * could use a shared ThreadPool.
+     *
+     * By using a static here, all in-proc binder interfaces made async with
+     * EffectClientAsyncProxy will get the same CommandThread.
+     *
+     * @return CommandThread to use.
+     */
+    static audio_utils::CommandThread& getThread() {
+        [[clang::no_destroy]] static audio_utils::CommandThread commandThread;
+        return commandThread;
+    }
+};  // class EffectClientAsyncProxy
+
+}  // namespace android::media
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index b667c8d..055da5b 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -23,8 +23,8 @@
     ],
     sanitize: {
         misc_undefined: [
-            "unsigned-integer-overflow",
             "signed-integer-overflow",
+            "unsigned-integer-overflow",
         ],
     },
 }
@@ -32,8 +32,8 @@
 cc_defaults {
     name: "audio_aidl_conversion_test_defaults",
     defaults: [
-        "libaudioclient_tests_defaults",
         "latest_android_media_audio_common_types_cpp_static",
+        "libaudioclient_tests_defaults",
     ],
     static_libs: [
         "audioclient-types-aidl-cpp",
@@ -110,9 +110,9 @@
         "libcgrouprc",
         "libdl",
         "libmedia",
+        "libmedia_helper",
         "libmediametrics",
         "libmediautils",
-        "libmedia_helper",
         "libnblog",
         "libprocessgroup",
         "libshmemcompat",
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index c758fcd..576406d 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -87,7 +87,7 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 }
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
index 82c7db7..0ca50ab 100644
--- a/media/libaudiofoundation/tests/Android.bp
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -22,8 +22,8 @@
 
     static_libs: [
         "audioclient-types-aidl-cpp",
-        "libaudioclient_aidl_conversion",
         "libaudio_aidl_conversion_common_cpp",
+        "libaudioclient_aidl_conversion",
         "libaudiofoundation",
         "libstagefright_foundation",
     ],
@@ -37,8 +37,8 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     test_suites: ["device-tests"],
@@ -64,8 +64,8 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     test_suites: ["device-tests"],
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index b8d0998..639c7aa 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -18,8 +18,8 @@
 
     cflags: [
         "-Wall",
-        "-Wextra",
         "-Werror",
+        "-Wextra",
     ],
 
     required: [
@@ -44,7 +44,7 @@
         "libbase_headers",
         "liberror_headers",
         "libmediautils_headers",
-    ]
+    ],
 }
 
 cc_library_shared {
@@ -61,12 +61,12 @@
 
     shared_libs: [
         "libhidlbase",
-        "libutils",
         "liblog",
+        "libutils",
     ],
 
     header_libs: [
-        "libaudiohal_headers"
+        "libaudiohal_headers",
     ],
 }
 
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index 4d81f77..c7fa96e 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -49,8 +49,8 @@
 
     cflags: [
         "-Wall",
-        "-Wextra",
         "-Werror",
+        "-Wextra",
         "-fvisibility=hidden",
     ],
     shared_libs: [
@@ -211,10 +211,10 @@
         "libbinder_ndk",
     ],
     cflags: [
-        "-DMAJOR_VERSION=7",
-        "-DMINOR_VERSION=1",
         "-DCOMMON_TYPES_MINOR_VERSION=0",
         "-DCORE_TYPES_MINOR_VERSION=0",
+        "-DMAJOR_VERSION=7",
+        "-DMINOR_VERSION=1",
         "-include common/all-versions/VersionMacro.h",
     ],
 }
@@ -245,25 +245,25 @@
         "libeffectsconfig_headers",
     ],
     cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wthread-safety",
         "-DBACKEND_CPP_NDK",
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wthread-safety",
     ],
 }
 
 cc_library_shared {
     name: "libaudiohal@aidl",
     defaults: [
-        "libaudiohal_default",
         "libaudiohal_aidl_default",
+        "libaudiohal_default",
     ],
     srcs: [
-        "DevicesFactoryHalEntry.cpp",
-        "EffectsFactoryHalEntry.cpp",
         ":audio_effect_hal_aidl_src_files",
         ":core_audio_hal_aidl_src_files",
+        "DevicesFactoryHalEntry.cpp",
+        "EffectsFactoryHalEntry.cpp",
     ],
 }
 
@@ -281,8 +281,9 @@
 filegroup {
     name: "audio_effect_hal_aidl_src_files",
     srcs: [
-        "EffectConversionHelperAidl.cpp",
+        ":audio_effectproxy_src_files",
         "EffectBufferHalAidl.cpp",
+        "EffectConversionHelperAidl.cpp",
         "EffectHalAidl.cpp",
         "EffectsFactoryHalAidl.cpp",
         "effectsAidlConversion/AidlConversionAec.cpp",
@@ -301,7 +302,6 @@
         "effectsAidlConversion/AidlConversionVendorExtension.cpp",
         "effectsAidlConversion/AidlConversionVirtualizer.cpp",
         "effectsAidlConversion/AidlConversionVisualizer.cpp",
-        ":audio_effectproxy_src_files",
     ],
 }
 
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 478e0f0..ea4258c 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -752,10 +752,14 @@
     // the attributes reported by `getParameters` API.
     struct audio_port_v7 temp = *devicePort;
     AudioProfileAttributesMultimap attrsFromDevice;
-    status_t status = getAudioPort(&temp);
-    if (status == NO_ERROR) {
-        attrsFromDevice = createAudioProfilesAttrMap(temp.audio_profiles, 0 /*first*/,
-                                                     temp.num_audio_profiles);
+    bool supportsPatches;
+    if (supportsAudioPatches(&supportsPatches) == OK && supportsPatches) {
+        // The audio patches are supported since HAL 3.0, which is the same HAL version
+        // requirement for 'getAudioPort' API.
+        if (getAudioPort(&temp) == NO_ERROR) {
+            attrsFromDevice = createAudioProfilesAttrMap(temp.audio_profiles, 0 /*first*/,
+                                                         temp.num_audio_profiles);
+        }
     }
     auto streamIt = mStreams.find(mixPort->ext.mix.handle);
     if (streamIt == mStreams.end()) {
@@ -767,7 +771,7 @@
     }
 
     String8 formatsStr;
-    status = getParametersFromStream(
+    status_t status = getParametersFromStream(
             stream, AudioParameter::keyStreamSupportedFormats, nullptr /*extraParameters*/,
             &formatsStr);
     if (status != NO_ERROR) {
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index 00cf5a6..af0f8f2 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -208,6 +208,10 @@
         if (desc.common.flags.volume == Flags::Volume::NONE) {
             common.flags.volume = Flags::Volume::NONE;
         }
+        // set to AUXILIARY if any sub-effect is of AUXILIARY type
+        if (desc.common.flags.type == Flags::Type::AUXILIARY) {
+            common.flags.type = Flags::Type::AUXILIARY;
+        }
     }
 
     // copy type UUID from any of sub-effects, all sub-effects should have same type
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index acc69ec..263e3e9 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -450,7 +450,7 @@
         *portConfig = it->second;
         return OK;
     }
-    ALOGE("%s: could not find a configured device port for device %s",
+    ALOGE("%s: could not find a device port config for device %s",
             __func__, device.toString().c_str());
     return BAD_VALUE;
 }
@@ -1020,6 +1020,13 @@
                 }
             }
             resetUnusedPortConfigs();
+            // Patches created by Hal2AidlMapper during stream creation and not "claimed"
+            // by the framework must not be surfaced to it.
+            for (auto& s : mStreams) {
+                if (auto it = releasedPatches.find(s.second.second); it != releasedPatches.end()) {
+                    releasedPatches.erase(it);
+                }
+            }
             mFwkPatches.merge(releasedPatches);
             LOG_ALWAYS_FATAL_IF(!releasedPatches.empty(),
                     "mFwkPatches already contains some of released patches");
diff --git a/media/libaudiohal/tests/Android.bp b/media/libaudiohal/tests/Android.bp
index b9af0bf..f6a7eea 100644
--- a/media/libaudiohal/tests/Android.bp
+++ b/media/libaudiohal/tests/Android.bp
@@ -25,8 +25,8 @@
     name: "libaudiohal_aidl_test_default",
     test_suites: ["device-tests"],
     defaults: [
-        "libaudiohal_default",
         "libaudiohal_aidl_default",
+        "libaudiohal_default",
     ],
     shared_libs: [
         "libaudiohal",
@@ -36,8 +36,8 @@
 cc_test {
     name: "CoreAudioHalAidlTest",
     srcs: [
-        "CoreAudioHalAidl_test.cpp",
         ":core_audio_hal_aidl_src_files",
+        "CoreAudioHalAidl_test.cpp",
     ],
     defaults: ["libaudiohal_aidl_test_default"],
     header_libs: ["libaudiohalimpl_headers"],
@@ -56,8 +56,8 @@
 cc_test {
     name: "EffectProxyTest",
     srcs: [
-        "EffectProxy_test.cpp",
         ":audio_effectproxy_src_files",
+        "EffectProxy_test.cpp",
     ],
     defaults: [
         "libaudiohal_aidl_test_default",
@@ -69,8 +69,8 @@
 cc_test {
     name: "EffectHalVersionCompatibilityTest",
     srcs: [
-        "EffectHalVersionCompatibility_test.cpp",
         ":audio_effect_hal_aidl_src_files",
+        "EffectHalVersionCompatibility_test.cpp",
     ],
     defaults: ["libaudiohal_aidl_test_default"],
     header_libs: ["libaudiohalimpl_headers"],
diff --git a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
index 3541078..5106874 100644
--- a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
+++ b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include <algorithm>
 #include <memory>
+#include <mutex>
 #include <string>
 #include <vector>
 
@@ -22,6 +24,7 @@
 #include <gtest/gtest.h>
 
 #include <DeviceHalAidl.h>
+#include <Hal2AidlMapper.h>
 #include <StreamHalAidl.h>
 #include <aidl/android/hardware/audio/core/BnModule.h>
 #include <aidl/android/hardware/audio/core/BnStreamCommon.h>
@@ -31,7 +34,24 @@
 
 namespace {
 
+using ::aidl::android::hardware::audio::core::AudioPatch;
+using ::aidl::android::hardware::audio::core::AudioRoute;
 using ::aidl::android::hardware::audio::core::VendorParameter;
+using ::aidl::android::media::audio::common::AudioChannelLayout;
+using ::aidl::android::media::audio::common::AudioConfig;
+using ::aidl::android::media::audio::common::AudioDeviceDescription;
+using ::aidl::android::media::audio::common::AudioDeviceType;
+using ::aidl::android::media::audio::common::AudioFormatDescription;
+using ::aidl::android::media::audio::common::AudioFormatType;
+using ::aidl::android::media::audio::common::AudioIoFlags;
+using ::aidl::android::media::audio::common::AudioPort;
+using ::aidl::android::media::audio::common::AudioPortConfig;
+using ::aidl::android::media::audio::common::AudioPortDeviceExt;
+using ::aidl::android::media::audio::common::AudioPortExt;
+using ::aidl::android::media::audio::common::AudioPortMixExt;
+using ::aidl::android::media::audio::common::AudioProfile;
+using ::aidl::android::media::audio::common::AudioSource;
+using ::aidl::android::media::audio::common::PcmType;
 
 class VendorParameterMock {
   public:
@@ -63,9 +83,105 @@
     std::vector<VendorParameter> mSyncParameters;
 };
 
+struct Configuration {
+    std::vector<AudioPort> ports;
+    std::vector<AudioPortConfig> portConfigs;
+    std::vector<AudioRoute> routes;
+    std::vector<AudioPatch> patches;
+    int32_t nextPortId = 1;
+    int32_t nextPatchId = 1;
+};
+
+void fillProfile(AudioProfile* profile, const std::vector<int32_t>& channelLayouts,
+                 const std::vector<int32_t>& sampleRates) {
+    for (auto layout : channelLayouts) {
+        profile->channelMasks.push_back(
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
+    }
+    profile->sampleRates.insert(profile->sampleRates.end(), sampleRates.begin(), sampleRates.end());
+}
+
+AudioProfile createProfile(PcmType pcmType, const std::vector<int32_t>& channelLayouts,
+                           const std::vector<int32_t>& sampleRates) {
+    AudioProfile profile;
+    profile.format.type = AudioFormatType::PCM;
+    profile.format.pcm = pcmType;
+    fillProfile(&profile, channelLayouts, sampleRates);
+    return profile;
+}
+
+AudioPortExt createPortDeviceExt(AudioDeviceType devType, int32_t flags,
+                                 std::string connection = "") {
+    AudioPortDeviceExt deviceExt;
+    deviceExt.device.type.type = devType;
+    if (devType == AudioDeviceType::IN_MICROPHONE && connection.empty()) {
+        deviceExt.device.address = "bottom";
+    } else if (devType == AudioDeviceType::IN_MICROPHONE_BACK && connection.empty()) {
+        deviceExt.device.address = "back";
+    }
+    deviceExt.device.type.connection = std::move(connection);
+    deviceExt.flags = flags;
+    return AudioPortExt::make<AudioPortExt::device>(deviceExt);
+}
+
+AudioPortExt createPortMixExt(int32_t maxOpenStreamCount, int32_t maxActiveStreamCount) {
+    AudioPortMixExt mixExt;
+    mixExt.maxOpenStreamCount = maxOpenStreamCount;
+    mixExt.maxActiveStreamCount = maxActiveStreamCount;
+    return AudioPortExt::make<AudioPortExt::mix>(mixExt);
+}
+
+AudioPort createPort(int32_t id, const std::string& name, int32_t flags, bool isInput,
+                     const AudioPortExt& ext) {
+    AudioPort port;
+    port.id = id;
+    port.name = name;
+    port.flags = isInput ? AudioIoFlags::make<AudioIoFlags::input>(flags)
+                         : AudioIoFlags::make<AudioIoFlags::output>(flags);
+    port.ext = ext;
+    return port;
+}
+
+AudioRoute createRoute(const std::vector<AudioPort>& sources, const AudioPort& sink) {
+    AudioRoute route;
+    route.sinkPortId = sink.id;
+    std::transform(sources.begin(), sources.end(), std::back_inserter(route.sourcePortIds),
+                   [](const auto& port) { return port.id; });
+    return route;
+}
+
+template <typename T>
+auto findById(std::vector<T>& v, int32_t id) {
+    return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
+}
+
+Configuration getTestConfiguration() {
+    const std::vector<AudioProfile> standardPcmAudioProfiles = {
+            createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})};
+    Configuration c;
+
+    AudioPort btOutDevice =
+            createPort(c.nextPortId++, "BT A2DP Out", 0, false,
+                       createPortDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+                                           AudioDeviceDescription::CONNECTION_BT_A2DP));
+    btOutDevice.profiles = standardPcmAudioProfiles;
+    c.ports.push_back(btOutDevice);
+
+    AudioPort btOutMix =
+            createPort(c.nextPortId++, "a2dp output", 0, false, createPortMixExt(1, 1));
+    btOutMix.profiles = standardPcmAudioProfiles;
+    c.ports.push_back(btOutMix);
+
+    c.routes.push_back(createRoute({btOutMix}, btOutDevice));
+
+    return c;
+}
+
 class ModuleMock : public ::aidl::android::hardware::audio::core::BnModule,
                    public VendorParameterMock {
   public:
+    ModuleMock() = default;
+    explicit ModuleMock(const Configuration& config) : mConfig(config) {}
     bool isScreenTurnedOn() const { return mIsScreenTurnedOn; }
     ScreenRotation getScreenRotation() const { return mScreenRotation; }
 
@@ -91,35 +207,91 @@
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus connectExternalDevice(
-            const ::aidl::android::media::audio::common::AudioPort&,
-            ::aidl::android::media::audio::common::AudioPort*) override {
+            const ::aidl::android::media::audio::common::AudioPort& portIdAndData,
+            ::aidl::android::media::audio::common::AudioPort* port) override {
+        auto src = portIdAndData;  // Make a copy to mimic RPC behavior.
+        auto iter = findById<AudioPort>(mConfig.ports, src.id);
+        if (iter == mConfig.ports.end()) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        *port = *iter;
+        port->ext = src.ext;
+        port->id = mConfig.nextPortId++;
+        ALOGD("%s: returning %s", __func__, port->toString().c_str());
+        mConfig.ports.push_back(*port);
+        std::vector<AudioRoute> newRoutes;
+        for (auto& r : mConfig.routes) {
+            if (r.sinkPortId == src.id) {
+                newRoutes.push_back(AudioRoute{.sourcePortIds = r.sourcePortIds,
+                                               .sinkPortId = port->id,
+                                               .isExclusive = r.isExclusive});
+            } else if (std::find(r.sourcePortIds.begin(), r.sourcePortIds.end(), src.id) !=
+                       r.sourcePortIds.end()) {
+                r.sourcePortIds.push_back(port->id);
+            }
+        }
+        mConfig.routes.insert(mConfig.routes.end(), newRoutes.begin(), newRoutes.end());
         return ndk::ScopedAStatus::ok();
     }
-    ndk::ScopedAStatus disconnectExternalDevice(int32_t) override {
+    ndk::ScopedAStatus disconnectExternalDevice(int32_t portId) override {
+        auto iter = findById<AudioPort>(mConfig.ports, portId);
+        if (iter == mConfig.ports.end()) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        mConfig.ports.erase(iter);
+        for (auto it = mConfig.routes.begin(); it != mConfig.routes.end();) {
+            if (it->sinkPortId == portId) {
+                it = mConfig.routes.erase(it);
+            } else {
+                if (auto srcIt =
+                            std::find(it->sourcePortIds.begin(), it->sourcePortIds.end(), portId);
+                    srcIt != it->sourcePortIds.end()) {
+                    it->sourcePortIds.erase(srcIt);
+                }
+                ++it;
+            }
+        }
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus getAudioPatches(
-            std::vector<::aidl::android::hardware::audio::core::AudioPatch>*) override {
+            std::vector<::aidl::android::hardware::audio::core::AudioPatch>* patches) override {
+        *patches = mConfig.patches;
         return ndk::ScopedAStatus::ok();
     }
-    ndk::ScopedAStatus getAudioPort(int32_t,
-                                    ::aidl::android::media::audio::common::AudioPort*) override {
+    ndk::ScopedAStatus getAudioPort(
+            int32_t portId, ::aidl::android::media::audio::common::AudioPort* port) override {
+        auto iter = findById<AudioPort>(mConfig.ports, portId);
+        if (iter == mConfig.ports.end()) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        *port = *iter;
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus getAudioPortConfigs(
-            std::vector<::aidl::android::media::audio::common::AudioPortConfig>*) override {
+            std::vector<::aidl::android::media::audio::common::AudioPortConfig>* configs) override {
+        *configs = mConfig.portConfigs;
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus getAudioPorts(
-            std::vector<::aidl::android::media::audio::common::AudioPort>*) override {
+            std::vector<::aidl::android::media::audio::common::AudioPort>* ports) override {
+        *ports = mConfig.ports;
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus getAudioRoutes(
-            std::vector<::aidl::android::hardware::audio::core::AudioRoute>*) override {
+            std::vector<::aidl::android::hardware::audio::core::AudioRoute>* routes) override {
+        *routes = mConfig.routes;
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus getAudioRoutesForAudioPort(
-            int32_t, std::vector<::aidl::android::hardware::audio::core::AudioRoute>*) override {
+            int32_t portId,
+            std::vector<::aidl::android::hardware::audio::core::AudioRoute>* routes) override {
+        for (auto& r : mConfig.routes) {
+            const auto& srcs = r.sourcePortIds;
+            if (r.sinkPortId == portId ||
+                std::find(srcs.begin(), srcs.end(), portId) != srcs.end()) {
+                routes->push_back(r);
+            }
+        }
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus openInputStream(const OpenInputStreamArguments&,
@@ -133,17 +305,69 @@
     ndk::ScopedAStatus getSupportedPlaybackRateFactors(SupportedPlaybackRateFactors*) override {
         return ndk::ScopedAStatus::ok();
     }
-    ndk::ScopedAStatus setAudioPatch(const ::aidl::android::hardware::audio::core::AudioPatch&,
-                                     ::aidl::android::hardware::audio::core::AudioPatch*) override {
+    ndk::ScopedAStatus setAudioPatch(
+            const ::aidl::android::hardware::audio::core::AudioPatch& requested,
+            ::aidl::android::hardware::audio::core::AudioPatch* patch) override {
+        if (requested.id == 0) {
+            *patch = requested;
+            patch->id = mConfig.nextPatchId++;
+            mConfig.patches.push_back(*patch);
+            ALOGD("%s: returning %s", __func__, patch->toString().c_str());
+        } else {
+            auto iter = findById<AudioPatch>(mConfig.patches, requested.id);
+            if (iter == mConfig.patches.end()) {
+                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+            }
+            *iter = *patch = requested;
+            ALOGD("%s: updated %s", __func__, patch->toString().c_str());
+        }
         return ndk::ScopedAStatus::ok();
     }
     ndk::ScopedAStatus setAudioPortConfig(
-            const ::aidl::android::media::audio::common::AudioPortConfig&,
-            ::aidl::android::media::audio::common::AudioPortConfig*, bool*) override {
+            const ::aidl::android::media::audio::common::AudioPortConfig& requested,
+            ::aidl::android::media::audio::common::AudioPortConfig* config,
+            bool* applied) override {
+        *applied = false;
+        auto src = requested;  // Make a copy to mimic RPC behavior.
+        if (src.id == 0) {
+            *config = src;
+            if (config->ext.getTag() == AudioPortExt::unspecified) {
+                auto iter = findById<AudioPort>(mConfig.ports, src.portId);
+                if (iter == mConfig.ports.end()) {
+                    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+                }
+                config->ext = iter->ext;
+            }
+            config->id = mConfig.nextPortId++;
+            mConfig.portConfigs.push_back(*config);
+            ALOGD("%s: returning %s", __func__, config->toString().c_str());
+        } else {
+            auto iter = findById<AudioPortConfig>(mConfig.portConfigs, src.id);
+            if (iter == mConfig.portConfigs.end()) {
+                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+            }
+            *iter = *config = src;
+            ALOGD("%s: updated %s", __func__, config->toString().c_str());
+        }
+        *applied = true;
         return ndk::ScopedAStatus::ok();
     }
-    ndk::ScopedAStatus resetAudioPatch(int32_t) override { return ndk::ScopedAStatus::ok(); }
-    ndk::ScopedAStatus resetAudioPortConfig(int32_t) override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus resetAudioPatch(int32_t patchId) override {
+        auto iter = findById<AudioPatch>(mConfig.patches, patchId);
+        if (iter == mConfig.patches.end()) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        mConfig.patches.erase(iter);
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus resetAudioPortConfig(int32_t portConfigId) override {
+        auto iter = findById<AudioPortConfig>(mConfig.portConfigs, portConfigId);
+        if (iter == mConfig.portConfigs.end()) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        mConfig.portConfigs.erase(iter);
+        return ndk::ScopedAStatus::ok();
+    }
     ndk::ScopedAStatus getMasterMute(bool*) override { return ndk::ScopedAStatus::ok(); }
     ndk::ScopedAStatus setMasterMute(bool) override { return ndk::ScopedAStatus::ok(); }
     ndk::ScopedAStatus getMasterVolume(float*) override { return ndk::ScopedAStatus::ok(); }
@@ -205,6 +429,7 @@
         return ndk::ScopedAStatus::ok();
     }
 
+    Configuration mConfig;
     bool mIsScreenTurnedOn = false;
     ScreenRotation mScreenRotation = ScreenRotation::DEG_0;
 };
@@ -398,6 +623,35 @@
 
 using namespace android;
 
+namespace {
+
+class StreamHalMock : public virtual StreamHalInterface {
+  public:
+    StreamHalMock() = default;
+    ~StreamHalMock() override = default;
+    status_t getBufferSize(size_t*) override { return OK; }
+    status_t getAudioProperties(audio_config_base_t*) override { return OK; }
+    status_t setParameters(const String8&) override { return OK; }
+    status_t getParameters(const String8&, String8*) override { return OK; }
+    status_t getFrameSize(size_t*) override { return OK; }
+    status_t addEffect(sp<EffectHalInterface>) override { return OK; }
+    status_t removeEffect(sp<EffectHalInterface>) override { return OK; }
+    status_t standby() override { return OK; }
+    status_t dump(int, const Vector<String16>&) override { return OK; }
+    status_t start() override { return OK; }
+    status_t stop() override { return OK; }
+    status_t createMmapBuffer(int32_t, struct audio_mmap_buffer_info*) override { return OK; }
+    status_t getMmapPosition(struct audio_mmap_position*) override { return OK; }
+    status_t setHalThreadPriority(int) override { return OK; }
+    status_t legacyCreateAudioPatch(const struct audio_port_config&, std::optional<audio_source_t>,
+                                    audio_devices_t) override {
+        return OK;
+    }
+    status_t legacyReleaseAudioPatch() override { return OK; }
+};
+
+}  // namespace
+
 class DeviceHalAidlTest : public testing::Test {
   public:
     void SetUp() override {
@@ -593,3 +847,297 @@
     EXPECT_EQ(0UL, mStreamCommon->getAsyncParameters().size());
     EXPECT_EQ(0UL, mStreamCommon->getSyncParameters().size());
 }
+
+class Hal2AidlMapperTest : public testing::Test {
+  public:
+    void SetUp() override {
+        mModule = ndk::SharedRefBase::make<ModuleMock>(getTestConfiguration());
+        mMapper = std::make_unique<Hal2AidlMapper>("test", mModule);
+        ASSERT_EQ(OK, mMapper->initialize());
+
+        mConnectedPort.ext = createPortDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+                                                 AudioDeviceDescription::CONNECTION_BT_A2DP);
+        mConnectedPort.ext.get<AudioPortExt::device>().device.address = "00:11:22:33:44:55";
+        ASSERT_EQ(OK, mMapper->setDevicePortConnectedState(mConnectedPort, true /*connected*/));
+
+        std::mutex mutex;  // Only needed for cleanups.
+        auto mapperAccessor = std::make_unique<LockedAccessor<Hal2AidlMapper>>(*mMapper, mutex);
+        Hal2AidlMapper::Cleanups cleanups(*mapperAccessor);
+        AudioConfig config;
+        config.base.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_STEREO);
+        config.base.format =
+                AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
+        config.base.sampleRate = 48000;
+        ASSERT_EQ(OK,
+                  mMapper->prepareToOpenStream(
+                          42 /*ioHandle*/, mConnectedPort.ext.get<AudioPortExt::device>().device,
+                          AudioIoFlags::make<AudioIoFlags::output>(0), AudioSource::DEFAULT,
+                          &cleanups, &config, &mMixPortConfig, &mPatch));
+        cleanups.disarmAll();
+        ASSERT_NE(0, mPatch.id);
+        ASSERT_NE(0, mMixPortConfig.id);
+        mStream = sp<StreamHalMock>::make();
+        mMapper->addStream(mStream, mMixPortConfig.id, mPatch.id);
+
+        ASSERT_EQ(OK, mMapper->findPortConfig(mConnectedPort.ext.get<AudioPortExt::device>().device,
+                                              &mDevicePortConfig));
+        ASSERT_EQ(1UL, mPatch.sourcePortConfigIds.size());
+        ASSERT_EQ(mMixPortConfig.id, mPatch.sourcePortConfigIds[0]);
+        ASSERT_EQ(1UL, mPatch.sinkPortConfigIds.size());
+        ASSERT_EQ(mDevicePortConfig.id, mPatch.sinkPortConfigIds[0]);
+    }
+
+    void TearDown() override {
+        mStream.clear();
+        mMapper.reset();
+        mModule.reset();
+    }
+
+  protected:
+    void CloseDisconnectImpl() {
+        mStream.clear();
+        ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    }
+
+    void ConnectAnotherDevice() {
+        mConnectedPort.ext.get<AudioPortExt::device>().device.address = "00:11:22:33:44:66";
+        ASSERT_EQ(OK, mMapper->setDevicePortConnectedState(mConnectedPort, true /*connected*/));
+    }
+
+    void CreateFwkPatch(int32_t* patchId) {
+        std::mutex mutex;  // Only needed for cleanups.
+        auto mapperAccessor = std::make_unique<LockedAccessor<Hal2AidlMapper>>(*mMapper, mutex);
+        Hal2AidlMapper::Cleanups cleanups(*mapperAccessor);
+        ASSERT_EQ(OK, mMapper->createOrUpdatePatch({mMixPortConfig}, {mDevicePortConfig}, patchId,
+                                                   &cleanups));
+        cleanups.disarmAll();
+    }
+
+    void DisconnectDevice() {
+        ASSERT_EQ(OK, mMapper->prepareToDisconnectExternalDevice(mConnectedPort));
+        ASSERT_EQ(OK, mMapper->setDevicePortConnectedState(mConnectedPort, false /*connected*/));
+    }
+
+    void ReleaseFwkOnlyPatch(int32_t patchId) {
+        // The patch only exists for the framework.
+        EXPECT_EQ(patchId, mMapper->findFwkPatch(patchId));
+        ASSERT_EQ(BAD_VALUE, mMapper->releaseAudioPatch(patchId));
+        mMapper->eraseFwkPatch(patchId);
+        // The patch is now erased.
+        EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+    }
+
+    std::shared_ptr<ModuleMock> mModule;
+    std::unique_ptr<Hal2AidlMapper> mMapper;
+    AudioPort mConnectedPort;
+    AudioPortConfig mMixPortConfig;
+    AudioPortConfig mDevicePortConfig;
+    AudioPatch mPatch;
+    sp<StreamHalInterface> mStream;
+};
+
+/**
+ * External device connections and patches tests diagram.
+ *
+ * [Connect device] -> [Create Stream]
+ *                            |-> [ (1) Close Stream] -> [Disconnect Device]
+ *                            |-> [ (2) Disconnect Device]
+ *                            |          |-> [ (3) Close Stream]
+ *                            |          \-> [ (4) Connect Another Device]
+ *                            |                    |-> (1)
+ *                            |                    |-> (2) -> (3)
+ *                            |                    \-> (5) -> (7)
+ *                            \-> [ (5) Create/Update Fwk Patch]
+ *                                       |-> [(6) Release Fwk Patch]
+ *                                       |        |-> (1)
+ *                                       |        \-> (2) (including reconnection)
+ *                                       \-> [(7) Disconnect Device]
+ *                                                |-> [Release Fwk Patch] -> [Close Stream]
+ *                                                \-> (4) -> (5) -> (6) -> (1)
+ *
+ * Note that the test (acting on behalf of DeviceHalAidl) is responsible
+ * for calling `eraseFwkPatch` and `updateFwkPatch` when needed.
+ */
+
+// (1)
+TEST_F(Hal2AidlMapperTest, CloseDisconnect) {
+    ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
+    // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+}
+
+// (2) -> (3)
+TEST_F(Hal2AidlMapperTest, DisconnectClose) {
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    mStream.clear();
+}
+
+// (2) -> (4) -> (1)
+TEST_F(Hal2AidlMapperTest, DisconnectConnectCloseDisconnect) {
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
+    ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
+    // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+}
+
+// (2) -> (4) -> (2) -> (3)
+TEST_F(Hal2AidlMapperTest, DisconnectConnectDisconnectClose) {
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    mStream.clear();
+}
+
+// (5) -> (6) -> (1)
+TEST_F(Hal2AidlMapperTest, CreateFwkPatchReleaseCloseDisconnect) {
+    int32_t patchId;
+    ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
+    // Must be the patch created during stream opening.
+    ASSERT_EQ(mPatch.id, patchId);
+    // The patch was not reset by HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_EQ(OK, mMapper->releaseAudioPatch(patchId));
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+    ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+}
+
+// (5) -> (6) -> (2) -> (3)
+TEST_F(Hal2AidlMapperTest, CreateFwkPatchReleaseDisconnectClose) {
+    int32_t patchId;
+    ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
+    // Must be the patch created during stream opening.
+    ASSERT_EQ(mPatch.id, patchId);
+    // The patch was not reset by HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_EQ(OK, mMapper->releaseAudioPatch(patchId));
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    mStream.clear();
+}
+
+// (5) -> (6) -> (2) -> (4) -> (2) -> (3)
+TEST_F(Hal2AidlMapperTest, CreateFwkPatchReleaseDisconnectConnectDisconnectClose) {
+    int32_t patchId;
+    ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
+    // Must be the patch created during stream opening.
+    ASSERT_EQ(mPatch.id, patchId);
+    // The patch was not reset by HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_EQ(OK, mMapper->releaseAudioPatch(patchId));
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    mStream.clear();
+}
+
+// (5) -> (7) -> Release -> Close
+TEST_F(Hal2AidlMapperTest, CreateFwkPatchDisconnectReleaseClose) {
+    int32_t patchId;
+    ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
+    // Must be the patch created during stream opening.
+    ASSERT_EQ(mPatch.id, patchId);
+    // The patch was not reset by HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    ASSERT_NO_FATAL_FAILURE(ReleaseFwkOnlyPatch(patchId));
+
+    mStream.clear();
+    EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+}
+
+// (5) -> (7) -> (4) -> (5) -> (6) -> (1)
+TEST_F(Hal2AidlMapperTest, CreateFwkPatchDisconnectConnectUpdateReleaseCloseDisconnect) {
+    int32_t patchId;
+    ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
+    // Must be the patch created during stream opening.
+    ASSERT_EQ(mPatch.id, patchId);
+    // The patch was not reset by HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch now only exists for the framework.
+    EXPECT_EQ(mPatch.id, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
+    // Change the device address locally, for patch update.
+    mDevicePortConfig.ext.get<AudioPortExt::device>().device.address =
+            mConnectedPort.ext.get<AudioPortExt::device>().device.address;
+    int32_t newPatchId = patchId;
+    ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&newPatchId));
+    EXPECT_NE(patchId, newPatchId);
+    mMapper->updateFwkPatch(patchId, newPatchId);
+    EXPECT_EQ(newPatchId, mMapper->findFwkPatch(patchId));
+    // Just in case, check that HAL patch ID is not listed as a fwk patch.
+    EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
+    // Verify that device port config was updated.
+    ASSERT_EQ(OK, mMapper->findPortConfig(mConnectedPort.ext.get<AudioPortExt::device>().device,
+                                          &mDevicePortConfig));
+
+    ASSERT_EQ(OK, mMapper->releaseAudioPatch(newPatchId));
+    // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
+    EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+    // Just in case, check that HAL patch ID is not listed.
+    EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
+
+    ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
+    EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
+}
+
+// (2) -> (4) -> (5) -> (7) -> Release -> Close
+TEST_F(Hal2AidlMapperTest, DisconnectConnectCreateFwkPatchDisconnectReleaseClose) {
+    const int32_t patchId = mPatch.id;
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+
+    ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
+    // Change the device address locally, for patch update.
+    mDevicePortConfig.ext.get<AudioPortExt::device>().device.address =
+            mConnectedPort.ext.get<AudioPortExt::device>().device.address;
+    int32_t newPatchId = 0;  // Use 0 since the fwk does not know about the HAL patch.
+    EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
+    ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&newPatchId));
+    EXPECT_NE(0, newPatchId);
+    EXPECT_NE(patchId, newPatchId);
+    // Just in case, check that HAL patch ID is not listed as a fwk patch.
+    EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
+    // Verify that device port config was updated.
+    ASSERT_EQ(OK, mMapper->findPortConfig(mConnectedPort.ext.get<AudioPortExt::device>().device,
+                                          &mDevicePortConfig));
+
+    ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
+    ASSERT_NO_FATAL_FAILURE(ReleaseFwkOnlyPatch(newPatchId));
+
+    mStream.clear();
+    EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
+    EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
+}
diff --git a/media/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index 6160d7d..9d510a8 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -22,11 +22,13 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
 
         // uncomment to disable NEON on architectures that actually do support NEON, for benchmarking
+
         // "-DUSE_NEON=false",
+        "-Werror",
+
     ],
 
     arch: {
@@ -62,7 +64,7 @@
     header_libs: [
         "libaudiohal_headers",
         "libbase_headers",
-        "libmedia_headers"
+        "libmedia_headers",
     ],
 
     shared_libs: [
@@ -87,8 +89,8 @@
         "AudioMixerBase.cpp",
         "AudioResampler.cpp",
         "AudioResamplerCubic.cpp",
-        "AudioResamplerSinc.cpp",
         "AudioResamplerDyn.cpp",
+        "AudioResamplerSinc.cpp",
     ],
 
     arch: {
diff --git a/media/libaudioprocessing/audio-resampler/Android.bp b/media/libaudioprocessing/audio-resampler/Android.bp
index 4ea75e7..791ae37 100644
--- a/media/libaudioprocessing/audio-resampler/Android.bp
+++ b/media/libaudioprocessing/audio-resampler/Android.bp
@@ -13,12 +13,12 @@
     srcs: ["AudioResamplerCoefficients.cpp"],
 
     shared_libs: [
-        "libutils",
         "liblog",
+        "libutils",
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 }
diff --git a/media/libaudioprocessing/tests/Android.bp b/media/libaudioprocessing/tests/Android.bp
index a33bf55..ba9b165 100644
--- a/media/libaudioprocessing/tests/Android.bp
+++ b/media/libaudioprocessing/tests/Android.bp
@@ -29,8 +29,8 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 }
 
diff --git a/media/libcpustats/Android.bp b/media/libcpustats/Android.bp
index 1ab1de0..2b134a7 100644
--- a/media/libcpustats/Android.bp
+++ b/media/libcpustats/Android.bp
@@ -24,8 +24,8 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     host_supported: true,
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
index 293a9c2..1672797 100644
--- a/media/libeffects/config/Android.bp
+++ b/media/libeffects/config/Android.bp
@@ -20,11 +20,11 @@
     ],
 
     shared_libs: [
+        "libcutils",
         "liblog",
+        "libmedia_helper",
         "libtinyxml2",
         "libutils",
-        "libmedia_helper",
-        "libcutils",
     ],
 
     header_libs: [
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index 0b25327..19b8082 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -38,9 +38,9 @@
     relative_install_path: "soundfx",
 
     cflags: [
-        "-fvisibility=hidden",
         "-Wall",
         "-Werror",
+        "-fvisibility=hidden",
     ],
 
     header_libs: [
@@ -52,9 +52,9 @@
 cc_library_shared {
     name: "libdownmixaidl",
     srcs: [
-        "aidl/EffectDownmix.cpp",
-        "aidl/DownmixContext.cpp",
         ":effectCommonFile",
+        "aidl/DownmixContext.cpp",
+        "aidl/EffectDownmix.cpp",
     ],
     defaults: [
         "aidlaudioeffectservice_defaults",
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index e93a4e6..12477a4 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -33,7 +33,7 @@
 }
 
 cc_defaults {
-    name : "dynamicsprocessingdefaults",
+    name: "dynamicsprocessingdefaults",
     srcs: [
         "dsp/DPBase.cpp",
         "dsp/DPFrequency.cpp",
@@ -50,9 +50,9 @@
         "libeigen",
     ],
     cflags: [
-        "-Wthread-safety",
         "-Wall",
         "-Werror",
+        "-Wthread-safety",
     ],
     relative_install_path: "soundfx",
 }
@@ -80,9 +80,9 @@
     name: "libdynamicsprocessingaidl",
 
     srcs: [
+        ":effectCommonFile",
         "aidl/DynamicsProcessing.cpp",
         "aidl/DynamicsProcessingContext.cpp",
-        ":effectCommonFile",
     ],
 
     defaults: [
diff --git a/media/libeffects/factory/Android.bp b/media/libeffects/factory/Android.bp
index ad5188f..9be45a5 100644
--- a/media/libeffects/factory/Android.bp
+++ b/media/libeffects/factory/Android.bp
@@ -21,17 +21,17 @@
     name: "libeffects",
     vendor: true,
     srcs: [
-        "EffectsFactory.c",
         "EffectsConfigLoader.c",
+        "EffectsFactory.c",
         "EffectsFactoryState.c",
         "EffectsXmlConfigLoader.cpp",
     ],
 
     shared_libs: [
         "libcutils",
-        "liblog",
         "libdl",
         "libeffectsconfig",
+        "liblog",
     ],
     cflags: ["-fvisibility=hidden"],
 
@@ -54,13 +54,13 @@
 
     cflags: [
         "-Wall",
-        "-Wextra",
         "-Werror",
+        "-Wextra",
     ],
 
     shared_libs: [
-        "libeffectsconfig",
         "libeffects",
+        "libeffectsconfig",
     ],
     local_include_dirs: [
         ".",
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index 7d96b53..9975f75 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -23,7 +23,7 @@
 }
 
 cc_defaults {
-    name : "hapticgeneratordefaults",
+    name: "hapticgeneratordefaults",
     srcs: [
         "Processors.cpp",
     ],
@@ -54,13 +54,15 @@
     ],
 
     cflags: [
-        "-O2", // Turning on the optimization in order to reduce effect processing time.
-               // The latency is around 1/5 less than without the optimization.
+        // Turning on the optimization in order to reduce effect processing time.
+        // The latency is around 1/5 less than without the optimization.
+        "-O2",
         "-Wall",
         "-Werror",
-        "-ffast-math", // This is needed for the non-zero coefficients optimization for
-                       // BiquadFilter. Try the biquad_filter_benchmark test in audio_utils
-                       // with/without `-ffast-math` for more context.
+        // This is needed for the non-zero coefficients optimization for
+        // BiquadFilter. Try the biquad_filter_benchmark test in audio_utils
+        // with/without `-ffast-math` for more context.
+        "-ffast-math",
         "-fvisibility=hidden",
     ],
 }
@@ -69,9 +71,9 @@
     name: "libhapticgeneratoraidl",
 
     srcs: [
+        ":effectCommonFile",
         "aidl/EffectHapticGenerator.cpp",
         "aidl/HapticGeneratorContext.cpp",
-        ":effectCommonFile",
     ],
 
     defaults: [
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
index 5d9886c..f60d616 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
@@ -114,10 +114,11 @@
     std::stringstream ss;
     ss << "\t\tHaptic setting:\n";
     ss << "\t\t- tracks intensity map:\n";
-    for (const auto&[id, intensity] : param.id2Intensity) {
-        ss << "\t\t\t- id=" << id << ", intensity=" << (int) intensity;
+    for (const auto&[id, hapticScale] : param.id2HapticScale) {
+        ss << "\t\t\t- id=" << id << ", hapticLevel=" << (int) hapticScale.getLevel()
+           << ", adaptiveScaleFactor=" << hapticScale.getAdaptiveScaleFactor();
     }
-    ss << "\t\t- max intensity: " << (int) param.maxHapticIntensity << '\n';
+    ss << "\t\t- max scale level: " << (int) param.maxHapticScale.getLevel() << '\n';
     ss << "\t\t- max haptic amplitude: " << param.maxHapticAmplitude << '\n';
     return ss.str();
 }
@@ -145,7 +146,7 @@
     memset(context->param.hapticChannelSource, 0, sizeof(context->param.hapticChannelSource));
     context->param.hapticChannelCount = 0;
     context->param.audioChannelCount = 0;
-    context->param.maxHapticIntensity = os::HapticLevel::MUTE;
+    context->param.maxHapticScale = os::HapticScale::mute();
 
     context->param.resonantFrequency = DEFAULT_RESONANT_FREQUENCY;
     context->param.bpfQ = 1.0f;
@@ -312,22 +313,25 @@
                                  void *value) {
     switch (param) {
     case HG_PARAM_HAPTIC_INTENSITY: {
-        if (value == nullptr || size != (uint32_t) (2 * sizeof(int))) {
+        if (value == nullptr || size != (uint32_t) (2 * sizeof(int) + sizeof(float))) {
             return -EINVAL;
         }
-        int id = *(int *) value;
-        os::HapticLevel hapticIntensity =
-                static_cast<os::HapticLevel>(*((int *) value + 1));
-        ALOGD("Setting haptic intensity as %d", static_cast<int>(hapticIntensity));
-        if (hapticIntensity == os::HapticLevel::MUTE) {
-            context->param.id2Intensity.erase(id);
+        const int id = *(int *) value;
+        const os::HapticLevel hapticLevel = static_cast<os::HapticLevel>(*((int *) value + 1));
+        const float adaptiveScaleFactor = (*((float *) value + 2));
+        const os::HapticScale hapticScale = {hapticLevel, adaptiveScaleFactor};
+        ALOGD("Updating haptic scale, hapticLevel=%d, adaptiveScaleFactor=%f",
+              static_cast<int>(hapticLevel), adaptiveScaleFactor);
+        if (hapticScale.isScaleMute()) {
+            context->param.id2HapticScale.erase(id);
         } else {
-            context->param.id2Intensity.emplace(id, hapticIntensity);
+            context->param.id2HapticScale.emplace(id, hapticScale);
         }
-        context->param.maxHapticIntensity = hapticIntensity;
-        for (const auto&[id, intensity] : context->param.id2Intensity) {
-            context->param.maxHapticIntensity = std::max(
-                    context->param.maxHapticIntensity, intensity);
+        context->param.maxHapticScale = hapticScale;
+        for (const auto&[id, scale] : context->param.id2HapticScale) {
+            if (scale.getLevel() > context->param.maxHapticScale.getLevel()) {
+                context->param.maxHapticScale = scale;
+            }
         }
         break;
     }
@@ -479,7 +483,7 @@
         return -ENODATA;
     }
 
-    if (context->param.maxHapticIntensity == os::HapticLevel::MUTE) {
+    if (context->param.maxHapticScale.isScaleMute()) {
         // Haptic channels are muted, not need to generate haptic data.
         return 0;
     }
@@ -506,7 +510,7 @@
             context->processingChain, context->inputBuffer.data(),
             context->outputBuffer.data(), inBuffer->frameCount);
         os::scaleHapticData(hapticOutBuffer, hapticSampleCount,
-                            { /*level=*/context->param.maxHapticIntensity},
+                            context->param.maxHapticScale,
                             context->param.maxHapticAmplitude);
 
     // For haptic data, the haptic playback thread will copy the data from effect input buffer,
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
index f122c0a..dbfc5ea 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
@@ -48,9 +48,9 @@
     uint32_t audioChannelCount;
     uint32_t hapticChannelCount;
 
-    // A map from track id to haptic intensity.
-    std::map<int, os::HapticLevel> id2Intensity;
-    os::HapticLevel maxHapticIntensity; // max intensity will be used to scale haptic data.
+    // A map from track id to haptic scale.
+    std::map<int, os::HapticScale> id2HapticScale;
+    os::HapticScale maxHapticScale; // max haptic scale will be used to scale haptic data.
     float maxHapticAmplitude; // max amplitude will be used to limit haptic data absolute values.
 
     float resonantFrequency;
diff --git a/media/libeffects/loudness/Android.bp b/media/libeffects/loudness/Android.bp
index 46e4669..4f04ffb 100644
--- a/media/libeffects/loudness/Android.bp
+++ b/media/libeffects/loudness/Android.bp
@@ -48,10 +48,10 @@
 cc_library_shared {
     name: "libloudnessenhanceraidl",
     srcs: [
+        ":effectCommonFile",
         "aidl/EffectLoudnessEnhancer.cpp",
         "aidl/LoudnessEnhancerContext.cpp",
         "dsp/core/dynamic_range_compression.cpp",
-        ":effectCommonFile",
     ],
     defaults: [
         "aidlaudioeffectservice_defaults",
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index c1a77f0..02b918b 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -31,6 +31,60 @@
     vendor: true,
     host_supported: true,
     srcs: [
+        "Bass/src/LVDBE_Control.cpp",
+        "Bass/src/LVDBE_Init.cpp",
+        "Bass/src/LVDBE_Process.cpp",
+        "Bass/src/LVDBE_Tables.cpp",
+        "Bundle/src/LVM_API_Specials.cpp",
+        "Bundle/src/LVM_Buffers.cpp",
+        "Bundle/src/LVM_Control.cpp",
+        "Bundle/src/LVM_Init.cpp",
+        "Bundle/src/LVM_Process.cpp",
+        "Bundle/src/LVM_Tables.cpp",
+        "Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.cpp",
+        "Common/src/Add2_Sat_32x32.cpp",
+        "Common/src/Copy_16.cpp",
+        "Common/src/DC_2I_D16_TRC_WRA_01.cpp",
+        "Common/src/DC_2I_D16_TRC_WRA_01_Init.cpp",
+        "Common/src/DelayMix_16x16.cpp",
+        "Common/src/From2iToMS_16x16.cpp",
+        "Common/src/From2iToMono_32.cpp",
+        "Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.cpp",
+        "Common/src/LVC_Core_MixHard_2St_D16C31_SAT.cpp",
+        "Common/src/LVC_Core_MixInSoft_D16C31_SAT.cpp",
+        "Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.cpp",
+        "Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.cpp",
+        "Common/src/LVC_MixInSoft_D16C31_SAT.cpp",
+        "Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp",
+        "Common/src/LVC_MixSoft_1St_D16C31_SAT.cpp",
+        "Common/src/LVC_MixSoft_2St_D16C31_SAT.cpp",
+        "Common/src/LVC_Mixer_GetCurrent.cpp",
+        "Common/src/LVC_Mixer_GetTarget.cpp",
+        "Common/src/LVC_Mixer_Init.cpp",
+        "Common/src/LVC_Mixer_SetTarget.cpp",
+        "Common/src/LVC_Mixer_SetTimeConstant.cpp",
+        "Common/src/LVC_Mixer_VarSlope_SetTimeConstant.cpp",
+        "Common/src/LVM_Timer.cpp",
+        "Common/src/LVM_Timer_Init.cpp",
+        "Common/src/MSTo2i_Sat_16x16.cpp",
+        "Common/src/Mac3s_Sat_32x16.cpp",
+        "Common/src/MonoTo2I_32.cpp",
+        "Common/src/Mult3s_32x16.cpp",
+        "Common/src/NonLinComp_D16.cpp",
+        "Common/src/Shift_Sat_v16xv16.cpp",
+        "Common/src/Shift_Sat_v32xv32.cpp",
+        "Common/src/dB_to_Lin32.cpp",
+        "Eq/src/LVEQNB_CalcCoef.cpp",
+        "Eq/src/LVEQNB_Control.cpp",
+        "Eq/src/LVEQNB_Init.cpp",
+        "Eq/src/LVEQNB_Process.cpp",
+        "Eq/src/LVEQNB_Tables.cpp",
+        "SpectrumAnalyzer/src/LVPSA_Control.cpp",
+        "SpectrumAnalyzer/src/LVPSA_Init.cpp",
+        "SpectrumAnalyzer/src/LVPSA_Process.cpp",
+        "SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp",
+        "SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp",
+        "SpectrumAnalyzer/src/LVPSA_Tables.cpp",
         "StereoWidening/src/LVCS_BypassMix.cpp",
         "StereoWidening/src/LVCS_Control.cpp",
         "StereoWidening/src/LVCS_Equaliser.cpp",
@@ -39,77 +93,23 @@
         "StereoWidening/src/LVCS_ReverbGenerator.cpp",
         "StereoWidening/src/LVCS_StereoEnhancer.cpp",
         "StereoWidening/src/LVCS_Tables.cpp",
-        "Bass/src/LVDBE_Control.cpp",
-        "Bass/src/LVDBE_Init.cpp",
-        "Bass/src/LVDBE_Process.cpp",
-        "Bass/src/LVDBE_Tables.cpp",
-        "Bundle/src/LVM_API_Specials.cpp",
-        "Bundle/src/LVM_Buffers.cpp",
-        "Bundle/src/LVM_Init.cpp",
-        "Bundle/src/LVM_Process.cpp",
-        "Bundle/src/LVM_Tables.cpp",
-        "Bundle/src/LVM_Control.cpp",
-        "SpectrumAnalyzer/src/LVPSA_Control.cpp",
-        "SpectrumAnalyzer/src/LVPSA_Init.cpp",
-        "SpectrumAnalyzer/src/LVPSA_Process.cpp",
-        "SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp",
-        "SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp",
-        "SpectrumAnalyzer/src/LVPSA_Tables.cpp",
-        "Eq/src/LVEQNB_CalcCoef.cpp",
-        "Eq/src/LVEQNB_Control.cpp",
-        "Eq/src/LVEQNB_Init.cpp",
-        "Eq/src/LVEQNB_Process.cpp",
-        "Eq/src/LVEQNB_Tables.cpp",
-        "Common/src/DC_2I_D16_TRC_WRA_01.cpp",
-        "Common/src/DC_2I_D16_TRC_WRA_01_Init.cpp",
-        "Common/src/Copy_16.cpp",
-        "Common/src/MonoTo2I_32.cpp",
-        "Common/src/dB_to_Lin32.cpp",
-        "Common/src/Shift_Sat_v16xv16.cpp",
-        "Common/src/Shift_Sat_v32xv32.cpp",
-        "Common/src/From2iToMono_32.cpp",
-        "Common/src/Mult3s_32x16.cpp",
-        "Common/src/NonLinComp_D16.cpp",
-        "Common/src/DelayMix_16x16.cpp",
-        "Common/src/MSTo2i_Sat_16x16.cpp",
-        "Common/src/From2iToMS_16x16.cpp",
-        "Common/src/Mac3s_Sat_32x16.cpp",
-        "Common/src/Add2_Sat_32x32.cpp",
-        "Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp",
-        "Common/src/LVC_MixSoft_1St_D16C31_SAT.cpp",
-        "Common/src/LVC_Mixer_VarSlope_SetTimeConstant.cpp",
-        "Common/src/LVC_Mixer_SetTimeConstant.cpp",
-        "Common/src/LVC_Mixer_SetTarget.cpp",
-        "Common/src/LVC_Mixer_GetTarget.cpp",
-        "Common/src/LVC_Mixer_Init.cpp",
-        "Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.cpp",
-        "Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.cpp",
-        "Common/src/LVC_Core_MixInSoft_D16C31_SAT.cpp",
-        "Common/src/LVC_Mixer_GetCurrent.cpp",
-        "Common/src/LVC_MixSoft_2St_D16C31_SAT.cpp",
-        "Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.cpp",
-        "Common/src/LVC_Core_MixHard_2St_D16C31_SAT.cpp",
-        "Common/src/LVC_MixInSoft_D16C31_SAT.cpp",
-        "Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.cpp",
-        "Common/src/LVM_Timer.cpp",
-        "Common/src/LVM_Timer_Init.cpp",
     ],
 
     local_include_dirs: [
-        "Eq/lib",
-        "Eq/src",
         "Bass/lib",
         "Bass/src",
-        "Common/src",
         "Bundle/src",
+        "Common/src",
+        "Eq/lib",
+        "Eq/src",
         "SpectrumAnalyzer/lib",
         "SpectrumAnalyzer/src",
-        "StereoWidening/src",
         "StereoWidening/lib",
+        "StereoWidening/src",
     ],
     export_include_dirs: [
-        "Common/lib",
         "Bundle/lib",
+        "Common/lib",
     ],
     shared_libs: [
         "liblog",
@@ -121,9 +121,9 @@
         "libhardware_headers",
     ],
     cppflags: [
-        "-fvisibility=hidden",
         "-Wall",
         "-Werror",
+        "-fvisibility=hidden",
     ],
 
 }
@@ -141,6 +141,26 @@
     vendor: true,
     host_supported: true,
     srcs: [
+        "Common/src/Add2_Sat_32x32.cpp",
+        "Common/src/Copy_16.cpp",
+        "Common/src/Core_MixHard_2St_D32C31_SAT.cpp",
+        "Common/src/Core_MixInSoft_D32C31_SAT.cpp",
+        "Common/src/Core_MixSoft_1St_D32C31_WRA.cpp",
+        "Common/src/From2iToMono_32.cpp",
+        "Common/src/JoinTo2i_32x32.cpp",
+        "Common/src/LVM_FO_HPF.cpp",
+        "Common/src/LVM_FO_LPF.cpp",
+        "Common/src/LVM_GetOmega.cpp",
+        "Common/src/LVM_Mixer_TimeConstant.cpp",
+        "Common/src/LVM_Polynomial.cpp",
+        "Common/src/LVM_Power10.cpp",
+        "Common/src/Mac3s_Sat_32x16.cpp",
+        "Common/src/MixInSoft_D32C31_SAT.cpp",
+        "Common/src/MixSoft_1St_D32C31_WRA.cpp",
+        "Common/src/MixSoft_2St_D32C31_SAT.cpp",
+        "Common/src/MonoTo2I_32.cpp",
+        "Common/src/Mult3s_32x16.cpp",
+        "Common/src/Shift_Sat_v32xv32.cpp",
         "Reverb/src/LVREV_ApplyNewSettings.cpp",
         "Reverb/src/LVREV_ClearAudioBuffers.cpp",
         "Reverb/src/LVREV_GetControlParameters.cpp",
@@ -148,42 +168,22 @@
         "Reverb/src/LVREV_Process.cpp",
         "Reverb/src/LVREV_SetControlParameters.cpp",
         "Reverb/src/LVREV_Tables.cpp",
-        "Common/src/From2iToMono_32.cpp",
-        "Common/src/Mult3s_32x16.cpp",
-        "Common/src/Copy_16.cpp",
-        "Common/src/Mac3s_Sat_32x16.cpp",
-        "Common/src/Shift_Sat_v32xv32.cpp",
-        "Common/src/Add2_Sat_32x32.cpp",
-        "Common/src/JoinTo2i_32x32.cpp",
-        "Common/src/MonoTo2I_32.cpp",
-        "Common/src/LVM_FO_HPF.cpp",
-        "Common/src/LVM_FO_LPF.cpp",
-        "Common/src/LVM_Polynomial.cpp",
-        "Common/src/LVM_Power10.cpp",
-        "Common/src/LVM_GetOmega.cpp",
-        "Common/src/MixSoft_2St_D32C31_SAT.cpp",
-        "Common/src/MixSoft_1St_D32C31_WRA.cpp",
-        "Common/src/MixInSoft_D32C31_SAT.cpp",
-        "Common/src/LVM_Mixer_TimeConstant.cpp",
-        "Common/src/Core_MixHard_2St_D32C31_SAT.cpp",
-        "Common/src/Core_MixSoft_1St_D32C31_WRA.cpp",
-        "Common/src/Core_MixInSoft_D32C31_SAT.cpp",
     ],
 
     local_include_dirs: [
-        "Reverb/src",
         "Common/src",
+        "Reverb/src",
     ],
     export_include_dirs: [
-        "Reverb/lib",
         "Common/lib",
+        "Reverb/lib",
     ],
     static_libs: [
         "libaudioutils",
     ],
     cppflags: [
-        "-fvisibility=hidden",
         "-Wall",
         "-Werror",
+        "-fvisibility=hidden",
     ],
 }
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index 781aad6..5b48045 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -52,8 +52,8 @@
     local_include_dirs: ["Bundle"],
 
     header_libs: [
-        "libhardware_headers",
         "libaudioeffects",
+        "libhardware_headers",
     ],
 }
 
@@ -93,8 +93,8 @@
     export_include_dirs: ["Reverb"],
 
     header_libs: [
-        "libhardware_headers",
         "libaudioeffects",
+        "libhardware_headers",
     ],
 
     sanitize: {
@@ -105,9 +105,9 @@
 cc_library_shared {
     name: "libbundleaidl",
     srcs: [
+        ":effectCommonFile",
         "Aidl/BundleContext.cpp",
         "Aidl/EffectBundleAidl.cpp",
-        ":effectCommonFile",
     ],
     static_libs: ["libmusicbundle"],
     defaults: [
@@ -125,8 +125,8 @@
         "libstagefright_foundation",
     ],
     cflags: [
-        "-Wthread-safety",
         "-DBACKEND_NDK",
+        "-Wthread-safety",
     ],
     relative_install_path: "soundfx",
     visibility: [
@@ -137,9 +137,9 @@
 cc_library_shared {
     name: "libreverbaidl",
     srcs: [
-        "Reverb/aidl/ReverbContext.cpp",
-        "Reverb/aidl/EffectReverb.cpp",
         ":effectCommonFile",
+        "Reverb/aidl/EffectReverb.cpp",
+        "Reverb/aidl/ReverbContext.cpp",
     ],
     static_libs: ["libreverb"],
     defaults: [
@@ -151,8 +151,8 @@
         "libhardware_headers",
     ],
     shared_libs: [
-        "libbase",
         "libaudioutils",
+        "libbase",
         "libcutils",
         "liblog",
     ],
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index d658536..44b7d97 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -63,30 +63,30 @@
 cc_library_shared {
     name: "libpreprocessingaidl",
     srcs: [
-        "aidl/PreProcessingContext.cpp",
-        "aidl/EffectPreProcessing.cpp",
         ":effectCommonFile",
+        "aidl/EffectPreProcessing.cpp",
+        "aidl/PreProcessingContext.cpp",
     ],
     defaults: [
         "aidlaudioeffectservice_defaults",
     ],
     local_include_dirs: ["aidl"],
     shared_libs: [
+        "libaudioutils",
         "liblog",
         "libutils",
-        "libaudioutils",
     ],
     static_libs: [
         "webrtc_audio_processing",
     ],
     header_libs: [
-        "libwebrtc_absl_headers",
         "libaudioeffects",
         "libhardware_headers",
+        "libwebrtc_absl_headers",
     ],
     cflags: [
-        "-Wthread-safety",
         "-Wno-unused-parameter",
+        "-Wthread-safety",
     ],
     relative_install_path: "soundfx",
     visibility: [
diff --git a/media/libeffects/proxy/Android.bp b/media/libeffects/proxy/Android.bp
index 6256eda..95da4de 100644
--- a/media/libeffects/proxy/Android.bp
+++ b/media/libeffects/proxy/Android.bp
@@ -29,19 +29,19 @@
     srcs: ["EffectProxy.cpp"],
 
     cflags: [
-        "-fvisibility=hidden",
         "-Wall",
         "-Werror",
+        "-fvisibility=hidden",
     ],
 
     include_dirs: ["frameworks/av/media/libeffects/factory"],
 
     header_libs: ["libaudioeffects"],
     shared_libs: [
-        "liblog",
         "libcutils",
-        "libutils",
         "libdl",
         "libeffects",
+        "liblog",
+        "libutils",
     ],
 }
diff --git a/media/libeffects/testlibs/Android.bp b/media/libeffects/testlibs/Android.bp
index 5ba56bb..f5aad92 100644
--- a/media/libeffects/testlibs/Android.bp
+++ b/media/libeffects/testlibs/Android.bp
@@ -33,10 +33,10 @@
     relative_install_path: "soundfx",
 
     cflags: [
-        "-fvisibility=hidden",
         "-Wall",
         "-Werror",
         "-Wno-address-of-packed-member",
+        "-fvisibility=hidden",
     ],
 
     header_libs: [
@@ -66,9 +66,9 @@
     relative_install_path: "soundfx",
 
     cflags: [
-        "-fvisibility=hidden",
         "-Wall",
         "-Werror",
+        "-fvisibility=hidden",
     ],
 
     header_libs: [
diff --git a/media/libeffects/visualizer/Android.bp b/media/libeffects/visualizer/Android.bp
index 66ceadf..8f1d8da 100644
--- a/media/libeffects/visualizer/Android.bp
+++ b/media/libeffects/visualizer/Android.bp
@@ -54,9 +54,9 @@
 cc_library_shared {
     name: "libvisualizeraidl",
     srcs: [
+        ":effectCommonFile",
         "aidl/Visualizer.cpp",
         "aidl/VisualizerContext.cpp",
-        ":effectCommonFile",
     ],
     defaults: [
         "aidlaudioeffectservice_defaults",
diff --git a/media/libnbaio/Android.bp b/media/libnbaio/Android.bp
index 434ae00..158900a 100644
--- a/media/libnbaio/Android.bp
+++ b/media/libnbaio/Android.bp
@@ -15,8 +15,8 @@
         "NBAIO.cpp",
     ],
     header_libs: [
-        "libaudioclient_headers",
         "libaudio_system_headers",
+        "libaudioclient_headers",
     ],
     export_header_lib_headers: [
         "libaudioclient_headers",
@@ -35,8 +35,8 @@
     export_include_dirs: ["include_mono"],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 }
 
diff --git a/media/libnblog/Android.bp b/media/libnblog/Android.bp
index 8cfece6..b4d48b0 100644
--- a/media/libnblog/Android.bp
+++ b/media/libnblog/Android.bp
@@ -35,8 +35,8 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     include_dirs: ["system/media/audio_utils/include"],
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 1a0bb7f..46703bb 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -48,6 +48,9 @@
 static const int64_t kBufferTimeOutUs = 10000LL; // 10 msec
 static const size_t kRetryCount = 100; // must be >0
 static const int64_t kDefaultSampleDurationUs = 33333LL; // 33ms
+// For codec, 0 is the highest importance; higher the number lesser important.
+// To make codec for thumbnail less important, give it a value more than 0.
+static const int kThumbnailImportance = 1;
 
 sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
         int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
@@ -585,6 +588,9 @@
         }
     }
 
+    // Set the importance for thumbnail.
+    videoFormat->setInt32(KEY_IMPORTANCE, kThumbnailImportance);
+
     int32_t frameRate;
     if (trackMeta()->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
         mDefaultSampleDurationUs = 1000000LL / frameRate;
@@ -902,6 +908,10 @@
         videoFormat->setInt32("android._num-input-buffers", 1);
         videoFormat->setInt32("android._num-output-buffers", 1);
     }
+
+    /// Set the importance for thumbnail.
+    videoFormat->setInt32(KEY_IMPORTANCE, kThumbnailImportance);
+
     return videoFormat;
 }
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index e79e55b..e4f3b83 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -3395,9 +3395,6 @@
     if (bufferInfos == nullptr || bufferInfos->value.empty()) {
         return BAD_VALUE;
     }
-    if (cryptoInfos == nullptr || cryptoInfos->value.empty()) {
-        return BAD_VALUE;
-    }
     status_t err = OK;
     sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
     msg->setSize("index", index);
@@ -3405,8 +3402,12 @@
         new WrapperObject<sp<hardware::HidlMemory>>{buffer}};
     msg->setObject("memory", memory);
     msg->setSize("offset", offset);
-    msg->setSize("ssize", size);
-    msg->setObject("cryptoInfos", cryptoInfos);
+    if (cryptoInfos != nullptr) {
+        msg->setSize("ssize", size);
+        msg->setObject("cryptoInfos", cryptoInfos);
+    } else {
+        msg->setSize("size", size);
+    }
     msg->setObject("accessUnitInfo", bufferInfos);
     if (OK != (err = generateFlagsFromAccessUnitInfo(msg, bufferInfos))) {
         return err;
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index 5dd8423..dd6da15 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -1,13 +1,4 @@
 {
-  "postsubmit": [
-    // writerTest fails about 5 out of 66
-    // { "name": "writerTest" },
-
-    { "name": "HEVCUtilsUnitTest" },
-    { "name": "ExtractorFactoryTest" }
-
-  ],
-
   "presubmit-large": [
     {
       "name": "CtsMediaMiscTestCases",
@@ -92,8 +83,16 @@
     }
   ],
   "postsubmit": [
+    // writerTest fails about 5 out of 66
+    // { "name": "writerTest" },
     {
        "name": "BatteryChecker_test"
+    },
+    {
+        "name": "ExtractorFactoryTest"
+    },
+    {
+        "name": "HEVCUtilsUnitTest"
     }
   ]
 }
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 959f43e..458ac9c 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -626,6 +626,10 @@
             // ACodec is waiting for all buffers to be returned, do NOT
             // submit any more buffers to the codec.
             bufferSource->onOmxIdle();
+        } else if (param == OMX_StateExecuting) {
+            // Initiating transition from Idle -> Executing
+            // Start submitting buffers to codec.
+            bufferSource->onOmxExecuting();
         } else if (param == OMX_StateLoaded) {
             // Initiating transition from Idle/Executing -> Loaded
             // Buffers are about to be freed.
@@ -2404,13 +2408,6 @@
             asString(event), event, arg1String, arg1, arg2String, arg2);
     const sp<IOMXBufferSource> bufferSource(getBufferSource());
 
-    if (bufferSource != NULL
-            && event == OMX_EventCmdComplete
-            && arg1 == OMX_CommandStateSet
-            && arg2 == OMX_StateExecuting) {
-        bufferSource->onOmxExecuting();
-    }
-
     // allow configuration if we return to the loaded state
     if (event == OMX_EventCmdComplete
             && arg1 == OMX_CommandStateSet
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 6ed3e0e..723131d 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -10,8 +10,6 @@
 cc_library_static {
     name: "libstagefright_webm",
 
-    cppflags: ["-D__STDINT_LIMITS"],
-
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index d096d63..7a49d8e 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -134,6 +134,8 @@
     ],
 
     dictionary: "mp4_extractor_fuzzer.dict",
+
+    corpus: ["corpus_mp4/*"],
 }
 
 cc_fuzz {
@@ -202,7 +204,6 @@
         "ogg_extractor_fuzzer.cpp",
     ],
 
-
     static_libs: [
         "libstagefright_metadatautils",
         "libvorbisidec",
diff --git a/media/module/extractors/fuzzers/corpus_mp4/164a5bad5340b262316f93932c4160813657e1e0 b/media/module/extractors/fuzzers/corpus_mp4/164a5bad5340b262316f93932c4160813657e1e0
new file mode 100644
index 0000000..c17251b
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/164a5bad5340b262316f93932c4160813657e1e0
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/24f242f3b30fd5c2ff0f9aebed4375a3ab5cdceb b/media/module/extractors/fuzzers/corpus_mp4/24f242f3b30fd5c2ff0f9aebed4375a3ab5cdceb
new file mode 100644
index 0000000..16907fd
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/24f242f3b30fd5c2ff0f9aebed4375a3ab5cdceb
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/2a017927fdab79a8cc3b0bb75224cb44f4c1b35b b/media/module/extractors/fuzzers/corpus_mp4/2a017927fdab79a8cc3b0bb75224cb44f4c1b35b
new file mode 100644
index 0000000..2ec7881
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/2a017927fdab79a8cc3b0bb75224cb44f4c1b35b
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/58b3155e64ac16e4e6c68b68257871bcd769b92f b/media/module/extractors/fuzzers/corpus_mp4/58b3155e64ac16e4e6c68b68257871bcd769b92f
new file mode 100644
index 0000000..cd1fdcc
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/58b3155e64ac16e4e6c68b68257871bcd769b92f
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/64093d4da00ba406310c7679cd8b37562e6344b5 b/media/module/extractors/fuzzers/corpus_mp4/64093d4da00ba406310c7679cd8b37562e6344b5
new file mode 100644
index 0000000..f1ea812
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/64093d4da00ba406310c7679cd8b37562e6344b5
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/7355066d4975de07e9b6d0e9907c896eeb90577a b/media/module/extractors/fuzzers/corpus_mp4/7355066d4975de07e9b6d0e9907c896eeb90577a
new file mode 100644
index 0000000..c5d3eb2
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/7355066d4975de07e9b6d0e9907c896eeb90577a
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/7a48b0237581c794097a15add08517b3c6dc0aa2 b/media/module/extractors/fuzzers/corpus_mp4/7a48b0237581c794097a15add08517b3c6dc0aa2
new file mode 100644
index 0000000..1f6c29d
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/7a48b0237581c794097a15add08517b3c6dc0aa2
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/8706f07041a0cf828a7b40d727533d6c732b5ebc b/media/module/extractors/fuzzers/corpus_mp4/8706f07041a0cf828a7b40d727533d6c732b5ebc
new file mode 100644
index 0000000..40d639d
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/8706f07041a0cf828a7b40d727533d6c732b5ebc
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/911a46d40d60b9a806dbdc70799048df2f546615 b/media/module/extractors/fuzzers/corpus_mp4/911a46d40d60b9a806dbdc70799048df2f546615
new file mode 100644
index 0000000..2056348
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/911a46d40d60b9a806dbdc70799048df2f546615
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/97b1d0e78525c793574cce3e66f86564c2a10271 b/media/module/extractors/fuzzers/corpus_mp4/97b1d0e78525c793574cce3e66f86564c2a10271
new file mode 100644
index 0000000..f50d4f4
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/97b1d0e78525c793574cce3e66f86564c2a10271
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/d52e7095534fdf1f040b10a80df4cbc069a97a4e b/media/module/extractors/fuzzers/corpus_mp4/d52e7095534fdf1f040b10a80df4cbc069a97a4e
new file mode 100644
index 0000000..25ea55b
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/d52e7095534fdf1f040b10a80df4cbc069a97a4e
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/ec6bd6069f74a2f6e92442f88efb29288ad6f456 b/media/module/extractors/fuzzers/corpus_mp4/ec6bd6069f74a2f6e92442f88efb29288ad6f456
new file mode 100644
index 0000000..62d259b
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/ec6bd6069f74a2f6e92442f88efb29288ad6f456
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus_mp4/faa22bcb745206340d5d411b498a3868d2b1feec b/media/module/extractors/fuzzers/corpus_mp4/faa22bcb745206340d5d411b498a3868d2b1feec
new file mode 100644
index 0000000..d649632
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus_mp4/faa22bcb745206340d5d411b498a3868d2b1feec
Binary files differ
diff --git a/media/module/extractors/fuzzers/mp4_extractor_fuzzer.dict b/media/module/extractors/fuzzers/mp4_extractor_fuzzer.dict
index 3683649..b48c854 100644
--- a/media/module/extractors/fuzzers/mp4_extractor_fuzzer.dict
+++ b/media/module/extractors/fuzzers/mp4_extractor_fuzzer.dict
@@ -246,3 +246,4 @@
 kw245="iso5"
 kw246="resv"
 kw247="iso6"
+kw248="clap"
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index c4f2808..4926e46 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
 #define LOG_TAG "ServiceUtilities"
 
 #include <audio_utils/clock.h>
@@ -113,8 +114,9 @@
     return std::optional<AttributionSourceState>{myAttributionSource};
 }
 
-static bool checkRecordingInternal(const AttributionSourceState& attributionSource,
-        const String16& msg, bool start, audio_source_t source) {
+    static bool checkRecordingInternal(const AttributionSourceState &attributionSource,
+                                       const uint32_t virtualDeviceId,
+                                       const String16 &msg, bool start, audio_source_t source) {
     // Okay to not track in app ops as audio server or media server is us and if
     // device is rooted security model is considered compromised.
     // system_server loses its RECORD_AUDIO permission when a secondary
@@ -126,7 +128,7 @@
     // 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 =
+    std::optional<AttributionSourceState> resolvedAttributionSource =
             resolveAttributionSource(attributionSource);
     if (!resolvedAttributionSource.has_value()) {
         return false;
@@ -135,6 +137,7 @@
     const int32_t attributedOpCode = getOpForSource(source);
 
     permission::PermissionChecker permissionChecker;
+    resolvedAttributionSource.value().deviceId = virtualDeviceId;
     bool permitted = false;
     if (start) {
         permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
@@ -149,13 +152,24 @@
     return permitted;
 }
 
-bool recordingAllowed(const AttributionSourceState& attributionSource, audio_source_t source) {
-    return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source);
+static constexpr int DEVICE_ID_DEFAULT = 0;
+
+bool recordingAllowed(const AttributionSourceState &attributionSource, audio_source_t source) {
+    return checkRecordingInternal(attributionSource, DEVICE_ID_DEFAULT, String16(), /*start*/ false,
+                                  source);
+}
+
+bool recordingAllowed(const AttributionSourceState &attributionSource,
+                      const uint32_t virtualDeviceId,
+                      audio_source_t source) {
+    return checkRecordingInternal(attributionSource, virtualDeviceId,
+                                  String16(), /*start*/ false, source);
 }
 
 bool startRecording(const AttributionSourceState& attributionSource, const String16& msg,
         audio_source_t source) {
-    return checkRecordingInternal(attributionSource, msg, /*start*/ true, source);
+    return checkRecordingInternal(attributionSource, DEVICE_ID_DEFAULT, msg, /*start*/ true,
+                                  source);
 }
 
 void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source) {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 0b3a3f9..aa9e120 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -87,6 +87,10 @@
 
 bool recordingAllowed(const AttributionSourceState& attributionSource,
         audio_source_t source = AUDIO_SOURCE_DEFAULT);
+
+bool recordingAllowed(const AttributionSourceState &attributionSource,
+                      uint32_t virtualDeviceId,
+                      audio_source_t source);
 bool startRecording(const AttributionSourceState& attributionSource,
     const String16& msg, audio_source_t source);
 void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source);
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 129541f..3652aa2 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -66,12 +66,12 @@
 
     // Remove some pedantic stylistic requirements.
     "-google-readability-casting", // C++ casts not always necessary and may be verbose
-    "-google-readability-todo",    // do not require TODO(info)
+    "-google-readability-todo", // do not require TODO(info)
 
-    "-bugprone-unhandled-self-assignment",
-    "-bugprone-suspicious-string-compare",
-    "-cert-oop54-cpp", // found in TransactionLog.h
     "-bugprone-narrowing-conversions", // b/182410845
+    "-bugprone-suspicious-string-compare",
+    "-bugprone-unhandled-self-assignment",
+    "-cert-oop54-cpp", // found in TransactionLog.h
 ]
 
 // TODO(b/275642749) Reenable these warnings
@@ -101,9 +101,9 @@
     "-Wall",
     "-Wdeprecated",
     "-Werror",
+    "-Werror=conditional-uninitialized",
     "-Werror=implicit-fallthrough",
     "-Werror=sometimes-uninitialized",
-    "-Werror=conditional-uninitialized",
     "-Wextra",
 
     // suppress some warning chatter.
@@ -113,9 +113,9 @@
     "-Wredundant-decls",
     "-Wshadow",
     "-Wstrict-aliasing",
-    "-fstrict-aliasing",
     "-Wthread-safety",
     //"-Wthread-safety-negative", // experimental - looks broken in R.
+    "-fstrict-aliasing",
     "-Wunreachable-code",
     "-Wunreachable-code-break",
     "-Wunreachable-code-return",
@@ -134,7 +134,7 @@
     tidy_checks: audioflinger_tidy_errors,
     tidy_checks_as_errors: audioflinger_tidy_errors,
     tidy_flags: [
-      "-format-style=file",
+        "-format-style=file",
     ],
 }
 
@@ -142,49 +142,48 @@
     name: "libaudioflinger_dependencies",
 
     shared_libs: [
-        "audioflinger-aidl-cpp",
         "audioclient-types-aidl-cpp",
+        "audioflinger-aidl-cpp",
         "av-types-aidl-cpp",
         "com.android.media.audio-aconfig-cc",
         "effect-aidl-cpp",
-        "libaudioclient_aidl_conversion",
         "libactivitymanager_aidl",
+        "libaudioclient",
+        "libaudioclient_aidl_conversion",
         "libaudioflinger_datapath",
         "libaudioflinger_fastpath",
         "libaudioflinger_timing",
         "libaudioflinger_utils",
         "libaudiofoundation",
         "libaudiohal",
+        "libaudiomanager",
         "libaudioprocessing",
         "libaudioutils",
-        "libcutils",
-        "libutils",
-        "liblog",
         "libbinder",
         "libbinder_ndk",
-        "libaudioclient",
-        "libaudiomanager",
+        "libcutils",
+        "liblog",
+        "libmedia_helper",
         "libmediametrics",
         "libmediautils",
+        "libmemunreachable",
         "libnbaio",
         "libnblog",
         "libpermission",
         "libpowermanager",
-        "libmemunreachable",
-        "libmedia_helper",
         "libshmemcompat",
         "libsounddose",
+        "libutils",
         "libvibrator",
         "packagemanager_aidl-cpp",
     ],
 
     static_libs: [
-        "libmedialogservice",
         "libaudiospdif",
+        "libmedialogservice",
     ],
 }
 
-
 cc_library {
     name: "libaudioflinger",
 
@@ -231,9 +230,9 @@
     ],
 
     cflags: [
-        "-fvisibility=hidden",
-        "-Werror",
         "-Wall",
+        "-Werror",
+        "-fvisibility=hidden",
     ],
     sanitize: {
         integer_overflow: true,
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index a4c5099..012c2fe 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -31,6 +31,7 @@
 #include <media/AudioContainers.h>
 #include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioEffect.h>
+#include <media/EffectClientAsyncProxy.h>
 #include <media/ShmemCompat.h>
 #include <media/TypeConverter.h>
 #include <media/audiohal/EffectHalInterface.h>
@@ -1545,13 +1546,16 @@
         return INVALID_OPERATION;
     }
 
-    std::vector<uint8_t> request(sizeof(effect_param_t) + 3 * sizeof(uint32_t));
+    std::vector<uint8_t> request(sizeof(effect_param_t) + 3 * sizeof(uint32_t) + sizeof(float));
     effect_param_t *param = (effect_param_t*) request.data();
     param->psize = sizeof(int32_t);
-    param->vsize = sizeof(int32_t) * 2;
+    param->vsize = sizeof(int32_t) * 2 + sizeof(float);
     *(int32_t*)param->data = HG_PARAM_HAPTIC_INTENSITY;
-    *((int32_t*)param->data + 1) = id;
-    *((int32_t*)param->data + 2) = static_cast<int32_t>(hapticScale.getLevel());
+    int32_t* hapticScalePtr = reinterpret_cast<int32_t*>(param->data + sizeof(int32_t));
+    hapticScalePtr[0] = id;
+    hapticScalePtr[1] = static_cast<int32_t>(hapticScale.getLevel());
+    float* adaptiveScaleFactorPtr = reinterpret_cast<float*>(param->data + 3 * sizeof(int32_t));
+    *adaptiveScaleFactorPtr = hapticScale.getAdaptiveScaleFactor();
     std::vector<uint8_t> response;
     status_t status = command(EFFECT_CMD_SET_PARAM, request, sizeof(int32_t), &response);
     if (status == NO_ERROR) {
@@ -1726,7 +1730,8 @@
                                          const sp<media::IEffectClient>& effectClient,
                                          int32_t priority, bool notifyFramesProcessed)
     : BnEffect(),
-    mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
+    mEffect(effect), mEffectClient(media::EffectClientAsyncProxy::makeIfNeeded(effectClient)),
+    mClient(client), mCblk(nullptr),
     mPriority(priority), mHasControl(false), mEnabled(false), mDisconnected(false),
     mNotifyFramesProcessed(notifyFramesProcessed)
 {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c9ef69f..f9a093a 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2928,7 +2928,6 @@
 
             // Set haptic intensity for effect
             if (chain != nullptr) {
-                // TODO(b/324559333): Add adaptive haptics scaling support for the HapticGenerator.
                 chain->setHapticScale_l(track->id(), hapticScale);
             }
         }
@@ -3510,7 +3509,7 @@
             char *endptr;
             unsigned long ul = strtoul(value, &endptr, 0);
             if (*endptr == '\0' && ul != 0) {
-                ALOGD("Silence is golden");
+                ALOGW("%s: mute from ro.audio.silent. Silence is golden", __func__);
                 // The setprop command will not allow a property to be changed after
                 // the first time it is set, so we don't have to worry about un-muting.
                 setMasterMute_l(true);
@@ -7896,6 +7895,11 @@
     if (mSupportedLatencyModes.empty()) {
         return;
     }
+    // Do not update the HAL latency mode if no track is active
+    if (mActiveTracks.isEmpty()) {
+        return;
+    }
+
     audio_latency_mode_t latencyMode = AUDIO_LATENCY_MODE_FREE;
     if (mSupportedLatencyModes.size() == 1) {
         // If the HAL only support one latency mode currently, confirm the choice
@@ -8214,7 +8218,6 @@
     inputStandBy();
 
 reacquire_wakelock:
-    sp<IAfRecordTrack> activeTrack;
     {
         audio_utils::lock_guard _l(mutex());
         acquireWakeLock_l();
@@ -8230,6 +8233,8 @@
 
     // loop while there is work to do
     for (int64_t loopCount = 0;; ++loopCount) {  // loopCount used for statistics tracking
+        // Note: these sp<> are released at the end of the for loop outside of the mutex() lock.
+        sp<IAfRecordTrack> activeTrack;
         Vector<sp<IAfEffectChain>> effectChains;
 
         // activeTracks accumulates a copy of a subset of mActiveTracks
diff --git a/services/audioflinger/afutils/Android.bp b/services/audioflinger/afutils/Android.bp
index 5e29ce9..e147266 100644
--- a/services/audioflinger/afutils/Android.bp
+++ b/services/audioflinger/afutils/Android.bp
@@ -23,7 +23,7 @@
     tidy_checks: audioflinger_utils_tidy_errors,
     tidy_checks_as_errors: audioflinger_utils_tidy_errors,
     tidy_flags: [
-      "-format-style=file",
+        "-format-style=file",
     ],
 }
 
@@ -64,10 +64,10 @@
     ],
 
     header_libs: [
-        "libaaudio_headers",  // PropertyUtils.cpp
+        "libaaudio_headers", // PropertyUtils.cpp
     ],
 
     include_dirs: [
-        "frameworks/av/services/audioflinger",  // for configuration
+        "frameworks/av/services/audioflinger", // for configuration
     ],
 }
diff --git a/services/audioflinger/afutils/NBAIO_Tee.cpp b/services/audioflinger/afutils/NBAIO_Tee.cpp
index 86fb128..cdc8e95 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.cpp
+++ b/services/audioflinger/afutils/NBAIO_Tee.cpp
@@ -514,6 +514,12 @@
     return NO_ERROR; // return full path
 }
 
+/* static */
+NBAIO_Tee::RunningTees& NBAIO_Tee::getRunningTees() {
+    [[clang::no_destroy]] static RunningTees runningTees;
+    return runningTees;
+}
+
 } // namespace android
 
 #endif // TEE_SINK
diff --git a/services/audioflinger/afutils/NBAIO_Tee.h b/services/audioflinger/afutils/NBAIO_Tee.h
index a5c544e..5ab1949 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.h
+++ b/services/audioflinger/afutils/NBAIO_Tee.h
@@ -310,10 +310,7 @@
     };
 
     // singleton
-    static RunningTees &getRunningTees() {
-        static RunningTees runningTees;
-        return runningTees;
-    }
+    static RunningTees& getRunningTees();
 
     // The NBAIO TeeImpl may have lifetime longer than NBAIO_Tee if
     // RunningTees::dump() is being called simultaneous to ~NBAIO_Tee().
diff --git a/services/audioflinger/datapath/Android.bp b/services/audioflinger/datapath/Android.bp
index 4235f14..6918881 100644
--- a/services/audioflinger/datapath/Android.bp
+++ b/services/audioflinger/datapath/Android.bp
@@ -29,7 +29,7 @@
     tidy_checks: audioflinger_datapath_tidy_errors,
     tidy_checks_as_errors: audioflinger_datapath_tidy_errors,
     tidy_flags: [
-      "-format-style=file",
+        "-format-style=file",
     ],
 }
 
@@ -70,6 +70,6 @@
     ],
 
     include_dirs: [
-        "frameworks/av/services/audioflinger",  // for configuration
+        "frameworks/av/services/audioflinger", // for configuration
     ],
 }
diff --git a/services/audioflinger/fastpath/Android.bp b/services/audioflinger/fastpath/Android.bp
index 84a580f..5ebc583 100644
--- a/services/audioflinger/fastpath/Android.bp
+++ b/services/audioflinger/fastpath/Android.bp
@@ -24,7 +24,7 @@
     tidy_checks: fastpath_tidy_errors,
     tidy_checks_as_errors: fastpath_tidy_errors,
     tidy_flags: [
-      "-format-style=file",
+        "-format-style=file",
     ],
 }
 
diff --git a/services/audioflinger/sounddose/Android.bp b/services/audioflinger/sounddose/Android.bp
index 2cab5d1..884622e 100644
--- a/services/audioflinger/sounddose/Android.bp
+++ b/services/audioflinger/sounddose/Android.bp
@@ -29,7 +29,7 @@
     tidy_checks: audioflinger_sounddose_tidy_errors,
     tidy_checks_as_errors: audioflinger_sounddose_tidy_errors,
     tidy_flags: [
-      "-format-style=file",
+        "-format-style=file",
     ],
 }
 
@@ -40,9 +40,9 @@
 
     defaults: [
         "audioflinger_sounddose_flags_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_core_sounddose_ndk_shared",
         "latest_android_hardware_audio_sounddose_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
     ],
 
     srcs: [
@@ -66,9 +66,9 @@
     ],
 
     cflags: [
+        "-DBACKEND_NDK",
         "-Wall",
         "-Werror",
-        "-DBACKEND_NDK",
     ],
 }
 
diff --git a/services/audioflinger/sounddose/tests/Android.bp b/services/audioflinger/sounddose/tests/Android.bp
index 60e170d..fcbebe1 100644
--- a/services/audioflinger/sounddose/tests/Android.bp
+++ b/services/audioflinger/sounddose/tests/Android.bp
@@ -16,9 +16,9 @@
     ],
 
     defaults: [
-        "latest_android_media_audio_common_types_ndk_static",
         "latest_android_hardware_audio_core_sounddose_ndk_static",
         "latest_android_hardware_audio_sounddose_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
     ],
 
     shared_libs: [
@@ -43,10 +43,10 @@
     ],
 
     cflags: [
+        "-DBACKEND_NDK",
         "-Wall",
         "-Werror",
         "-Wextra",
-        "-DBACKEND_NDK",
     ],
 
     test_suites: [
diff --git a/services/audioflinger/timing/Android.bp b/services/audioflinger/timing/Android.bp
index 30ebca0..2666ddb 100644
--- a/services/audioflinger/timing/Android.bp
+++ b/services/audioflinger/timing/Android.bp
@@ -29,7 +29,7 @@
     tidy_checks: audioflinger_timing_tidy_errors,
     tidy_checks_as_errors: audioflinger_timing_tidy_errors,
     tidy_flags: [
-      "-format-style=file",
+        "-format-style=file",
     ],
 }
 
diff --git a/services/audioparameterparser/Android.bp b/services/audioparameterparser/Android.bp
index b3da333..f5feece 100644
--- a/services/audioparameterparser/Android.bp
+++ b/services/audioparameterparser/Android.bp
@@ -45,8 +45,8 @@
 
     cflags: [
         "-Wall",
-        "-Wextra",
         "-Werror",
+        "-Wextra",
         "-Wthread-safety",
     ],
 }
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index bfc3132..8f17ffc 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -166,7 +166,8 @@
                                      audio_input_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId,
                                      input_type_t *inputType,
-                                     audio_port_handle_t *portId) = 0;
+                                     audio_port_handle_t *portId,
+                                     uint32_t *virtualDeviceId) = 0;
     // indicates to the audio policy manager that the input starts being used.
     virtual status_t startInput(audio_port_handle_t portId) = 0;
     // indicates to the audio policy manager that the input stops being used.
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
index a2ebb8d..cf1a771 100644
--- a/services/audiopolicy/TEST_MAPPING
+++ b/services/audiopolicy/TEST_MAPPING
@@ -46,6 +46,9 @@
           "include-filter": "com.google.android.gts.audio.AudioPolicyHostTest"
         }
       ]
+    },
+    {
+      "name": "spatializer_tests"
     }
   ]
 }
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 7c70877..00958aa 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#define __STDC_LIMIT_MACROS
 #include <inttypes.h>
 
 #include <sys/types.h>
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 6f71ac5..44f84b9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -235,7 +235,8 @@
                                                   &deviceType,
                                                   String8(mDevice->address().c_str()),
                                                   source,
-                                                  flags);
+                                                  static_cast<audio_input_flags_t>(
+                                                          flags & mProfile->getFlags()));
     LOG_ALWAYS_FATAL_IF(mDevice->type() != deviceType,
                         "%s openInput returned device %08x when given device %08x",
                         __FUNCTION__, mDevice->type(), deviceType);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index d1819fd..3430f4b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -30,7 +30,7 @@
 #include <AudioOutputDescriptor.h>
 #include <android_media_audiopolicy.h>
 
-namespace audio_flags = android::media::audiopolicy;
+namespace audiopolicy_flags = android::media::audiopolicy;
 
 namespace android {
 namespace {
@@ -193,7 +193,7 @@
                     mix.mDeviceType, mix.mDeviceAddress.c_str());
             return BAD_VALUE;
         }
-        if (audio_flags::audio_mix_ownership()) {
+        if (audiopolicy_flags::audio_mix_ownership()) {
             if (mix.mToken == registeredMix->mToken) {
                 ALOGE("registerMix(): same mix already registered - skipping");
                 return BAD_VALUE;
@@ -221,7 +221,7 @@
 {
     for (size_t i = 0; i < size(); i++) {
         const sp<AudioPolicyMix>& registeredMix = itemAt(i);
-        if (audio_flags::audio_mix_ownership()) {
+        if (audiopolicy_flags::audio_mix_ownership()) {
             if (mix.mToken == registeredMix->mToken) {
                 ALOGD("unregisterMix(): removing mix for dev=0x%x addr=%s",
                       mix.mDeviceType, mix.mDeviceAddress.c_str());
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index a93c816..9e07d79 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -32,10 +32,10 @@
     name: "libaudiopolicyengine_common",
     srcs: [
         "src/EngineBase.cpp",
+        "src/LastRemovableMediaDevices.cpp",
         "src/ProductStrategy.cpp",
         "src/VolumeCurve.cpp",
         "src/VolumeGroup.cpp",
-        "src/LastRemovableMediaDevices.cpp",
     ],
     cflags: [
         "-Wall",
@@ -43,10 +43,10 @@
         "-Wextra",
     ],
     header_libs: [
-        "libbase_headers",
         "libaudiopolicycommon",
         "libaudiopolicyengine_common_headers",
         "libaudiopolicyengine_interface_headers",
+        "libbase_headers",
     ],
     export_header_lib_headers: [
         "libaudiopolicyengine_common_headers",
@@ -59,7 +59,7 @@
         "libaudiopolicycomponents",
     ],
     whole_static_libs: [
-        "server_configurable_flags",
         "com.android.media.audio-aconfig-cc",
+        "server_configurable_flags",
     ],
 }
diff --git a/services/audiopolicy/engine/common/src/VolumeCurve.cpp b/services/audiopolicy/engine/common/src/VolumeCurve.cpp
index fccbc60..9411155 100644
--- a/services/audiopolicy/engine/common/src/VolumeCurve.cpp
+++ b/services/audiopolicy/engine/common/src/VolumeCurve.cpp
@@ -69,7 +69,7 @@
         return mCurvePoints[nbCurvePoints - 1].mAttenuationInMb / 100.0f;
     }
     if (indexInUiPosition == 0) {
-        if (indexInUiPosition != mCurvePoints[0].mIndex) {
+        if ((size_t)volIdx != mCurvePoints[0].mIndex) {
             return VOLUME_MIN_DB; // out of bounds
         }
         return mCurvePoints[0].mAttenuationInMb / 100.0f;
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
index 0864e6a..ab2c134 100644
--- a/services/audiopolicy/engine/config/Android.bp
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -33,7 +33,7 @@
     ],
     header_libs: [
         "libaudio_system_headers",
-        "libmedia_headers",
         "libaudioclient_headers",
+        "libmedia_headers",
     ],
 }
diff --git a/services/audiopolicy/engine/config/tests/Android.bp b/services/audiopolicy/engine/config/tests/Android.bp
index 8c7b7db..2df51d0 100644
--- a/services/audiopolicy/engine/config/tests/Android.bp
+++ b/services/audiopolicy/engine/config/tests/Android.bp
@@ -28,8 +28,8 @@
     data: [":audiopolicy_engineconfig_files"],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     test_suites: ["device-tests"],
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index d59ab5a..66df930 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -20,8 +20,8 @@
     srcs: [
         "src/Engine.cpp",
         "src/EngineInstance.cpp",
-        "src/Stream.cpp",
         "src/InputSource.cpp",
+        "src/Stream.cpp",
     ],
     cflags: [
         "-Wall",
@@ -30,10 +30,10 @@
     ],
     local_include_dirs: ["include"],
     header_libs: [
-        "libbase_headers",
         "libaudiopolicycommon",
         "libaudiopolicyengine_interface_headers",
         "libaudiopolicyengineconfigurable_interface_headers",
+        "libbase_headers",
     ],
     static_libs: [
         "libaudiopolicyengine_common",
@@ -44,14 +44,14 @@
     shared_libs: [
         "libaudio_aidl_conversion_common_cpp",
         "libaudiofoundation",
+        "libaudiopolicy",
         "libaudiopolicycomponents",
         "libbase",
-        "liblog",
         "libcutils",
-        "libutils",
+        "liblog",
         "libmedia_helper",
-        "libaudiopolicy",
         "libparameter",
+        "libutils",
         "libxml2",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
index fb1a71c..7e429ef 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
@@ -37,8 +37,8 @@
     vendor: true,
     src: ":audio_policy_engine_configuration",
     required: [
-        ":audio_policy_engine_criterion_types.xml",
         ":audio_policy_engine_criteria.xml",
+        ":audio_policy_engine_criterion_types.xml",
         ":audio_policy_engine_product_strategies.xml",
         ":audio_policy_engine_volumes.xml",
     ],
@@ -69,19 +69,19 @@
     name: "audio_policy_engine_criterion_types",
     defaults: ["buildpolicycriteriontypesrule"],
     srcs: [
-        ":audio_policy_configuration_top_file",
         ":audio_policy_configuration_files",
+        ":audio_policy_configuration_top_file",
     ],
 }
 
 filegroup {
     name: "audio_policy_configuration_files",
     srcs: [
-        ":r_submix_audio_policy_configuration",
-        ":default_volume_tables",
         ":audio_policy_volumes",
-        ":surround_sound_configuration_5_0",
+        ":default_volume_tables",
         ":primary_audio_policy_configuration",
+        ":r_submix_audio_policy_configuration",
+        ":surround_sound_configuration_5_0",
     ],
 }
 
@@ -104,9 +104,9 @@
     name: "audio_policy_engine_configuration_files",
     srcs: [
         ":audio_policy_engine_configuration",
-        "audio_policy_engine_product_strategies.xml",
-        ":audio_policy_engine_volumes",
-        ":audio_policy_engine_criterion_types",
         ":audio_policy_engine_criteria",
+        ":audio_policy_engine_criterion_types",
+        ":audio_policy_engine_volumes",
+        "audio_policy_engine_product_strategies.xml",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
index b9abb54..12a554d 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
@@ -18,8 +18,8 @@
 
 soong_namespace {
     imports: [
-        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
         "frameworks/av/services/audiopolicy/config",
+        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
     ],
 }
 
@@ -38,10 +38,10 @@
     vendor: true,
     src: ":audio_policy_engine_configuration",
     required: [
-        "audio_policy_engine_criterion_types.xml",
-        "audio_policy_engine_criteria.xml",
-        "audio_policy_engine_product_strategies.xml",
         ":audio_policy_engine_volumes.xml",
+        "audio_policy_engine_criteria.xml",
+        "audio_policy_engine_criterion_types.xml",
+        "audio_policy_engine_product_strategies.xml",
     ],
 }
 
@@ -64,19 +64,19 @@
     name: "audio_policy_engine_criterion_types",
     defaults: ["buildpolicycriteriontypesrule"],
     srcs: [
-        ":audio_policy_configuration_top_file",
         ":audio_policy_configuration_files",
+        ":audio_policy_configuration_top_file",
     ],
 }
 
 filegroup {
     name: "audio_policy_configuration_files",
     srcs: [
-        ":r_submix_audio_policy_configuration",
-        ":default_volume_tables",
         ":audio_policy_volumes",
-        ":surround_sound_configuration_5_0",
+        ":default_volume_tables",
         ":primary_audio_policy_configuration",
+        ":r_submix_audio_policy_configuration",
+        ":surround_sound_configuration_5_0",
     ],
 }
 
@@ -89,9 +89,9 @@
     name: "audio_policy_engine_configuration_files",
     srcs: [
         ":audio_policy_engine_configuration",
-        "audio_policy_engine_product_strategies.xml",
-        ":audio_policy_engine_volumes",
-        ":audio_policy_engine_criterion_types",
         ":audio_policy_engine_criteria",
+        ":audio_policy_engine_criterion_types",
+        ":audio_policy_engine_volumes",
+        "audio_policy_engine_product_strategies.xml",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
index 67a6128..b0a4dfd 100644
--- a/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
@@ -37,8 +37,8 @@
     vendor: true,
     src: ":audio_policy_engine_configuration",
     required: [
-        ":audio_policy_engine_criterion_types.xml",
         ":audio_policy_engine_criteria.xml",
+        ":audio_policy_engine_criterion_types.xml",
         ":audio_policy_engine_product_strategies.xml",
         ":audio_policy_engine_volumes.xml",
     ],
@@ -75,19 +75,19 @@
     name: "audio_policy_engine_criterion_types",
     defaults: ["buildpolicycriteriontypesrule"],
     srcs: [
-        ":audio_policy_configuration_top_file",
         ":audio_policy_configuration_files",
+        ":audio_policy_configuration_top_file",
     ],
 }
 
 filegroup {
     name: "audio_policy_configuration_files",
     srcs: [
-        ":r_submix_audio_policy_configuration",
-        ":default_volume_tables",
         ":audio_policy_volumes",
-        ":surround_sound_configuration_5_0",
+        ":default_volume_tables",
         ":primary_audio_policy_configuration",
+        ":r_submix_audio_policy_configuration",
+        ":surround_sound_configuration_5_0",
     ],
 }
 
@@ -115,10 +115,10 @@
     name: "audio_policy_engine_configuration_files",
     srcs: [
         ":audio_policy_engine_configuration",
-        "audio_policy_engine_product_strategies.xml",
-        ":audio_policy_engine_stream_volumes",
-        ":audio_policy_engine_default_stream_volumes",
-        ":audio_policy_engine_criterion_types",
         ":audio_policy_engine_criteria",
+        ":audio_policy_engine_criterion_types",
+        ":audio_policy_engine_default_stream_volumes",
+        ":audio_policy_engine_stream_volumes",
+        "audio_policy_engine_product_strategies.xml",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
index 38451f2..42585e9 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
@@ -18,8 +18,8 @@
 
 soong_namespace {
     imports: [
-        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
         "frameworks/av/services/audiopolicy/config",
+        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
     ],
 }
 
@@ -63,10 +63,10 @@
     src: ":domaingeneratorpolicyrule_gen",
     sub_dir: "parameter-framework/Settings/Policy",
     required: [
-        "ProductStrategies.xml",
         "PolicyClass.xml",
-        "PolicySubsystem.xml",
         "PolicySubsystem-CommonTypes.xml",
+        "PolicySubsystem.xml",
+        "ProductStrategies.xml",
     ],
 }
 
@@ -75,9 +75,9 @@
     enabled: false, // TODO: This module fails to build
     defaults: ["domaingeneratorpolicyrule"],
     srcs: [
-        ":audio_policy_pfw_toplevel",
-        ":audio_policy_pfw_structure_files",
         ":audio_policy_engine_criterion_types",
+        ":audio_policy_pfw_structure_files",
+        ":audio_policy_pfw_toplevel",
         ":edd_files",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
index eae6ae2..efde298 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
@@ -18,9 +18,9 @@
 
 soong_namespace {
     imports: [
+        "frameworks/av/services/audiopolicy/config",
         "frameworks/av/services/audiopolicy/engineconfigurable/config/example/caremu",
         "frameworks/av/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car",
-        "frameworks/av/services/audiopolicy/config",
     ],
 }
 
@@ -64,10 +64,10 @@
     src: ":domaingeneratorpolicyrule_gen",
     sub_dir: "parameter-framework/Settings/Policy",
     required: [
-        "ProductStrategies.xml",
         "PolicyClass.xml",
-        "PolicySubsystem.xml",
         "PolicySubsystem-CommonTypes.xml",
+        "PolicySubsystem.xml",
+        "ProductStrategies.xml",
     ],
 }
 
@@ -76,9 +76,9 @@
     enabled: false, // TODO: This module fails to build
     defaults: ["domaingeneratorpolicyrule"],
     srcs: [
-        ":audio_policy_pfw_toplevel",
-        ":audio_policy_pfw_structure_files",
         ":audio_policy_engine_criterion_types",
+        ":audio_policy_pfw_structure_files",
+        ":audio_policy_pfw_toplevel",
         ":edd_files",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
index 4e8654b..474094e 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
@@ -18,8 +18,8 @@
 
 soong_namespace {
     imports: [
-        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
         "frameworks/av/services/audiopolicy/config",
+        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
     ],
 }
 
@@ -63,10 +63,10 @@
     src: ":domaingeneratorpolicyrule_gen",
     sub_dir: "parameter-framework/Settings/Policy",
     required: [
-        "ProductStrategies.xml",
         "PolicyClass.xml",
-        "PolicySubsystem.xml",
         "PolicySubsystem-CommonTypes.xml",
+        "PolicySubsystem.xml",
+        "ProductStrategies.xml",
     ],
 }
 
@@ -75,9 +75,9 @@
     enabled: false, // TODO: This module fails to build
     defaults: ["domaingeneratorpolicyrule"],
     srcs: [
-        ":audio_policy_pfw_toplevel",
-        ":audio_policy_pfw_structure_files",
         ":audio_policy_engine_criterion_types",
+        ":audio_policy_pfw_structure_files",
+        ":audio_policy_pfw_toplevel",
         ":edd_files",
     ],
 }
@@ -87,16 +87,16 @@
     srcs: [
         ":device_for_input_source.pfw",
         ":volumes.pfw",
-        "Settings/device_for_product_strategy_media.pfw",
         "Settings/device_for_product_strategy_accessibility.pfw",
         "Settings/device_for_product_strategy_dtmf.pfw",
         "Settings/device_for_product_strategy_enforced_audible.pfw",
+        "Settings/device_for_product_strategy_media.pfw",
+        "Settings/device_for_product_strategy_patch.pfw",
         "Settings/device_for_product_strategy_phone.pfw",
+        "Settings/device_for_product_strategy_rerouting.pfw",
         "Settings/device_for_product_strategy_sonification.pfw",
         "Settings/device_for_product_strategy_sonification_respectful.pfw",
         "Settings/device_for_product_strategy_transmitted_through_speaker.pfw",
-        "Settings/device_for_product_strategy_rerouting.pfw",
-        "Settings/device_for_product_strategy_patch.pfw",
     ],
 }
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
index e279a8f..aba9767 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
@@ -18,8 +18,8 @@
 
 soong_namespace {
     imports: [
-        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
         "frameworks/av/services/audiopolicy/config",
+        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
     ],
 }
 
@@ -42,8 +42,8 @@
     sub_dir: "parameter-framework/Settings/Policy",
     required: [
         "PolicyClass.xml",
-        "PolicySubsystem.xml",
         "PolicySubsystem-CommonTypes.xml",
+        "PolicySubsystem.xml",
     ],
 }
 
@@ -52,9 +52,9 @@
     enabled: false, // TODO: This module fails to build
     defaults: ["domaingeneratorpolicyrule"],
     srcs: [
-        ":audio_policy_pfw_toplevel",
-        ":audio_policy_pfw_structure_files",
         ":audio_policy_engine_criterion_types",
+        ":audio_policy_pfw_structure_files",
+        ":audio_policy_pfw_toplevel",
         ":edd_files",
     ],
 }
@@ -76,8 +76,8 @@
 filegroup {
     name: "edd_files",
     srcs: [
-        "device_for_input_source.pfw",
         ":volumes.pfw",
+        "device_for_input_source.pfw",
     ],
 }
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
index 47b8b54..77677a1 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
@@ -18,8 +18,8 @@
 
 soong_namespace {
     imports: [
-        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
         "frameworks/av/services/audiopolicy/config",
+        "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
     ],
 }
 
@@ -42,8 +42,8 @@
     sub_dir: "parameter-framework/Settings/Policy",
     required: [
         "PolicyClass.xml",
-        "PolicySubsystem.xml",
         "PolicySubsystem-CommonTypes.xml",
+        "PolicySubsystem.xml",
     ],
 }
 
@@ -52,9 +52,9 @@
     enabled: false, // TODO: This module fails to build
     defaults: ["domaingeneratorpolicyrule"],
     srcs: [
-        ":audio_policy_pfw_toplevel",
-        ":audio_policy_pfw_structure_files",
         ":audio_policy_engine_criterion_types",
+        ":audio_policy_pfw_structure_files",
+        ":audio_policy_pfw_toplevel",
         ":edd_files",
     ],
 }
@@ -76,9 +76,9 @@
 filegroup {
     name: "edd_files",
     srcs: [
-        "device_for_strategies.pfw",
-        ":volumes.pfw",
         ":device_for_input_source.pfw",
+        ":volumes.pfw",
+        "device_for_strategies.pfw",
     ],
 }
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
index aa2163e..3dc2229 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
@@ -11,11 +11,11 @@
 cc_library_shared {
     name: "libpolicy-subsystem",
     srcs: [
-        "PolicySubsystemBuilder.cpp",
-        "PolicySubsystem.cpp",
         "InputSource.cpp",
-        "Stream.cpp",
+        "PolicySubsystem.cpp",
+        "PolicySubsystemBuilder.cpp",
         "ProductStrategy.cpp",
+        "Stream.cpp",
     ],
     cflags: [
         "-Wall",
@@ -25,11 +25,11 @@
         "-fvisibility=hidden",
     ],
     header_libs: [
-        "libbase_headers",
-        "libaudiopolicycommon",
         "libaudioclient_headers",
+        "libaudiopolicycommon",
         "libaudiopolicyengine_interface_headers",
         "libaudiopolicyengineconfigurable_interface_headers",
+        "libbase_headers",
     ],
     static_libs: [
         "libaudiopolicyengine_common",
@@ -39,8 +39,8 @@
         "libaudiopolicycomponents",
         "libaudiopolicyengineconfigurable",
         "liblog",
-        "libutils",
         "libmedia_helper",
         "libparameter",
+        "libutils",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index 2f77372..d1fb2fb 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -67,8 +67,8 @@
     ],
     libs: [
         "EddParser.py",
-        "hostConfig.py",
         "PFWScriptGenerator.py",
+        "hostConfig.py",
     ],
     required: [
         "domainGeneratorConnector",
@@ -78,8 +78,8 @@
 genrule_defaults {
     name: "domaingeneratorpolicyrule",
     tools: [
-        "domainGeneratorPolicy",
         "domainGeneratorConnector",
+        "domainGeneratorPolicy",
     ],
     cmd: "mkdir -p $(genDir)/Structure/Policy && " +
         "cp $(locations :audio_policy_pfw_structure_files) $(genDir)/Structure/Policy && " +
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.bp b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
index a897880..78d5fa3 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.bp
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
@@ -18,14 +18,14 @@
         "-Wextra",
     ],
     header_libs: [
-        "libbase_headers",
-        "libaudiopolicycommon",
         "libaudiofoundation_headers",
+        "libaudiopolicycommon",
+        "libbase_headers",
     ],
     shared_libs: [
         "liblog",
-        "libutils",
         "libmedia_helper",
         "libparameter",
+        "libutils",
     ],
 }
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 98adff0..7810d63 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -15,15 +15,15 @@
         "src/EngineInstance.cpp",
     ],
     cflags: [
-        "-fvisibility=hidden",
         "-Wall",
         "-Werror",
         "-Wextra",
+        "-fvisibility=hidden",
     ],
     header_libs: [
-        "libbase_headers",
         "libaudiopolicycommon",
         "libaudiopolicyengine_interface_headers",
+        "libbase_headers",
     ],
     static_libs: [
         "libaudiopolicyengine_common",
@@ -32,13 +32,13 @@
     shared_libs: [
         "libaudio_aidl_conversion_common_cpp",
         "libaudiofoundation",
+        "libaudiopolicy",
         "libaudiopolicycomponents",
         "libbase",
-        "liblog",
         "libcutils",
-        "libutils",
+        "liblog",
         "libmedia_helper",
-        "libaudiopolicy",
+        "libutils",
         "libxml2",
     ],
 }
diff --git a/services/audiopolicy/enginedefault/config/example/Android.bp b/services/audiopolicy/enginedefault/config/example/Android.bp
index f305c39..31f9a46 100644
--- a/services/audiopolicy/enginedefault/config/example/Android.bp
+++ b/services/audiopolicy/enginedefault/config/example/Android.bp
@@ -34,9 +34,9 @@
     vendor: true,
     src: "phone/audio_policy_engine_configuration.xml",
     required: [
-        ":audio_policy_engine_stream_volumes.xml",
         ":audio_policy_engine_default_stream_volumes.xml",
         ":audio_policy_engine_product_strategies.xml",
+        ":audio_policy_engine_stream_volumes.xml",
     ],
 }
 
diff --git a/services/audiopolicy/fuzzer/Android.bp b/services/audiopolicy/fuzzer/Android.bp
index fca02e4..8cee613 100644
--- a/services/audiopolicy/fuzzer/Android.bp
+++ b/services/audiopolicy/fuzzer/Android.bp
@@ -37,22 +37,22 @@
     shared_libs: [
         "android.hardware.audio.common-util",
         "capture_state_listener-aidl-cpp",
+        "framework-permission-aidl-cpp",
         "libaudioclient",
         "libaudiofoundation",
+        "libaudiopolicy",
         "libaudiopolicycomponents",
+        "libaudiopolicymanagerdefault",
         "libbase",
+        "libbinder",
         "libcutils",
-        "libhidlbase",
         "libdl",
+        "libhidlbase",
         "liblog",
         "libmedia_helper",
         "libmediametrics",
         "libutils",
         "libxml2",
-        "libbinder",
-        "libaudiopolicy",
-        "libaudiopolicymanagerdefault",
-        "framework-permission-aidl-cpp",
     ],
     static_libs: [
         "android.hardware.audio.common@7.0-enums",
diff --git a/services/audiopolicy/fuzzer/aidl/Android.bp b/services/audiopolicy/fuzzer/aidl/Android.bp
index 8b37d36..2c85955 100644
--- a/services/audiopolicy/fuzzer/aidl/Android.bp
+++ b/services/audiopolicy/fuzzer/aidl/Android.bp
@@ -26,30 +26,31 @@
         "audiopolicy-aidl-cpp",
         "audiopolicy-types-aidl-cpp",
         "framework-permission-aidl-cpp",
+        "libactivitymanager_aidl",
+        "libaudioclient",
+        "libaudioflinger",
+        "libaudiohal",
         "libaudiopolicy",
         "libaudiopolicymanagerdefault",
-        "libactivitymanager_aidl",
-        "libaudiohal",
         "libaudiopolicyservice",
-        "libaudioflinger",
-        "libaudioclient",
         "libaudioprocessing",
         "libhidlbase",
         "liblog",
         "libmediautils",
-        "libnblog",
         "libnbaio",
+        "libnblog",
         "libpowermanager",
         "libvibrator",
         "packagemanager_aidl-cpp",
     ],
     static_libs: [
+        "libaudiomockhal",
         "libfakeservicemanager",
         "libmediaplayerservice",
     ],
     header_libs: [
-        "libaudiohal_headers",
         "libaudioflinger_headers",
+        "libaudiohal_headers",
         "libaudiopolicymanager_interface_headers",
         "libbinder_headers",
         "libmedia_headers",
@@ -73,6 +74,9 @@
     srcs: ["audiopolicy_aidl_fuzzer.cpp"],
     defaults: [
         "audiopolicy_aidl_fuzzer_defaults",
+        "latest_android_hardware_audio_core_ndk_shared",
+        "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
         "service_fuzzer_defaults",
     ],
 }
diff --git a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
index ca79c49..3d972dc 100644
--- a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
@@ -18,8 +18,12 @@
 #include <AudioFlinger.h>
 #include <android-base/logging.h>
 #include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <android/media/IAudioPolicyService.h>
+#include <core-mock/ConfigMock.h>
+#include <core-mock/ModuleMock.h>
+#include <effect-mock/FactoryMock.h>
 #include <fakeservicemanager/FakeServiceManager.h>
 #include <fuzzbinder/libbinder_driver.h>
 #include <fuzzbinder/random_binder.h>
@@ -55,14 +59,26 @@
     });
     gFakeServiceManager->clear();
 
-    for (const char* service :
-         {"activity", "sensor_privacy", "permission", "scheduling_policy",
-          "android.hardware.audio.core.IConfig", "batterystats", "media.metrics"}) {
+    for (const char* service : {"activity", "sensor_privacy", "permission", "scheduling_policy",
+                                "batterystats", "media.metrics"}) {
         if (!addService(String16(service), gFakeServiceManager, fdp)) {
             return 0;
         }
     }
 
+    auto configService = ndk::SharedRefBase::make<ConfigMock>();
+    CHECK_EQ(NO_ERROR, AServiceManager_addService(configService.get()->asBinder().get(),
+                                                  "android.hardware.audio.core.IConfig/default"));
+
+    auto factoryService = ndk::SharedRefBase::make<FactoryMock>();
+    CHECK_EQ(NO_ERROR,
+             AServiceManager_addService(factoryService.get()->asBinder().get(),
+                                        "android.hardware.audio.effect.IFactory/default"));
+
+    auto moduleService = ndk::SharedRefBase::make<ModuleMock>();
+    CHECK_EQ(NO_ERROR, AServiceManager_addService(moduleService.get()->asBinder().get(),
+                                                  "android.hardware.audio.core.IModule/default"));
+
     const auto audioFlinger = sp<AudioFlinger>::make();
     const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
 
@@ -79,8 +95,7 @@
                                              false /* allowIsolated */,
                                              IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
 
-    fuzzService(media::IAudioPolicyService::asBinder(audioPolicyService),
-                FuzzedDataProvider(data, size));
+    fuzzService(media::IAudioPolicyService::asBinder(audioPolicyService), std::move(fdp));
 
     return 0;
 }
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 58fcb5c..6416a47 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -207,7 +207,8 @@
                          audio_port_handle_t *selectedDeviceId, audio_format_t format,
                          audio_channel_mask_t channelMask, int sampleRate,
                          audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
-                         audio_port_handle_t *portId = nullptr);
+                         audio_port_handle_t *portId = nullptr,
+                         uint32_t *virtualDeviceId = nullptr);
     bool findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
                         const std::string &address, audio_port_v7 *foundPort);
     static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch *patch);
@@ -283,7 +284,7 @@
 bool AudioPolicyManagerFuzzer::getInputForAttr(
     const audio_attributes_t &attr, audio_unique_id_t riid, audio_port_handle_t *selectedDeviceId,
     audio_format_t format, audio_channel_mask_t channelMask, int sampleRate,
-    audio_input_flags_t flags, audio_port_handle_t *portId) {
+    audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t *virtualDeviceId) {
     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
     audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
     config.sample_rate = sampleRate;
@@ -298,7 +299,7 @@
     attributionSource.uid = 0;
     attributionSource.token = sp<BBinder>::make();
     if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, attributionSource,
-            &config, flags, selectedDeviceId, &inputType, portId) != OK) {
+            &config, flags, selectedDeviceId, &inputType, portId, virtualDeviceId) != 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 2f46d48..c1b8705 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -25,26 +25,26 @@
     shared_libs: [
         "com.android.media.audio-aconfig-cc",
         "libaudiofoundation",
+        "libaudiopolicy",
         "libaudiopolicycomponents",
+        "libbinder",
         "libcutils",
         "libdl",
-        "libutils",
+        "libhidlbase",
         "liblog",
-        "libaudiopolicy",
         "libmedia_helper",
         "libmediametrics",
-        "libbinder",
-        "libhidlbase",
+        "libutils",
         "libxml2",
         // The default audio policy engine is always present in the system image.
         // libaudiopolicyengineconfigurable can be built in addition by specifying
         // a dependency on it in the device makefile. There will be no build time
         // conflict with libaudiopolicyenginedefault.
-        "libaudiopolicyenginedefault",
-        "framework-permission-aidl-cpp",
-        "libaudioclient_aidl_conversion",
         "audioclient-types-aidl-cpp",
         // Flag support
+        "framework-permission-aidl-cpp",
+        "libaudioclient_aidl_conversion",
+        "libaudiopolicyenginedefault",
         "android.media.audiopolicy-aconfig-cc",
         "com.android.media.audioserver-aconfig-cc",
     ],
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 8ef76c6..2dea379 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2697,7 +2697,8 @@
                                              audio_input_flags_t flags,
                                              audio_port_handle_t *selectedDeviceId,
                                              input_type_t *inputType,
-                                             audio_port_handle_t *portId)
+                                             audio_port_handle_t *portId,
+                                             uint32_t *virtualDeviceId)
 {
     ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
           "flags %#x attributes=%s requested device ID %d",
@@ -2799,6 +2800,9 @@
         } else {
             *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
         }
+        if (virtualDeviceId) {
+            *virtualDeviceId = policyMix->mVirtualDeviceId;
+        }
     } else {
         if (explicitRoutingDevice != nullptr) {
             device = explicitRoutingDevice;
@@ -2822,6 +2826,10 @@
             // meaning it receives audio injected into the framework, so the recorder doesn't
             // know about it and is therefore considered "legacy"
             *inputType = API_INPUT_LEGACY;
+
+            if (virtualDeviceId) {
+                *virtualDeviceId = policyMix->mVirtualDeviceId;
+            }
         } else if (audio_is_remote_submix_device(device->type())) {
             *inputType = API_INPUT_MIX_CAPTURE;
         } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
@@ -2853,6 +2861,11 @@
         goto error;
     }
 
+
+    if (policyMix != nullptr && virtualDeviceId != nullptr) {
+        *virtualDeviceId = policyMix->mVirtualDeviceId;
+    }
+
 exit:
 
     *selectedDeviceId = mAvailableInputDevices.contains(device) ?
@@ -3830,7 +3843,6 @@
 status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
 {
     ALOGV("unregisterPolicyMixes() num mixes %zu", mixes.size());
-    status_t endResult = NO_ERROR;
     status_t res = NO_ERROR;
     bool checkOutputs = false;
     sp<HwModule> rSubmixModule;
@@ -3843,7 +3855,6 @@
                         AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX);
                 if (rSubmixModule == 0) {
                     res = INVALID_OPERATION;
-                    endResult = INVALID_OPERATION;
                     continue;
                 }
             }
@@ -3852,20 +3863,25 @@
 
             if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
                 res = INVALID_OPERATION;
-                endResult = INVALID_OPERATION;
                 continue;
             }
 
-            for (auto device : {AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_DEVICE_OUT_REMOTE_SUBMIX}) {
+            for (auto device: {AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_DEVICE_OUT_REMOTE_SUBMIX}) {
                 if (getDeviceConnectionState(device, address.c_str()) ==
-                        AUDIO_POLICY_DEVICE_STATE_AVAILABLE)  {
-                    res = setDeviceConnectionStateInt(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                                      address.c_str(), "remote-submix",
-                                                      AUDIO_FORMAT_DEFAULT);
-                    if (res != OK) {
+                    AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+                    status_t currentRes =
+                            setDeviceConnectionStateInt(device,
+                                                        AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                                        address.c_str(),
+                                                        "remote-submix",
+                                                        AUDIO_FORMAT_DEFAULT);
+                    if (!audio_flags::audio_mix_ownership()) {
+                        res = currentRes;
+                    }
+                    if (currentRes != OK) {
                         ALOGE("Error making RemoteSubmix device unavailable for mix "
                               "with type %d, address %s", device, address.c_str());
-                        endResult = INVALID_OPERATION;
+                        res = INVALID_OPERATION;
                     }
                 }
             }
@@ -3875,24 +3891,16 @@
         } else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
             if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
                 res = INVALID_OPERATION;
-                endResult = INVALID_OPERATION;
                 continue;
             } else {
                 checkOutputs = true;
             }
         }
     }
-    if (audio_flags::audio_mix_ownership()) {
-        res = endResult;
-        if (res == NO_ERROR && checkOutputs) {
-            checkForDeviceAndOutputChanges();
-            updateCallAndOutputRouting();
-        }
-    } else {
-        if (res == NO_ERROR && checkOutputs) {
-            checkForDeviceAndOutputChanges();
-            updateCallAndOutputRouting();
-        }
+
+    if (res == NO_ERROR && checkOutputs) {
+        checkForDeviceAndOutputChanges();
+        updateCallAndOutputRouting();
     }
     return res;
 }
@@ -3910,9 +3918,10 @@
                              policyMix->mCbFlags);
         _aidl_return.back().mDeviceType = policyMix->mDeviceType;
         _aidl_return.back().mToken = policyMix->mToken;
+        _aidl_return.back().mVirtualDeviceId = policyMix->mVirtualDeviceId;
     }
 
-    ALOGVV("%s() returning %zu registered mixes", __func__, _aidl_return->size());
+    ALOGVV("%s() returning %zu registered mixes", __func__, _aidl_return.size());
     return OK;
 }
 
@@ -7285,7 +7294,6 @@
     DeviceVector devices;
     for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
         StreamTypeVector streams = mEngine->getStreamTypesForProductStrategy(productStrategy);
-        auto attr = mEngine->getAllAttributesForProductStrategy(productStrategy).front();
         auto hasStreamActive = [&](auto stream) {
             return hasStream(streams, stream) && isStreamActive(stream, 0);
         };
@@ -7310,6 +7318,7 @@
                 mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) {
             // Retrieval of devices for voice DL is done on primary output profile, cannot
             // check the route (would force modifying configuration file for this profile)
+            auto attr = mEngine->getAllAttributesForProductStrategy(productStrategy).front();
             devices = mEngine->getOutputDevicesForAttributes(attr, nullptr, fromCache);
             break;
         }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index a3232a2..0454e6e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -141,7 +141,8 @@
                                          audio_input_flags_t flags,
                                          audio_port_handle_t *selectedDeviceId,
                                          input_type_t *inputType,
-                                         audio_port_handle_t *portId);
+                                         audio_port_handle_t *portId,
+                                         uint32_t *virtualDeviceId);
 
         // indicates to the audio policy manager that the input starts being used.
         virtual status_t startInput(audio_port_handle_t portId);
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index cddbf39..dae3cce 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -12,6 +12,14 @@
     name: "libaudiopolicyservice_dependencies",
 
     shared_libs: [
+        "audioclient-types-aidl-cpp",
+        "audioflinger-aidl-cpp",
+        "audiopolicy-aidl-cpp",
+        "audiopolicy-types-aidl-cpp",
+        "capture_state_listener-aidl-cpp",
+        "com.android.media.audio-aconfig-cc",
+        "framework-permission-aidl-cpp",
+        "libPlatformProperties",
         "libactivitymanager_aidl",
         "libaudioclient",
         "libaudioclient_aidl_conversion",
@@ -32,27 +40,20 @@
         "libmediametrics",
         "libmediautils",
         "libpermission",
-        "libPlatformProperties",
         "libsensor",
         "libsensorprivacy",
         "libshmemcompat",
         "libstagefright_foundation",
         "libutils",
         "libxml2",
-        "audioclient-types-aidl-cpp",
-        "audioflinger-aidl-cpp",
-        "audiopolicy-aidl-cpp",
-        "audiopolicy-types-aidl-cpp",
-        "capture_state_listener-aidl-cpp",
-        "com.android.media.audio-aconfig-cc",
-        "framework-permission-aidl-cpp",
+        "android.media.audiopolicy-aconfig-cc",
         "packagemanager_aidl-cpp",
         "spatializer-aidl-cpp",
     ],
 
     static_libs: [
-        "libeffectsconfig",
         "libaudiopolicycomponents",
+        "libeffectsconfig",
     ],
 }
 
@@ -60,16 +61,16 @@
     name: "libaudiopolicyservice",
 
     defaults: [
-        "libaudiopolicyservice_dependencies",
         "latest_android_media_audio_common_types_cpp_shared",
+        "libaudiopolicyservice_dependencies",
     ],
 
     srcs: [
-        "AudioRecordClient.cpp",
         "AudioPolicyClientImpl.cpp",
         "AudioPolicyEffects.cpp",
         "AudioPolicyInterfaceImpl.cpp",
         "AudioPolicyService.cpp",
+        "AudioRecordClient.cpp",
         "CaptureStateNotifier.cpp",
         "Spatializer.cpp",
         "SpatializerPoseController.cpp",
@@ -92,18 +93,24 @@
     ],
 
     cflags: [
-        "-fvisibility=hidden",
-        "-Werror",
         "-Wall",
+        "-Werror",
         "-Wthread-safety",
+        "-fvisibility=hidden",
     ],
 
     export_shared_lib_headers: [
+        "framework-permission-aidl-cpp",
         "libactivitymanager_aidl",
         "libaudiousecasevalidation",
         "libheadtracking",
         "libheadtracking-binding",
         "libsensorprivacy",
-        "framework-permission-aidl-cpp",
     ],
 }
+
+cc_library_headers {
+    name: "libaudiopolicyservice_headers",
+    host_supported: true,
+    export_include_dirs: ["."],
+}
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 2a4c069..0c68ad1 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -20,6 +20,7 @@
 #include "AudioPolicyService.h"
 #include "AudioRecordClient.h"
 #include "TypeConverter.h"
+#include <android_media_audiopolicy.h>
 #include <media/AidlConversion.h>
 #include <media/AudioPolicy.h>
 #include <media/AudioValidator.h>
@@ -45,6 +46,7 @@
 #define MAX_ITEMS_PER_LIST 1024
 
 namespace android {
+namespace audiopolicy_flags = android::media::audiopolicy;
 using binder::Status;
 using aidl_utils::binderStatusFromStatusT;
 using content::AttributionSourceState;
@@ -62,6 +64,8 @@
 using media::audio::common::AudioUuid;
 using media::audio::common::Int;
 
+constexpr int kDefaultVirtualDeviceId = 0;
+
 const std::vector<audio_usage_t>& SYSTEM_USAGES = {
     AUDIO_USAGE_CALL_ASSISTANT,
     AUDIO_USAGE_EMERGENCY,
@@ -627,6 +631,8 @@
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr,
             attributionSource)));
 
+    uint32_t virtualDeviceId = kDefaultVirtualDeviceId;
+
     // check calling permissions.
     // Capturing from the following sources does not require permission RECORD_AUDIO
     // as the captured audio does not come from a microphone:
@@ -698,7 +704,8 @@
             status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
                                                           attributionSource, &config,
                                                           flags, &selectedDeviceId,
-                                                          &inputType, &portId);
+                                                          &inputType, &portId,
+                                                          &virtualDeviceId);
 
         }
         audioPolicyEffects = mAudioPolicyEffects;
@@ -737,6 +744,14 @@
                 LOG_ALWAYS_FATAL("%s encountered an invalid input type %d",
                         __func__, (int)inputType);
             }
+
+            if (audiopolicy_flags::record_audio_device_aware_permission()) {
+                // enforce device-aware RECORD_AUDIO permission
+                if (virtualDeviceId != kDefaultVirtualDeviceId &&
+                    !recordingAllowed(attributionSource, virtualDeviceId, inputSource)) {
+                    status = PERMISSION_DENIED;
+                }
+            }
         }
 
         if (status != NO_ERROR) {
@@ -752,6 +767,7 @@
 
         sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
                                                              selectedDeviceId, attributionSource,
+                                                             virtualDeviceId,
                                                              canCaptureOutput, canCaptureHotword,
                                                              mOutputCommandThread);
         mAudioRecordClients.add(portId, client);
@@ -1561,17 +1577,20 @@
     std::unique_ptr<audio_port_v7[]> ports(new audio_port_v7[num_ports]);
     unsigned int generation;
 
-    audio_utils::lock_guard _l(mMutex);
-    if (mAudioPolicyManager == NULL) {
-        return binderStatusFromStatusT(NO_INIT);
-    }
-
     const AttributionSourceState attributionSource = getCallingAttributionSource();
-
     AutoCallerClear acc;
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
-            mAudioPolicyManager->listAudioPorts(role, type, &num_ports, ports.get(), &generation)));
-    numPortsReq = std::min(numPortsReq, num_ports);
+    {
+        audio_utils::lock_guard _l(mMutex);
+        if (mAudioPolicyManager == NULL) {
+            return binderStatusFromStatusT(NO_INIT);
+        }
+        // AudioPolicyManager->listAudioPorts makes a deep copy of port structs into ports
+        // so it is safe to access after releasing the mutex
+        RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+                mAudioPolicyManager->listAudioPorts(
+                        role, type, &num_ports, ports.get(), &generation)));
+        numPortsReq = std::min(numPortsReq, num_ports);
+    }
 
     if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
         for (size_t i = 0; i < numPortsReq; ++i) {
@@ -1601,15 +1620,19 @@
 Status AudioPolicyService::getAudioPort(int portId,
                                         media::AudioPortFw* _aidl_return) {
     audio_port_v7 port{ .id = portId };
-    audio_utils::lock_guard _l(mMutex);
-    if (mAudioPolicyManager == NULL) {
-        return binderStatusFromStatusT(NO_INIT);
-    }
 
     const AttributionSourceState attributionSource = getCallingAttributionSource();
-
     AutoCallerClear acc;
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
+
+    {
+        audio_utils::lock_guard _l(mMutex);
+        if (mAudioPolicyManager == NULL) {
+            return binderStatusFromStatusT(NO_INIT);
+        }
+        // AudioPolicyManager->getAudioPort makes a deep copy of the port struct into port
+        // so it is safe to access after releasing the mutex
+        RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
+    }
 
     if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
         anonymizePortBluetoothAddress(&port);
@@ -1672,17 +1695,20 @@
     std::unique_ptr<audio_patch[]> patches(new audio_patch[num_patches]);
     unsigned int generation;
 
-    audio_utils::lock_guard _l(mMutex);
-    if (mAudioPolicyManager == NULL) {
-        return binderStatusFromStatusT(NO_INIT);
-    }
-
     const AttributionSourceState attributionSource = getCallingAttributionSource();
-
     AutoCallerClear acc;
-    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
-            mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
-    numPatchesReq = std::min(numPatchesReq, num_patches);
+
+    {
+        audio_utils::lock_guard _l(mMutex);
+        if (mAudioPolicyManager == NULL) {
+            return binderStatusFromStatusT(NO_INIT);
+        }
+        // AudioPolicyManager->listAudioPatches makes a deep copy of patches structs into patches
+        // so it is safe to access after releasing the mutex
+        RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+                mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
+        numPatchesReq = std::min(numPatchesReq, num_patches);
+    }
 
     if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
         for (size_t i = 0; i < numPatchesReq; ++i) {
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index e95147e..f6492d4 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -18,9 +18,6 @@
 //#define LOG_NDEBUG 0
 
 #include "Configuration.h"
-#undef __STRICT_ANSI__
-#define __STDINT_LIMITS
-#define __STDC_LIMIT_MACROS
 #include <stdint.h>
 #include <sys/time.h>
 #include <dlfcn.h>
diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp
index a89a84d..6d8b3cf 100644
--- a/services/audiopolicy/service/AudioRecordClient.cpp
+++ b/services/audiopolicy/service/AudioRecordClient.cpp
@@ -18,9 +18,10 @@
 
 #include "AudioRecordClient.h"
 #include "AudioPolicyService.h"
+#include <android_media_audiopolicy.h>
 
 namespace android::media::audiopolicy {
-
+namespace audiopolicy_flags = android::media::audiopolicy;
 using android::AudioPolicyService;
 
 namespace {
@@ -59,8 +60,10 @@
 // static
 sp<OpRecordAudioMonitor>
 OpRecordAudioMonitor::createIfNeeded(
-            const AttributionSourceState& attributionSource, const audio_attributes_t& attr,
-            wp<AudioPolicyService::AudioCommandThread> commandThread)
+        const AttributionSourceState &attributionSource,
+        const uint32_t virtualDeviceId,
+        const audio_attributes_t &attr,
+        wp<AudioPolicyService::AudioCommandThread> commandThread)
 {
     if (isAudioServerOrRootUid(attributionSource.uid)) {
         ALOGV("not silencing record for audio or root source %s",
@@ -78,15 +81,19 @@
             || attributionSource.packageName.value().size() == 0) {
         return nullptr;
     }
-    return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread);
+
+    return new OpRecordAudioMonitor(attributionSource, virtualDeviceId, attr,
+                                    getOpForSource(attr.source), commandThread);
 }
 
 OpRecordAudioMonitor::OpRecordAudioMonitor(
-        const AttributionSourceState& attributionSource, int32_t appOp,
+        const AttributionSourceState &attributionSource,
+        const uint32_t virtualDeviceId, const audio_attributes_t &attr,
+        int32_t appOp,
         wp<AudioPolicyService::AudioCommandThread> commandThread) :
-            mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp),
-            mCommandThread(commandThread)
-{
+        mHasOp(true), mAttributionSource(attributionSource),
+        mVirtualDeviceId(virtualDeviceId), mAttr(attr), mAppOp(appOp),
+        mCommandThread(commandThread) {
 }
 
 OpRecordAudioMonitor::~OpRecordAudioMonitor()
@@ -131,7 +138,12 @@
     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);
+    bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
+
+    if (audiopolicy_flags::record_audio_device_aware_permission()) {
+        const bool canRecord = recordingAllowed(mAttributionSource, mVirtualDeviceId, mAttr.source);
+        hasIt = hasIt && canRecord;
+    }
     // verbose logging only log when appOp changed
     ALOGI_IF(hasIt != mHasOp.load(),
             "App op %d missing, %ssilencing record %s",
diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h
index d3be316..76aff41 100644
--- a/services/audiopolicy/service/AudioRecordClient.h
+++ b/services/audiopolicy/service/AudioRecordClient.h
@@ -38,12 +38,16 @@
 
     static sp<OpRecordAudioMonitor> createIfNeeded(
             const AttributionSourceState& attributionSource,
+            uint32_t virtualDeviceId,
             const audio_attributes_t& attr,
             wp<AudioPolicyService::AudioCommandThread> commandThread);
 
 private:
-    OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp,
-            wp<AudioPolicyService::AudioCommandThread> commandThread);
+    OpRecordAudioMonitor(const AttributionSourceState &attributionSource,
+                         uint32_t virtualDeviceId,
+                         const audio_attributes_t &attr,
+                         int32_t appOp,
+                         wp<AudioPolicyService::AudioCommandThread> commandThread);
 
     void onFirstRef() override;
 
@@ -67,6 +71,8 @@
 
     std::atomic_bool mHasOp;
     const AttributionSourceState mAttributionSource;
+    const uint32_t mVirtualDeviceId;
+    const audio_attributes_t mAttr;
     const int32_t mAppOp;
     wp<AudioPolicyService::AudioCommandThread> mCommandThread;
 };
@@ -81,15 +87,20 @@
                       const audio_session_t session, audio_port_handle_t portId,
                       const audio_port_handle_t deviceId,
                       const AttributionSourceState& attributionSource,
+                      const uint32_t virtualDeviceId,
                       bool canCaptureOutput, bool canCaptureHotword,
                       wp<AudioPolicyService::AudioCommandThread> commandThread) :
                 AudioClient(attributes, io, attributionSource,
                     session, portId, deviceId), attributionSource(attributionSource),
+                    virtualDeviceId(virtualDeviceId),
                     startTimeNs(0), canCaptureOutput(canCaptureOutput),
                     canCaptureHotword(canCaptureHotword), silenced(false),
                     mOpRecordAudioMonitor(
                             OpRecordAudioMonitor::createIfNeeded(attributionSource,
-                            attributes, commandThread)) {}
+                                                                 virtualDeviceId,
+                                                                 attributes, commandThread)) {
+
+            }
             ~AudioRecordClient() override = default;
 
     bool hasOp() const {
@@ -97,6 +108,7 @@
     }
 
     const AttributionSourceState attributionSource; // attribution source of client
+    const uint32_t virtualDeviceId; // id of the virtual device associated with the audio device
     nsecs_t startTimeNs;
     const bool canCaptureOutput;
     const bool canCaptureHotword;
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 16f3a9a..233a484 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -1096,7 +1096,7 @@
 }
 
 void Spatializer::checkSensorsState_l() {
-    audio_latency_mode_t requestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
+    mRequestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
     const bool supportsSetLatencyMode = !mSupportedLatencyModes.empty();
     bool supportsLowLatencyMode;
     if (com::android::media::audio::dsa_over_bt_le_audio()) {
@@ -1117,7 +1117,7 @@
                     && mDesiredHeadTrackingMode != HeadTrackingMode::STATIC
                     && mHeadSensor != SpatializerPoseController::INVALID_SENSOR) {
                 if (supportsLowLatencyMode) {
-                    requestedLatencyMode = selectHeadtrackingConnectionMode_l();
+                    mRequestedLatencyMode = selectHeadtrackingConnectionMode_l();
                 }
                 if (mEngine != nullptr) {
                     setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
@@ -1139,9 +1139,9 @@
     }
     if (mOutput != AUDIO_IO_HANDLE_NONE && supportsSetLatencyMode) {
         const status_t status =
-                AudioSystem::setRequestedLatencyMode(mOutput, requestedLatencyMode);
+                AudioSystem::setRequestedLatencyMode(mOutput, mRequestedLatencyMode);
         ALOGD("%s: setRequestedLatencyMode for output thread(%d) to %s returned %d", __func__,
-              mOutput, toString(requestedLatencyMode).c_str(), status);
+              mOutput, toString(mRequestedLatencyMode).c_str(), status);
     }
 }
 
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 355df18..c5f159c 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -27,6 +27,7 @@
 #include <audio_utils/SimpleLog.h>
 #include <math.h>
 #include <media/AudioEffect.h>
+#include <media/MediaMetricsItem.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 #include <media/VectorRecorder.h>
 #include <media/audiohal/EffectHalInterface.h>
@@ -153,6 +154,34 @@
         return mLevel;
     }
 
+    /** For test only */
+    std::unordered_set<media::audio::common::HeadTracking::ConnectionMode>
+            getSupportedHeadtrackingConnectionModes() const {
+        return mSupportedHeadtrackingConnectionModes;
+    }
+
+    /** For test only */
+    media::audio::common::HeadTracking::ConnectionMode getHeadtrackingConnectionMode() const {
+        return mHeadtrackingConnectionMode;
+    }
+
+    /** For test only */
+    std::vector<audio_latency_mode_t> getSupportedLatencyModes() const {
+        audio_utils::lock_guard lock(mMutex);
+        return mSupportedLatencyModes;
+    }
+
+    /** For test only */
+    std::vector<audio_latency_mode_t> getOrderedLowLatencyModes() const {
+        return mOrderedLowLatencyModes;
+    }
+
+    /** For test only */
+    audio_latency_mode_t getRequestedLatencyMode() const {
+        audio_utils::lock_guard lock(mMutex);
+        return mRequestedLatencyMode;
+    }
+
     /** Called by audio policy service when the special output mixer dedicated to spatialization
      * is opened and the spatializer engine must be created.
      */
@@ -164,6 +193,12 @@
     /** Returns the output stream the spatializer is attached to. */
     audio_io_handle_t getOutput() const { audio_utils::lock_guard lock(mMutex); return mOutput; }
 
+    /** For test only */
+    void setOutput(audio_io_handle_t output) {
+        audio_utils::lock_guard lock(mMutex);
+        mOutput = output;
+    }
+
     void updateActiveTracks(size_t numActiveTracks);
 
     /** Gets the channel mask, sampling rate and format set for the spatializer input. */
@@ -188,6 +223,10 @@
     // NO_INIT: Spatializer creation failed.
     static void sendEmptyCreateSpatializerMetricWithStatus(status_t status);
 
+    /** Made public for test only */
+    void onSupportedLatencyModesChangedMsg(
+            audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes);
+
 private:
     Spatializer(effect_descriptor_t engineDescriptor,
                      SpatializerPolicyCallback *callback);
@@ -200,8 +239,6 @@
 
     void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
     void onActualModeChangeMsg(media::HeadTrackingMode mode);
-    void onSupportedLatencyModesChangedMsg(
-            audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes);
 
     static constexpr int kMaxEffectParamValues = 10;
     /**
@@ -484,9 +521,11 @@
     std::vector<media::audio::common::Spatialization::Mode> mSpatializationModes;
     std::vector<audio_channel_mask_t> mChannelMasks;
     bool mSupportsHeadTracking;
-    /** List of supported headtracking connection modes reported by the spatializer.
+
+    /** List of supported head tracking connection modes reported by the spatializer.
      * If the list is empty, the spatializer does not support any optional connection
      * mode and mode HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED is assumed.
+     * This is set in the factory constructor and can be accessed without mutex.
      */
     std::unordered_set<media::audio::common::HeadTracking::ConnectionMode>
             mSupportedHeadtrackingConnectionModes;
@@ -504,6 +543,9 @@
     std::vector<audio_latency_mode_t> mSupportedLatencyModes GUARDED_BY(mMutex);
     /** preference order for low latency modes according to persist.bluetooth.hid.transport */
     std::vector<audio_latency_mode_t> mOrderedLowLatencyModes;
+
+    audio_latency_mode_t mRequestedLatencyMode GUARDED_BY(mMutex) = AUDIO_LATENCY_MODE_FREE;
+
     /** string to latency mode map used to parse bluetooth.core.le.dsa_transport_preference */
     static const std::map<std::string, audio_latency_mode_t> sStringToLatencyModeMap;
     static const std::vector<const char*> sHeadPoseKeys;
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 34bd3b4..fc349ee 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -28,11 +28,11 @@
         "libbase",
         "libbinder",
         "libcutils",
+        "libcutils",
         "libhidlbase",
         "liblog",
         "libmedia_helper",
         "libutils",
-        "libcutils",
         "libxml2",
         "server_configurable_flags",
     ],
@@ -56,13 +56,13 @@
     data: [":audiopolicytest_configuration_files"],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     test_suites: [
-        "device-tests",
         "automotive-tests",
+        "device-tests",
     ],
 
 }
@@ -101,10 +101,47 @@
     srcs: ["audio_health_tests.cpp"],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     test_suites: ["device-tests"],
 
 }
+
+cc_test {
+    name: "spatializer_tests",
+
+    defaults: [
+        "latest_android_media_audio_common_types_cpp_shared",
+        "libaudiopolicyservice_dependencies",
+    ],
+
+    require_root: true,
+
+    shared_libs: [
+        "libaudioclient",
+        "libaudiofoundation",
+        "libcutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libaudiopolicyservice",
+    ],
+
+    header_libs: [
+        "libaudiohal_headers",
+        "libaudiopolicyservice_headers",
+        "libmediametrics_headers",
+    ],
+
+    srcs: ["spatializer_tests.cpp"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    test_suites: ["device-tests"],
+}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index e02c93a..f9d5946 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -204,7 +204,8 @@
             audio_channel_mask_t channelMask,
             int sampleRate,
             audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
-            audio_port_handle_t *portId = nullptr);
+            audio_port_handle_t *portId = nullptr,
+            uint32_t *virtualDeviceId = nullptr);
     PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
 
     void getAudioPorts(audio_port_type_t type, audio_port_role_t role,
@@ -316,7 +317,8 @@
         audio_channel_mask_t channelMask,
         int sampleRate,
         audio_input_flags_t flags,
-        audio_port_handle_t *portId) {
+        audio_port_handle_t *portId,
+        uint32_t *virtualDeviceId) {
     audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
     config.sample_rate = sampleRate;
     config.channel_mask = channelMask;
@@ -324,11 +326,12 @@
     audio_port_handle_t localPortId;
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
+    if (!virtualDeviceId) virtualDeviceId = 0;
     AudioPolicyInterface::input_type_t inputType;
     AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
     ASSERT_EQ(OK, mManager->getInputForAttr(
             &attr, input, riid, session, attributionSource, &config, flags,
-            selectedDeviceId, &inputType, portId));
+            selectedDeviceId, &inputType, portId, virtualDeviceId));
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
 }
 
@@ -1296,10 +1299,11 @@
     };
     audio_config_base_t config = requestedConfig;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+    uint32_t *virtualDeviceId = 0;
     ASSERT_EQ(OK, mManager->getInputForAttr(
             &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
             AUDIO_INPUT_FLAG_NONE,
-            &selectedDeviceId, &inputType, &portId));
+            &selectedDeviceId, &inputType, &portId, virtualDeviceId));
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
     ASSERT_TRUE(equals(requestedConfig, config));
 
@@ -1313,7 +1317,7 @@
     ASSERT_EQ(OK, mManager->getInputForAttr(
             &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
             AUDIO_INPUT_FLAG_NONE,
-            &selectedDeviceId, &inputType, &portId));
+            &selectedDeviceId, &inputType, &portId, virtualDeviceId));
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
     ASSERT_TRUE(equals(requestedConfig, config));
 
@@ -1369,6 +1373,7 @@
     AudioMix myAudioMix(matchCriteria, mixType, audioConfig, mixFlag,
             String8(mixAddress.c_str()), 0);
     myAudioMix.mDeviceType = deviceType;
+    myAudioMix.mToken = sp<BBinder>::make();
     // Clear mAudioMix before add new one to make sure we don't add already exist mixes.
     mAudioMixes.clear();
     return addPolicyMix(myAudioMix);
@@ -1569,8 +1574,7 @@
     validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
 
     mAudioMixes.clear();
-    mAudioMixes.add(validAudioMix);
-    status_t ret = mManager->registerPolicyMixes(mAudioMixes);
+    status_t ret = addPolicyMix(validAudioMix);
 
     ASSERT_EQ(NO_ERROR, ret);
 
@@ -1586,8 +1590,7 @@
                              MIX_ROUTE_FLAG_LOOP_BACK, String8(mMixAddress.c_str()), 0);
     validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
 
-    mAudioMixes.add(invalidAudioMix);
-    ret = mManager->registerPolicyMixes(mAudioMixes);
+    ret = addPolicyMix(invalidAudioMix);
 
     ASSERT_EQ(INVALID_OPERATION, ret);
 
@@ -1614,8 +1617,7 @@
     validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
 
     mAudioMixes.clear();
-    mAudioMixes.add(validAudioMix);
-    status_t ret = mManager->registerPolicyMixes(mAudioMixes);
+    status_t ret = addPolicyMix(validAudioMix);
 
     ASSERT_EQ(NO_ERROR, ret);
 
@@ -1629,7 +1631,7 @@
 
     AudioMix invalidAudioMix(invalidMixMatchCriteria, MIX_TYPE_PLAYERS, audioConfig,
                              MIX_ROUTE_FLAG_LOOP_BACK, String8(mMixAddress.c_str()), 0);
-    validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    invalidAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
 
     Vector<AudioMix> mixes;
     mixes.add(invalidAudioMix);
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index 43e2e39..abf72e0 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -15,7 +15,7 @@
         "test_audio_policy_primary_only_configuration.xml",
         "test_car_ap_atmos_offload_configuration.xml",
         "test_invalid_audio_policy_configuration.xml",
-        "test_tv_apm_configuration.xml",
         "test_settop_box_surround_configuration.xml",
+        "test_tv_apm_configuration.xml",
     ],
 }
diff --git a/services/audiopolicy/tests/spatializer_tests.cpp b/services/audiopolicy/tests/spatializer_tests.cpp
new file mode 100644
index 0000000..73bef43
--- /dev/null
+++ b/services/audiopolicy/tests/spatializer_tests.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Spatializer_Test"
+
+#include "Spatializer.h"
+
+#include <string>
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#include <android/media/audio/common/AudioLatencyMode.h>
+#include <android/media/audio/common/HeadTracking.h>
+#include <android/media/audio/common/Spatialization.h>
+#include <com_android_media_audio.h>
+#include <utils/Log.h>
+
+using namespace android;
+using media::audio::common::HeadTracking;
+using media::audio::common::Spatialization;
+
+class TestSpatializerPolicyCallback :
+        public SpatializerPolicyCallback {
+public:
+    void onCheckSpatializer() override {};
+};
+
+class SpatializerTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        const sp<EffectsFactoryHalInterface> effectsFactoryHal
+                = EffectsFactoryHalInterface::create();
+        mSpatializer = Spatializer::create(&mTestCallback, effectsFactoryHal);
+        if (mSpatializer == nullptr) {
+            GTEST_SKIP() << "Skipping Spatializer tests: no spatializer";
+        }
+        std::vector<Spatialization::Level> levels;
+        binder::Status status = mSpatializer->getSupportedLevels(&levels);
+        ASSERT_TRUE(status.isOk());
+        for (auto level : levels) {
+            if (level != Spatialization::Level::NONE) {
+                mSpatializer->setLevel(level);
+                break;
+            }
+        }
+        mSpatializer->setOutput(sTestOutput);
+    }
+
+    void TearDown() override {
+        if (mSpatializer == nullptr) {
+            return;
+        }
+        mSpatializer->setLevel(Spatialization::Level::NONE);
+        mSpatializer->setOutput(AUDIO_IO_HANDLE_NONE);
+        mSpatializer->setDesiredHeadTrackingMode(HeadTracking::Mode::DISABLED);
+        mSpatializer->setHeadSensor(SpatializerPoseController::INVALID_SENSOR);
+        mSpatializer->updateActiveTracks(0);
+    }
+
+    static constexpr audio_io_handle_t sTestOutput= 1977;
+    static constexpr int sTestSensorHandle = 1980;
+
+    const static inline std::vector<audio_latency_mode_t> sA2DPLatencyModes = {
+        AUDIO_LATENCY_MODE_LOW,
+        AUDIO_LATENCY_MODE_FREE
+    };
+    const static inline std::vector<audio_latency_mode_t> sBLELatencyModes = {
+        AUDIO_LATENCY_MODE_LOW,
+        AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
+        AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE,
+        AUDIO_LATENCY_MODE_FREE
+    };
+
+    bool setpUpForHeadtracking() {
+        bool htSupported;
+        mSpatializer->isHeadTrackingSupported(&htSupported);
+        if (!htSupported) {
+            return false;
+        }
+
+        std::vector<HeadTracking::Mode> htModes;
+        mSpatializer->getSupportedHeadTrackingModes(&htModes);
+        for (auto htMode : htModes) {
+            if (htMode != HeadTracking::Mode::DISABLED) {
+                mSpatializer->setDesiredHeadTrackingMode(htMode);
+                break;
+            }
+        }
+
+        mSpatializer->setHeadSensor(sTestSensorHandle);
+        return true;
+    }
+
+    TestSpatializerPolicyCallback mTestCallback;
+    sp<Spatializer> mSpatializer;
+};
+
+TEST_F(SpatializerTest, SupportedA2dpLatencyTest) {
+    if (!setpUpForHeadtracking()) {
+        GTEST_SKIP() << "Skipping SupportedA2dpLatencyTest: head tracking not supported";
+    }
+    std::vector<audio_latency_mode_t> latencies = sA2DPLatencyModes;
+    mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
+
+    std::vector<audio_latency_mode_t> supportedLatencies =
+            mSpatializer->getSupportedLatencyModes();
+
+    ASSERT_TRUE(supportedLatencies == sA2DPLatencyModes);
+    // Free mode must always be the last of the ordered list
+    ASSERT_TRUE(supportedLatencies.back() == AUDIO_LATENCY_MODE_FREE);
+}
+
+TEST_F(SpatializerTest, SupportedBleLatencyTest) {
+    if (!setpUpForHeadtracking()) {
+        GTEST_SKIP() << "Skipping SupportedBleLatencyTest: head tracking not supported";
+    }
+    if (!com::android::media::audio::dsa_over_bt_le_audio()) {
+        GTEST_SKIP() << "Skipping SupportedBleLatencyTest: DSA over LE not enabled";
+    }
+    std::vector<audio_latency_mode_t> latencies = sBLELatencyModes;
+    mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
+
+    std::vector<audio_latency_mode_t> supportedLatencies =
+            mSpatializer->getSupportedLatencyModes();
+
+    ASSERT_TRUE(supportedLatencies.back() == AUDIO_LATENCY_MODE_FREE);
+    ASSERT_TRUE(std::find(supportedLatencies.begin(), supportedLatencies.end(),
+            AUDIO_LATENCY_MODE_LOW) != supportedLatencies.end());
+
+    std::vector<audio_latency_mode_t> orderedLowLatencyModes =
+        mSpatializer->getOrderedLowLatencyModes();
+
+    std::vector<audio_latency_mode_t> supportedLowLatencyModes;
+    // remove free mode at the end of the supported list to only retain low latency modes
+    std::copy(supportedLatencies.begin(),
+              supportedLatencies.begin() + supportedLatencies.size() - 1,
+              std::back_inserter(supportedLowLatencyModes));
+
+    // Verify that supported low latency modes are always in ordered latency modes list and
+    // in the same order
+    std::vector<audio_latency_mode_t>::iterator lastIt = orderedLowLatencyModes.begin();
+    for (auto latency : supportedLowLatencyModes) {
+        auto it = std::find(orderedLowLatencyModes.begin(), orderedLowLatencyModes.end(), latency);
+        ASSERT_NE(it, orderedLowLatencyModes.end());
+        ASSERT_LE(lastIt, it);
+        lastIt = it;
+    }
+}
+
+TEST_F(SpatializerTest, RequestedA2dpLatencyTest) {
+    if (!setpUpForHeadtracking()) {
+        GTEST_SKIP() << "Skipping RequestedA2dpLatencyTest: head tracking not supported";
+    }
+
+    std::vector<audio_latency_mode_t> latencies = sA2DPLatencyModes;
+    mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
+
+    // requested latency mode must be free if no spatialized tracks are active
+    audio_latency_mode_t requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+    ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+
+    // requested latency mode must be low if at least one spatialized tracks is active
+    mSpatializer->updateActiveTracks(1);
+    requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+    ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_LOW);
+
+    // requested latency mode must be free after stopping the last spatialized tracks
+    mSpatializer->updateActiveTracks(0);
+    requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+    ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+}
+
+TEST_F(SpatializerTest, RequestedBleLatencyTest) {
+    if (!setpUpForHeadtracking()) {
+        GTEST_SKIP() << "Skipping RequestedBleLatencyTest: head tracking not supported";
+    }
+    if (!com::android::media::audio::dsa_over_bt_le_audio()) {
+        GTEST_SKIP() << "Skipping RequestedBleLatencyTest: DSA over LE not enabled";
+    }
+
+    mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput,
+            { AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
+              AUDIO_LATENCY_MODE_FREE });
+
+    // requested latency mode must be free if no spatialized tracks are active
+    audio_latency_mode_t requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+    ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+
+    // requested latency mode must be low software if at least one spatialized tracks is active
+    // and the only supported low latency mode is low software
+    mSpatializer->updateActiveTracks(1);
+    requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+    ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE);
+
+    mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput,
+            { AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
+              AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE,
+              AUDIO_LATENCY_MODE_FREE });
+
+    requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+    HeadTracking::ConnectionMode connectionMode = mSpatializer->getHeadtrackingConnectionMode();
+
+    // If low hardware mode is used, the spatializer must use either use one of the sensor
+    // connection tunneled modes.
+    // Otherwise, low software mode must be used
+    if (requestedLatencyMode == AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+        ASSERT_TRUE(connectionMode == HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_TUNNEL
+                        || connectionMode == HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_SW);
+    } else {
+        ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE);
+    }
+
+    // requested latency mode must be free after stopping the last spatialized tracks
+    mSpatializer->updateActiveTracks(0);
+    requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+    ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 5b76bb0..b9b30f6 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -186,8 +186,8 @@
         "aidl/AidlCameraServiceListener.cpp",
         "aidl/AidlUtils.cpp",
         "aidl/DeathPipe.cpp",
+        "utils/AttributionAndPermissionUtils.cpp",
         "utils/CameraServiceProxyWrapper.cpp",
-        "utils/CameraThreadState.cpp",
         "utils/CameraTraces.cpp",
         "utils/AutoConditionLock.cpp",
         "utils/SchedulingPolicyUtils.cpp",
@@ -262,7 +262,7 @@
         "liblog",
         "libutils",
         "libxml2",
-        "camera_platform_flags_c_lib"
+        "camera_platform_flags_c_lib",
     ],
 
     include_dirs: [
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 2d55f39..e30775d 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -38,7 +38,6 @@
 #include <aidl/AidlCameraService.h>
 #include <android-base/macros.h>
 #include <android-base/parseint.h>
-#include <android/permission/PermissionChecker.h>
 #include <binder/ActivityManager.h>
 #include <binder/AppOpsManager.h>
 #include <binder/IPCThreadState.h>
@@ -82,7 +81,6 @@
 #include "api2/CameraDeviceClient.h"
 #include "utils/CameraTraces.h"
 #include "utils/TagMonitor.h"
-#include "utils/CameraThreadState.h"
 #include "utils/CameraServiceProxyWrapper.h"
 #include "utils/SessionConfigurationUtils.h"
 
@@ -129,20 +127,16 @@
 
 // ----------------------------------------------------------------------------
 
-static const std::string sDumpPermission("android.permission.DUMP");
-static const std::string sManageCameraPermission("android.permission.MANAGE_CAMERA");
-static const std::string sCameraPermission("android.permission.CAMERA");
-static const std::string sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
-static const std::string sCameraHeadlessSystemUserPermission(
-        "android.permission.CAMERA_HEADLESS_SYSTEM_USER");
-static const std::string sCameraPrivacyAllowlistPermission(
-        "android.permission.CAMERA_PRIVACY_ALLOWLIST");
-static const std::string
-        sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
-static const std::string sCameraOpenCloseListenerPermission(
-        "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
-static const std::string
-        sCameraInjectExternalCameraPermission("android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
+// Permission strings (references to AttributionAndPermissionUtils for brevity)
+static const std::string &sDumpPermission =
+        AttributionAndPermissionUtils::sDumpPermission;
+static const std::string &sManageCameraPermission =
+        AttributionAndPermissionUtils::sManageCameraPermission;
+static const std::string &sCameraSendSystemEventsPermission =
+        AttributionAndPermissionUtils::sCameraSendSystemEventsPermission;
+static const std::string &sCameraInjectExternalCameraPermission =
+        AttributionAndPermissionUtils::sCameraInjectExternalCameraPermission;
+
 // Constant integer for FGS Logging, used to denote the API type for logger
 static const int LOG_FGS_CAMERA_API = 1;
 const char *sFileName = "lastOpenSessionDumpFile";
@@ -158,7 +152,11 @@
 static std::set<std::string> sServiceErrorEventSet;
 
 CameraService::CameraService(
-        std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
+        std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils) :
+        AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils == nullptr ?
+                std::make_shared<AttributionAndPermissionUtils>()\
+                : attributionAndPermissionUtils),
         mCameraServiceProxyWrapper(cameraServiceProxyWrapper == nullptr ?
                 std::make_shared<CameraServiceProxyWrapper>() : cameraServiceProxyWrapper),
         mEventLog(DEFAULT_EVENT_LOG_LENGTH),
@@ -167,6 +165,7 @@
         mSoundRef(0), mInitialized(false),
         mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE) {
     ALOGI("CameraService started (pid=%d)", getpid());
+    mAttributionAndPermissionUtils->setCameraService(this);
     mServiceLockWrapper = std::make_shared<WaitableMutexWrapper>(&mServiceLock);
     mMemFd = memfd_create(sFileName, MFD_ALLOW_SEALING);
     if (mMemFd == -1) {
@@ -174,12 +173,6 @@
     }
 }
 
-// The word 'System' here does not refer to clients only on the system
-// partition. They just need to have a android system uid.
-static bool doesClientHaveSystemUid() {
-    return (CameraThreadState::getCallingUid() < AID_APP_START);
-}
-
 // Enable processes with isolated AID to request the binder
 void CameraService::instantiate() {
     CameraService::publish(true);
@@ -215,7 +208,7 @@
 
     mUidPolicy = new UidPolicy(this);
     mUidPolicy->registerSelf();
-    mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
+    mSensorPrivacyPolicy = new SensorPrivacyPolicy(this, mAttributionAndPermissionUtils);
     mSensorPrivacyPolicy->registerSelf();
     mInjectionStatusListener = new InjectionStatusListener(this);
 
@@ -708,34 +701,7 @@
     broadcastTorchModeStatus(cameraId, newStatus, systemCameraKind);
 }
 
-static bool isAutomotiveDevice() {
-    // Checks the property ro.hardware.type and returns true if it is
-    // automotive.
-    char value[PROPERTY_VALUE_MAX] = {0};
-    property_get("ro.hardware.type", value, "");
-    return strncmp(value, "automotive", PROPERTY_VALUE_MAX) == 0;
-}
-
-static bool isHeadlessSystemUserMode() {
-    // Checks if the device is running in headless system user mode
-    // by checking the property ro.fw.mu.headless_system_user.
-    char value[PROPERTY_VALUE_MAX] = {0};
-    property_get("ro.fw.mu.headless_system_user", value, "");
-    return strncmp(value, "true", PROPERTY_VALUE_MAX) == 0;
-}
-
-static bool isAutomotivePrivilegedClient(int32_t uid) {
-    // Returns false if this is not an automotive device type.
-    if (!isAutomotiveDevice())
-        return false;
-
-    // Returns true if the uid is AID_AUTOMOTIVE_EVS which is a
-    // privileged client uid used for safety critical use cases such as
-    // rear view and surround view.
-    return uid == AID_AUTOMOTIVE_EVS;
-}
-
-bool CameraService::isAutomotiveExteriorSystemCamera(const std::string& cam_id) const{
+bool CameraService::isAutomotiveExteriorSystemCamera(const std::string& cam_id) const {
     // Returns false if this is not an automotive device type.
     if (!isAutomotiveDevice())
         return false;
@@ -780,62 +746,12 @@
     return true;
 }
 
-bool CameraService::checkPermission(const std::string& cameraId, const std::string& permission,
-        const AttributionSourceState& attributionSource, const std::string& message,
-        int32_t attributedOpCode) const{
-    if (isAutomotivePrivilegedClient(attributionSource.uid)) {
-        // If cameraId is empty, then it means that this check is not used for the
-        // purpose of accessing a specific camera, hence grant permission just
-        // based on uid to the automotive privileged client.
-        if (cameraId.empty())
-            return true;
-        // If this call is used for accessing a specific camera then cam_id must be provided.
-        // In that case, only pre-grants the permission for accessing the exterior system only
-        // camera.
-        return isAutomotiveExteriorSystemCamera(cameraId);
-    }
-
-    permission::PermissionChecker permissionChecker;
-    return permissionChecker.checkPermissionForPreflight(toString16(permission), attributionSource,
-            toString16(message), attributedOpCode)
-            != permission::PermissionChecker::PERMISSION_HARD_DENIED;
-}
-
-bool CameraService::hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid,
-        int callingUid) const{
-    AttributionSourceState attributionSource{};
-    attributionSource.pid = callingPid;
-    attributionSource.uid = callingUid;
-    bool checkPermissionForSystemCamera = checkPermission(cameraId,
-            sSystemCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
-    bool checkPermissionForCamera = checkPermission(cameraId,
-            sCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
-    return checkPermissionForSystemCamera && checkPermissionForCamera;
-}
-
-bool CameraService::hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId,
-        int callingPid, int callingUid) const{
-    AttributionSourceState attributionSource{};
-    attributionSource.pid = callingPid;
-    attributionSource.uid = callingUid;
-    return checkPermission(cameraId, sCameraHeadlessSystemUserPermission, attributionSource,
-            std::string(), AppOpsManager::OP_NONE);
-}
-
-bool CameraService::hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const{
-    AttributionSourceState attributionSource{};
-    attributionSource.pid = callingPid;
-    attributionSource.uid = callingUid;
-    return checkPermission(std::string(), sCameraPrivacyAllowlistPermission, attributionSource,
-            std::string(), AppOpsManager::OP_NONE);
-}
-
 Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
     ATRACE_CALL();
     Mutex::Autolock l(mServiceLock);
     bool hasSystemCameraPermissions =
-            hasPermissionsForSystemCamera(std::string(), CameraThreadState::getCallingPid(),
-                    CameraThreadState::getCallingUid());
+            hasPermissionsForSystemCamera(std::string(), getCallingPid(),
+                    getCallingUid());
     switch (type) {
         case CAMERA_TYPE_BACKWARD_COMPATIBLE:
             if (hasSystemCameraPermissions) {
@@ -862,8 +778,8 @@
 
 Status CameraService::remapCameraIds(const hardware::CameraIdRemapping& cameraIdRemapping) {
     if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
-        const int pid = CameraThreadState::getCallingPid();
-        const int uid = CameraThreadState::getCallingUid();
+        const int pid = getCallingPid();
+        const int uid = getCallingUid();
         ALOGE("%s: Permission Denial: can't configure camera ID mapping pid=%d, uid=%d",
                 __FUNCTION__, pid, uid);
         return STATUS_ERROR(ERROR_PERMISSION_DENIED,
@@ -894,7 +810,7 @@
     }
 
     const std::string cameraId = resolveCameraId(unresolvedCameraId,
-            CameraThreadState::getCallingUid());
+            getCallingUid());
 
     binder::Status res;
     if (request == nullptr) {
@@ -950,7 +866,7 @@
     }
 
     const std::string cameraId = resolveCameraId(unresolvedCameraId,
-            CameraThreadState::getCallingUid());
+            getCallingUid());
     if (supported == nullptr) {
         std::string msg = fmt::sprintf("Camera %s: Invalid 'support' input!",
                 unresolvedCameraId.c_str());
@@ -1007,7 +923,7 @@
     }
 
     const std::string cameraId =
-            resolveCameraId(unresolvedCameraId, CameraThreadState::getCallingUid());
+            resolveCameraId(unresolvedCameraId, getCallingUid());
 
     if (outMetadata == nullptr) {
         std::string msg =
@@ -1124,7 +1040,7 @@
     mServiceLock.unlock();
 
     // Clear calling identity for disconnect() PID checks.
-    int64_t token = CameraThreadState::clearCallingIdentity();
+    int64_t token = clearCallingIdentity();
 
     // Disconnect clients.
     for (auto& clientSp : clientsToDisconnect) {
@@ -1136,7 +1052,7 @@
     // Invoke destructors (which call disconnect()) now while we don't hold the mServiceLock.
     clientsToDisconnect.clear();
 
-    CameraThreadState::restoreCallingIdentity(token);
+    restoreCallingIdentity(token);
     mServiceLock.lock();
 
     {
@@ -1151,8 +1067,8 @@
             const std::string& cameraId,
             const CameraMetadata& sessionParams) {
    if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
-        const int pid = CameraThreadState::getCallingPid();
-        const int uid = CameraThreadState::getCallingUid();
+        const int pid = getCallingPid();
+        const int uid = getCallingUid();
         ALOGE("%s: Permission Denial: can't inject session params pid=%d, uid=%d",
                 __FUNCTION__, pid, uid);
         return STATUS_ERROR(ERROR_PERMISSION_DENIED,
@@ -1230,7 +1146,7 @@
     Mutex::Autolock l(mServiceLock);
     std::string unresolvedCameraId = cameraIdIntToStrLocked(cameraId);
     std::string cameraIdStr = resolveCameraId(
-            unresolvedCameraId, CameraThreadState::getCallingUid());
+            unresolvedCameraId, getCallingUid());
 
     if (shouldRejectSystemCameraConnection(cameraIdStr)) {
         return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
@@ -1243,7 +1159,7 @@
                 "Camera subsystem is not available");
     }
     bool hasSystemCameraPermissions = hasPermissionsForSystemCamera(std::to_string(cameraId),
-            CameraThreadState::getCallingPid(), CameraThreadState::getCallingUid());
+            getCallingPid(), getCallingUid());
     int cameraIdBound = mNumberOfCamerasWithoutSystemCamera;
     if (hasSystemCameraPermissions) {
         cameraIdBound = mNumberOfCameras;
@@ -1270,15 +1186,11 @@
 
 std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt) {
     const std::vector<std::string> *deviceIds = &mNormalDeviceIdsWithoutSystemCamera;
-    auto callingPid = CameraThreadState::getCallingPid();
-    auto callingUid = CameraThreadState::getCallingUid();
-    AttributionSourceState attributionSource{};
-    attributionSource.pid = callingPid;
-    attributionSource.uid = callingUid;
-    bool checkPermissionForSystemCamera = checkPermission(std::to_string(cameraIdInt),
-                sSystemCameraPermission, attributionSource, std::string(),
-                AppOpsManager::OP_NONE);
-    if (checkPermissionForSystemCamera || getpid() == callingPid) {
+    auto callingPid = getCallingPid();
+    auto callingUid = getCallingUid();
+    bool systemCameraPermissions = hasPermissionsForSystemCamera(std::to_string(cameraIdInt),
+            callingPid, callingUid, /* checkCameraPermissions= */ false);
+    if (systemCameraPermissions || getpid() == callingPid) {
         deviceIds = &mNormalDeviceIds;
     }
     if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(deviceIds->size())) {
@@ -1300,7 +1212,7 @@
     ATRACE_CALL();
 
     const std::string cameraId = resolveCameraId(unresolvedCameraId,
-            CameraThreadState::getCallingUid());
+            getCallingUid());
 
     if (!cameraInfo) {
         ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
@@ -1345,17 +1257,13 @@
         return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera kind "
                 "for device %s", cameraId.c_str());
     }
-    int callingPid = CameraThreadState::getCallingPid();
-    int callingUid = CameraThreadState::getCallingUid();
+    int callingPid = getCallingPid();
+    int callingUid = getCallingUid();
     std::vector<int32_t> tagsRemoved;
     // If it's not calling from cameraserver, check the permission only if
     // android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
     // it would've already been checked in shouldRejectSystemCameraConnection.
-    AttributionSourceState attributionSource{};
-    attributionSource.pid = callingPid;
-    attributionSource.uid = callingUid;
-    bool checkPermissionForCamera = checkPermission(cameraId, sCameraPermission,
-            attributionSource, std::string(), AppOpsManager::OP_NONE);
+    bool checkPermissionForCamera = hasPermissionsForCamera(cameraId, callingPid, callingUid);
     if ((callingPid != getpid()) &&
             (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
             !checkPermissionForCamera) {
@@ -1388,8 +1296,9 @@
         int32_t* torchStrength) {
     ATRACE_CALL();
     Mutex::Autolock l(mServiceLock);
+
     const std::string cameraId = resolveCameraId(
-        unresolvedCameraId, CameraThreadState::getCallingUid());
+        unresolvedCameraId, getCallingUid());
     if (!mInitialized) {
         ALOGE("%s: Camera HAL couldn't be initialized.", __FUNCTION__);
         return STATUS_ERROR(ERROR_DISCONNECTED, "Camera HAL couldn't be initialized.");
@@ -1541,7 +1450,7 @@
     if (effectiveApiLevel == API_1) { // Camera1 API route
         sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
         *client = new Camera2Client(cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
-                packageName, featureId, cameraId,
+                cameraService->mAttributionAndPermissionUtils, packageName, featureId, cameraId,
                 api1CameraId, facing, sensorOrientation,
                 clientPid, clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
                 forceSlowJpegMode);
@@ -1551,7 +1460,8 @@
         sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                 static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
         *client = new CameraDeviceClient(cameraService, tmp,
-                cameraService->mCameraServiceProxyWrapper, packageName, systemNativeClient,
+                cameraService->mCameraServiceProxyWrapper,
+                cameraService->mAttributionAndPermissionUtils, packageName, systemNativeClient,
                 featureId, cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
                 overrideForPerfClass, overrideToPortrait, originalCameraId);
         ALOGI("%s: Camera2 API, override to portrait %d", __FUNCTION__, overrideToPortrait);
@@ -1634,7 +1544,7 @@
 }
 
 Status CameraService::initializeShimMetadata(int cameraId) {
-    int uid = CameraThreadState::getCallingUid();
+    int uid = getCallingUid();
 
     std::string cameraIdStr = std::to_string(cameraId);
     Status ret = Status::ok();
@@ -1666,7 +1576,7 @@
 
     std::string unresolvedCameraId = std::to_string(cameraId);
     std::string cameraIdStr = resolveCameraId(unresolvedCameraId,
-            CameraThreadState::getCallingUid());
+            getCallingUid());
 
     // Check if we already have parameters
     {
@@ -1685,9 +1595,9 @@
         }
     }
 
-    int64_t token = CameraThreadState::clearCallingIdentity();
+    int64_t token = clearCallingIdentity();
     ret = initializeShimMetadata(cameraId);
-    CameraThreadState::restoreCallingIdentity(token);
+    restoreCallingIdentity(token);
     if (!ret.isOk()) {
         // Error already logged by callee
         return ret;
@@ -1715,38 +1625,6 @@
     return STATUS_ERROR(ERROR_INVALID_OPERATION, "Unable to initialize legacy parameters");
 }
 
-// Can camera service trust the caller based on the calling UID?
-static bool isTrustedCallingUid(uid_t uid) {
-    switch (uid) {
-        case AID_MEDIA:        // mediaserver
-        case AID_CAMERASERVER: // cameraserver
-        case AID_RADIO:        // telephony
-            return true;
-        default:
-            return false;
-    }
-}
-
-static status_t getUidForPackage(const std::string &packageName, int userId, /*inout*/uid_t& uid,
-        int err) {
-    PermissionController pc;
-    uid = pc.getPackageUid(toString16(packageName), 0);
-    if (uid <= 0) {
-        ALOGE("Unknown package: '%s'", packageName.c_str());
-        dprintf(err, "Unknown package: '%s'\n", packageName.c_str());
-        return BAD_VALUE;
-    }
-
-    if (userId < 0) {
-        ALOGE("Invalid user: %d", userId);
-        dprintf(err, "Invalid user: %d\n", userId);
-        return BAD_VALUE;
-    }
-
-    uid = multiuser_get_uid(userId, uid);
-    return NO_ERROR;
-}
-
 Status CameraService::validateConnectLocked(const std::string& cameraId,
         const std::string& clientName8, /*inout*/int& clientUid, /*inout*/int& clientPid,
         /*out*/int& originalClientPid) const {
@@ -1764,7 +1642,7 @@
     }
 #endif  // __BRILLO__
 
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = getCallingPid();
 
     if (!mInitialized) {
         ALOGE("CameraService::connect X (PID %d) rejected (camera HAL module not loaded)",
@@ -1798,10 +1676,8 @@
 Status CameraService::validateClientPermissionsLocked(const std::string& cameraId,
         const std::string& clientName, int& clientUid, int& clientPid,
         /*out*/int& originalClientPid) const {
-    AttributionSourceState attributionSource{};
-
-    int callingPid = CameraThreadState::getCallingPid();
-    int callingUid = CameraThreadState::getCallingUid();
+    int callingPid = getCallingPid();
+    int callingUid = getCallingUid();
 
     // Check if we can trust clientUid
     if (clientUid == USE_CALLING_UID) {
@@ -1813,7 +1689,7 @@
                 "Untrusted caller (calling PID %d, UID %d) trying to "
                 "forward camera access to camera %s for client %s (PID %d, UID %d)",
                 callingPid, callingUid, cameraId.c_str(),
-                clientName.c_str(), clientUid, clientPid);
+                clientName.c_str(), clientPid, clientUid);
     }
 
     // Check if we can trust clientPid
@@ -1826,7 +1702,7 @@
                 "Untrusted caller (calling PID %d, UID %d) trying to "
                 "forward camera access to camera %s for client %s (PID %d, UID %d)",
                 callingPid, callingUid, cameraId.c_str(),
-                clientName.c_str(), clientUid, clientPid);
+                clientName.c_str(), clientPid, clientUid);
     }
 
     if (shouldRejectSystemCameraConnection(cameraId)) {
@@ -1846,17 +1722,14 @@
     // If it's not calling from cameraserver, check the permission if the
     // device isn't a system only camera (shouldRejectSystemCameraConnection already checks for
     // android.permission.SYSTEM_CAMERA for system only camera devices).
-    attributionSource.pid = clientPid;
-    attributionSource.uid = clientUid;
-    attributionSource.packageName = clientName;
-    bool checkPermissionForCamera = checkPermission(cameraId, sCameraPermission, attributionSource,
-            std::string(), AppOpsManager::OP_NONE);
+    bool checkPermissionForCamera =
+            hasPermissionsForCamera(cameraId, clientPid, clientUid, clientName);
     if (callingPid != getpid() &&
                 (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) && !checkPermissionForCamera) {
         ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
         return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                 "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" without camera permission",
-                clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+                clientName.c_str(), clientPid, clientUid, cameraId.c_str());
     }
 
     // Make sure the UID is in an active state to use the camera
@@ -1867,7 +1740,7 @@
         return STATUS_ERROR_FMT(ERROR_DISABLED,
                 "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" from background ("
                 "calling UID %d proc state %" PRId32 ")",
-                clientName.c_str(), clientUid, clientPid, cameraId.c_str(),
+                clientName.c_str(), clientPid, clientUid, cameraId.c_str(),
                 callingUid, procState);
     }
 
@@ -1880,7 +1753,7 @@
         ALOGE("Access Denial: cannot use the camera when sensor privacy is enabled");
         return STATUS_ERROR_FMT(ERROR_DISABLED,
                 "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" when sensor privacy "
-                "is enabled", clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+                "is enabled", clientName.c_str(), clientPid, clientUid, cameraId.c_str());
     }
 
     // Only use passed in clientPid to check permission. Use calling PID as the client PID that's
@@ -1892,7 +1765,7 @@
 
     // For non-system clients : Only allow clients who are being used by the current foreground
     // device user, unless calling from our own process.
-    if (!doesClientHaveSystemUid() && callingPid != getpid() &&
+    if (!callerHasSystemUid() && callingPid != getpid() &&
             (mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) {
         ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from "
                 "device user %d, currently allowed device users: %s)", callingPid, clientUserId,
@@ -1906,13 +1779,14 @@
         // If the System User tries to access the camera when the device is running in
         // headless system user mode, ensure that client has the required permission
         // CAMERA_HEADLESS_SYSTEM_USER.
-        if (isHeadlessSystemUserMode() && (clientUserId == USER_SYSTEM) &&
-                !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
+        if (isHeadlessSystemUserMode()
+                && (clientUserId == USER_SYSTEM)
+                && !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
             ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
             return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                     "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" as Headless System \
                     User without camera headless system user permission",
-                    clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+                    clientName.c_str(), clientPid, clientUid, cameraId.c_str());
         }
     }
 
@@ -1921,7 +1795,7 @@
 
 status_t CameraService::checkIfDeviceIsUsable(const std::string& cameraId) const {
     auto cameraState = getCameraState(cameraId);
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = getCallingPid();
     if (cameraState == nullptr) {
         ALOGE("CameraService::connect X (PID %d) rejected (invalid camera ID %s)", callingPid,
                 cameraId.c_str());
@@ -2019,7 +1893,7 @@
 
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder = sm->checkService(String16(kProcessInfoServiceName));
-        if (!binder && isAutomotivePrivilegedClient(CameraThreadState::getCallingUid())) {
+        if (!binder && isAutomotivePrivilegedClient(getCallingUid())) {
             // If processinfo service is not available and the client is automotive privileged
             // client used for safety critical uses cases such as rear-view and surround-view which
             // needs to be available before android boot completes, then use the hardcoded values
@@ -2152,7 +2026,7 @@
     mServiceLock.unlock();
 
     // Clear caller identity temporarily so client disconnect PID checks work correctly
-    int64_t token = CameraThreadState::clearCallingIdentity();
+    int64_t token = clearCallingIdentity();
 
     // Destroy evicted clients
     for (auto& i : evictedClients) {
@@ -2160,7 +2034,7 @@
         i->getValue()->disconnect(); // Clients will remove themselves from the active client list
     }
 
-    CameraThreadState::restoreCallingIdentity(token);
+    restoreCallingIdentity(token);
 
     for (const auto& i : evictedClients) {
         ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",
@@ -2211,7 +2085,7 @@
 
     std::string unresolvedCameraId = cameraIdIntToStr(api1CameraId);
     std::string cameraIdStr = resolveCameraId(unresolvedCameraId,
-            CameraThreadState::getCallingUid());
+            getCallingUid());
 
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, cameraIdStr, api1CameraId,
@@ -2220,7 +2094,7 @@
             overrideToPortrait, forceSlowJpegMode, cameraIdStr, /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(cameraIdStr, CameraThreadState::getCallingPid(), clientPackageName,
+        logRejected(cameraIdStr, getCallingPid(), clientPackageName,
                 toStdString(ret.toString8()));
         return ret;
     }
@@ -2231,8 +2105,8 @@
     const auto& mActivityManager = getActivityManager();
     if (mActivityManager) {
         mActivityManager->logFgsApiBegin(LOG_FGS_CAMERA_API,
-            CameraThreadState::getCallingUid(),
-            CameraThreadState::getCallingPid());
+            getCallingUid(),
+            getCallingPid());
     }
 
     return ret;
@@ -2262,9 +2136,9 @@
     //    and the serving thread is a non hwbinder thread, the client must have
     //    android.permission.SYSTEM_CAMERA permissions to connect.
 
-    int cPid = CameraThreadState::getCallingPid();
-    int cUid = CameraThreadState::getCallingUid();
-    bool systemClient = doesClientHaveSystemUid();
+    int cPid = getCallingPid();
+    int cUid = getCallingUid();
+    bool systemClient = callerHasSystemUid();
     SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
     if (getSystemCameraKind(cameraId, &systemCameraKind) != OK) {
         // This isn't a known camera ID, so it's not a system camera
@@ -2273,7 +2147,7 @@
     }
 
     // (1) Cameraserver trying to connect, accept.
-    if (CameraThreadState::getCallingPid() == getpid()) {
+    if (isCallerCameraServerNotDelegating()) {
         return false;
     }
     // (2)
@@ -2309,17 +2183,18 @@
     Status ret = Status::ok();
     sp<CameraDeviceClient> client = nullptr;
     std::string clientPackageNameAdj = clientPackageName;
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = getCallingPid();
+    int callingUid = getCallingUid();
     bool systemNativeClient = false;
-    if (doesClientHaveSystemUid() && (clientPackageNameAdj.size() == 0)) {
-        std::string systemClient =
-                fmt::sprintf("client.pid<%d>", CameraThreadState::getCallingPid());
+    if (callerHasSystemUid() && (clientPackageNameAdj.size() == 0)) {
+        std::string systemClient = fmt::sprintf("client.pid<%d>", callingPid);
         clientPackageNameAdj = systemClient;
         systemNativeClient = true;
     }
+
     const std::string cameraId = resolveCameraId(
             unresolvedCameraId,
-            CameraThreadState::getCallingUid(),
+            callingUid,
             clientPackageNameAdj);
 
     if (oomScoreOffset < 0) {
@@ -2332,7 +2207,6 @@
     }
 
     userid_t clientUserId = multiuser_get_user_id(clientUid);
-    int callingUid = CameraThreadState::getCallingUid();
     if (clientUid == USE_CALLING_UID) {
         clientUserId = multiuser_get_user_id(callingUid);
     }
@@ -2349,8 +2223,8 @@
     // enforce system camera permissions
     if (oomScoreOffset > 0
             && !hasPermissionsForSystemCamera(cameraId, callingPid,
-                    CameraThreadState::getCallingUid())
-            && !isTrustedCallingUid(CameraThreadState::getCallingUid())) {
+                    callingUid)
+            && !isTrustedCallingUid(callingUid)) {
         std::string msg = fmt::sprintf("Cannot change the priority of a client %s pid %d for "
                         "camera id %s without SYSTEM_CAMERA permissions",
                         clientPackageNameAdj.c_str(), callingPid, cameraId.c_str());
@@ -2390,8 +2264,8 @@
     const auto& mActivityManager = getActivityManager();
     if (mActivityManager) {
         mActivityManager->logFgsApiBegin(LOG_FGS_CAMERA_API,
-            CameraThreadState::getCallingUid(),
-            CameraThreadState::getCallingPid());
+            callingUid,
+            callingPid);
     }
     return ret;
 }
@@ -2414,12 +2288,8 @@
         return true;
     } else if (mSensorPrivacyPolicy->getCameraPrivacyState() == SensorPrivacyManager::DISABLED) {
         return false;
-    } else if ((mSensorPrivacyPolicy->getCameraPrivacyState()
-            == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_HELPFUL_APPS) ||
-            (mSensorPrivacyPolicy->getCameraPrivacyState()
-            == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_REQUIRED_APPS) ||
-            (mSensorPrivacyPolicy->getCameraPrivacyState() ==
-            SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_APPS)) {
+    } else if (mSensorPrivacyPolicy->getCameraPrivacyState()
+            == SensorPrivacyManager::ENABLED_EXCEPT_ALLOWLISTED_APPS) {
         if (hasPermissionsForCameraPrivacyAllowlist(callingPid, callingUid)) {
             return false;
         } else {
@@ -2432,16 +2302,31 @@
 std::string CameraService::getPackageNameFromUid(int clientUid) {
     std::string packageName("");
 
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(toString16(kPermissionServiceName));
-    if (binder == 0) {
-        ALOGE("Cannot get permission service");
+    sp<IPermissionController> permCtrl;
+    if (flags::cache_permission_services()) {
+        permCtrl = getPermissionController();
+    } else {
+        sp<IServiceManager> sm = defaultServiceManager();
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+        // Using deprecated function to preserve functionality until the
+        // cache_permission_services flag is removed.
+        sp<IBinder> binder = sm->getService(toString16(kPermissionServiceName));
+#pragma clang diagnostic pop
+        if (binder == 0) {
+            ALOGE("Cannot get permission service");
+            permCtrl = nullptr;
+        } else {
+            permCtrl = interface_cast<IPermissionController>(binder);
+        }
+    }
+
+    if (permCtrl == nullptr) {
         // Return empty package name and the further interaction
         // with camera will likely fail
         return packageName;
     }
 
-    sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
     Vector<String16> packages;
 
     permCtrl->getPackagesForUid(clientUid, packages);
@@ -2471,7 +2356,7 @@
     bool isNonSystemNdk = false;
     std::string clientPackageName;
     int packageUid = (clientUid == USE_CALLING_UID) ?
-            CameraThreadState::getCallingUid() : clientUid;
+            getCallingUid() : clientUid;
     if (clientPackageNameMaybe.size() <= 0) {
         // NDK calls don't come with package names, but we need one for various cases.
         // Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
@@ -2487,7 +2372,7 @@
     int originalClientPid = 0;
 
     int packagePid = (clientPid == USE_CALLING_PID) ?
-        CameraThreadState::getCallingPid() : clientPid;
+        getCallingPid() : clientPid;
     ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) and "
             "Camera API version %d", packagePid, clientPackageName.c_str(), cameraId.c_str(),
             static_cast<int>(effectiveApiLevel));
@@ -2724,11 +2609,11 @@
             mServiceLock.unlock();
             // Clear caller identity temporarily so client disconnect PID
             // checks work correctly
-            int64_t token = CameraThreadState::clearCallingIdentity();
+            int64_t token = clearCallingIdentity();
             // Note AppOp to trigger the "Unblock" dialog
             client->noteAppOp();
             client->disconnect();
-            CameraThreadState::restoreCallingIdentity(token);
+            restoreCallingIdentity(token);
             // Reacquire mServiceLock
             mServiceLock.lock();
 
@@ -2880,7 +2765,7 @@
                 "Torch client binder in null.");
     }
 
-    int uid = CameraThreadState::getCallingUid();
+    int uid = getCallingUid();
     const std::string cameraId = resolveCameraId(unresolvedCameraId, uid);
     if (shouldRejectSystemCameraConnection(cameraId)) {
         return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to change the strength level"
@@ -2988,7 +2873,7 @@
         clientBinder->linkToDeath(this);
     }
 
-    int clientPid = CameraThreadState::getCallingPid();
+    int clientPid = getCallingPid();
     ALOGI("%s: Torch strength for camera id %s changed to %d for client PID %d",
             __FUNCTION__, cameraId.c_str(), torchStrength, clientPid);
     if (!shouldSkipTorchStrengthUpdates) {
@@ -3008,7 +2893,7 @@
                 "Torch client Binder is null");
     }
 
-    int uid = CameraThreadState::getCallingUid();
+    int uid = getCallingUid();
     const std::string cameraId = resolveCameraId(unresolvedCameraId, uid);
 
     if (shouldRejectSystemCameraConnection(cameraId)) {
@@ -3116,7 +3001,7 @@
         }
     }
 
-    int clientPid = CameraThreadState::getCallingPid();
+    int clientPid = getCallingPid();
     std::string torchState = enabled ? "on" : "off";
     ALOGI("Torch for camera id %s turned %s for client PID %d", cameraId.c_str(),
             torchState.c_str(), clientPid);
@@ -3136,7 +3021,7 @@
 
 Status CameraService::notifySystemEvent(int32_t eventId,
         const std::vector<int32_t>& args) {
-    const int pid = CameraThreadState::getCallingPid();
+    const int pid = getCallingPid();
     const int selfPid = getpid();
 
     // Permission checks
@@ -3144,7 +3029,7 @@
         // Ensure we're being called by system_server, or similar process with
         // permissions to notify the camera service about system events
         if (!checkCallingPermission(toString16(sCameraSendSystemEventsPermission))) {
-            const int uid = CameraThreadState::getCallingUid();
+            const int uid = getCallingUid();
             ALOGE("Permission Denial: cannot send updates to camera service about system"
                     " events from pid=%d, uid=%d", pid, uid);
             return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
@@ -3210,7 +3095,7 @@
 }
 
 Status CameraService::notifyDeviceStateChange(int64_t newState) {
-    const int pid = CameraThreadState::getCallingPid();
+    const int pid = getCallingPid();
     const int selfPid = getpid();
 
     // Permission checks
@@ -3218,7 +3103,7 @@
         // Ensure we're being called by system_server, or similar process with
         // permissions to notify the camera service about system events
         if (!checkCallingPermission(toString16(sCameraSendSystemEventsPermission))) {
-            const int uid = CameraThreadState::getCallingUid();
+            const int uid = getCallingUid();
             ALOGE("Permission Denial: cannot send updates to camera service about device"
                     " state changes from pid=%d, uid=%d", pid, uid);
             return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
@@ -3241,7 +3126,7 @@
 
 Status CameraService::notifyDisplayConfigurationChange() {
     ATRACE_CALL();
-    const int callingPid = CameraThreadState::getCallingPid();
+    const int callingPid = getCallingPid();
     const int selfPid = getpid();
 
     // Permission checks
@@ -3249,7 +3134,7 @@
         // Ensure we're being called by system_server, or similar process with
         // permissions to notify the camera service about system events
         if (!checkCallingPermission(toString16(sCameraSendSystemEventsPermission))) {
-            const int uid = CameraThreadState::getCallingUid();
+            const int uid = getCallingUid();
             ALOGE("Permission Denial: cannot send updates to camera service about orientation"
                     " changes from pid=%d, uid=%d", callingPid, uid);
             return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
@@ -3323,22 +3208,6 @@
     return Status::ok();
 }
 
-bool CameraService::hasCameraPermissions() const {
-    int callingPid = CameraThreadState::getCallingPid();
-    int callingUid = CameraThreadState::getCallingUid();
-    AttributionSourceState attributionSource{};
-    attributionSource.pid = callingPid;
-    attributionSource.uid = callingUid;
-    bool res = checkPermission(std::string(), sCameraPermission,
-            attributionSource, std::string(), AppOpsManager::OP_NONE);
-
-    bool hasPermission = ((callingPid == getpid()) || res);
-    if (!hasPermission) {
-        ALOGE("%s: pid %d doesn't have camera permissions", __FUNCTION__, callingPid);
-    }
-    return hasPermission;
-}
-
 Status CameraService::isConcurrentSessionConfigurationSupported(
         const std::vector<CameraIdAndSessionConfiguration>& cameraIdsAndSessionConfigurations,
         int targetSdkVersion, /*out*/bool* isSupported) {
@@ -3354,7 +3223,11 @@
     }
 
     // Check for camera permissions
-    if (!hasCameraPermissions()) {
+    int callingPid = getCallingPid();
+    int callingUid = getCallingUid();
+    bool hasCameraPermission = ((callingPid == getpid()) ||
+            hasPermissionsForCamera(callingPid, callingUid));
+    if (!hasCameraPermission) {
         return STATUS_ERROR(ERROR_PERMISSION_DENIED,
                 "android.permission.CAMERA needed to call"
                 "isConcurrentSessionConfigurationSupported");
@@ -3398,15 +3271,9 @@
         return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null listener given to addListener");
     }
 
-    auto clientUid = CameraThreadState::getCallingUid();
-    auto clientPid = CameraThreadState::getCallingPid();
-    AttributionSourceState attributionSource{};
-    attributionSource.uid = clientUid;
-    attributionSource.pid = clientPid;
-
-   bool openCloseCallbackAllowed = checkPermission(std::string(),
-            sCameraOpenCloseListenerPermission, attributionSource, std::string(),
-            AppOpsManager::OP_NONE);
+    auto clientPid = getCallingPid();
+    auto clientUid = getCallingUid();
+    bool openCloseCallbackAllowed = hasPermissionsForOpenCloseListener(clientPid, clientUid);
 
     Mutex::Autolock lock(mServiceLock);
 
@@ -3547,7 +3414,7 @@
     ATRACE_CALL();
 
     const std::string cameraId = resolveCameraId(
-            unresolvedCameraId, CameraThreadState::getCallingUid());
+            unresolvedCameraId, getCallingUid());
 
     ALOGV("%s: for camera ID = %s", __FUNCTION__, cameraId.c_str());
 
@@ -3612,7 +3479,7 @@
     ATRACE_CALL();
 
     const std::string cameraId = resolveCameraId(unresolvedCameraId,
-            CameraThreadState::getCallingUid());
+            getCallingUid());
 
     ALOGV("%s: for camera ID = %s", __FUNCTION__, cameraId.c_str());
     *isSupported = mCameraProviderManager->isHiddenPhysicalCamera(cameraId);
@@ -3629,8 +3496,8 @@
     ATRACE_CALL();
 
     if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
-        const int pid = CameraThreadState::getCallingPid();
-        const int uid = CameraThreadState::getCallingUid();
+        const int pid = getCallingPid();
+        const int uid = getCallingUid();
         ALOGE("Permission Denial: can't inject camera pid=%d, uid=%d", pid, uid);
         return STATUS_ERROR(ERROR_PERMISSION_DENIED,
                         "Permission Denial: no permission to inject camera");
@@ -3832,13 +3699,13 @@
     mServiceLock.unlock();
 
     // Clear caller identity temporarily so client disconnect PID checks work correctly
-    int64_t token = CameraThreadState::clearCallingIdentity();
+    int64_t token = clearCallingIdentity();
 
     for (auto& i : evicted) {
         i->disconnect();
     }
 
-    CameraThreadState::restoreCallingIdentity(token);
+    restoreCallingIdentity(token);
 
     // Reacquire mServiceLock
     mServiceLock.lock();
@@ -4049,6 +3916,7 @@
 
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& clientPackageName, bool systemNativeClient,
         const std::optional<std::string>& clientFeatureId,
         const std::string& cameraIdStr,
@@ -4057,13 +3925,14 @@
         int servicePid, bool overrideToPortrait) :
         CameraService::BasicClient(cameraService,
                 IInterface::asBinder(cameraClient),
+                attributionAndPermissionUtils,
                 clientPackageName, systemNativeClient, clientFeatureId,
                 cameraIdStr, cameraFacing, sensorOrientation,
                 clientPid, clientUid,
                 servicePid, overrideToPortrait),
         mCameraId(api1CameraId)
 {
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, mCameraId);
 
     mRemoteCallback = cameraClient;
@@ -4087,10 +3956,12 @@
 
 CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
         const sp<IBinder>& remoteCallback,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& clientPackageName, bool nativeClient,
         const std::optional<std::string>& clientFeatureId, const std::string& cameraIdStr,
         int cameraFacing, int sensorOrientation, int clientPid, uid_t clientUid,
         int servicePid, bool overrideToPortrait):
+        AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils),
         mDestructionStarted(false),
         mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing), mOrientation(sensorOrientation),
         mClientPackageName(clientPackageName), mSystemNativeClient(nativeClient),
@@ -4160,8 +4031,8 @@
     const auto& mActivityManager = getActivityManager();
     if (mActivityManager) {
         mActivityManager->logFgsApiEnd(LOG_FGS_CAMERA_API,
-            CameraThreadState::getCallingUid(),
-            CameraThreadState::getCallingPid());
+            getCallingUid(),
+            getCallingPid());
     }
 
     return res;
@@ -4171,7 +4042,7 @@
     // No dumping of clients directly over Binder,
     // must go through CameraService::dump
     android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "26265403",
-            CameraThreadState::getCallingUid(), NULL, 0);
+            getCallingUid(), NULL, 0);
     return OK;
 }
 
@@ -4504,7 +4375,7 @@
 
     // Reset the client PID to allow server-initiated disconnect,
     // and to prevent further calls by client.
-    mClientPid = CameraThreadState::getCallingPid();
+    mClientPid = getCallingPid();
     CaptureResultExtras resultExtras; // a dummy result (invalid)
     notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISABLED, resultExtras);
     disconnect();
@@ -4978,9 +4849,7 @@
     // if sensor privacy is enabled then block all clients from accessing the camera
     if (state == SensorPrivacyManager::ENABLED) {
         service->blockAllClients();
-    } else if ((state == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_APPS)
-            || (state == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_HELPFUL_APPS)
-            || (state == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_REQUIRED_APPS)) {
+    } else if (state == SensorPrivacyManager::ENABLED_EXCEPT_ALLOWLISTED_APPS) {
         service->blockPrivacyEnabledClients();
     }
     return binder::Status::ok();
@@ -5338,8 +5207,8 @@
 
     if (checkCallingPermission(toString16(sDumpPermission)) == false) {
         dprintf(fd, "Permission Denial: can't dump CameraService from pid=%d, uid=%d\n",
-                CameraThreadState::getCallingPid(),
-                CameraThreadState::getCallingUid());
+                getCallingPid(),
+                getCallingUid());
         return NO_ERROR;
     }
     bool locked = tryLock(mServiceLock);
@@ -5588,7 +5457,7 @@
       * binder driver
       */
     // PID here is approximate and can be wrong.
-    logClientDied(CameraThreadState::getCallingPid(), "Binder died unexpectedly");
+    logClientDied(getCallingPid(), "Binder died unexpectedly");
 
     // check torch client
     handleTorchClientBinderDied(who);
@@ -6604,9 +6473,9 @@
         mServiceLock.unlock();
 
         // Clear caller identity temporarily so client disconnect PID checks work correctly
-        int64_t token = CameraThreadState::clearCallingIdentity();
+        int64_t token = clearCallingIdentity();
         clientSp->disconnect();
-        CameraThreadState::restoreCallingIdentity(token);
+        restoreCallingIdentity(token);
 
         // Reacquire mServiceLock
         mServiceLock.lock();
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8822cd3..f25cf7d 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -34,6 +34,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/IActivityManager.h>
 #include <binder/IAppOpsCallback.h>
+#include <binder/IPermissionController.h>
 #include <binder/IUidObserver.h>
 #include <hardware/camera.h>
 #include <sensorprivacy/SensorPrivacyManager.h>
@@ -53,6 +54,7 @@
 #include "utils/ClientManager.h"
 #include "utils/IPCTransport.h"
 #include "utils/CameraServiceProxyWrapper.h"
+#include "utils/AttributionAndPermissionUtils.h"
 
 #include <set>
 #include <string>
@@ -77,7 +79,8 @@
     public virtual ::android::hardware::BnCameraService,
     public virtual IBinder::DeathRecipient,
     public virtual CameraProviderManager::StatusListener,
-    public virtual IServiceManager::LocalRegistrationCallback
+    public virtual IServiceManager::LocalRegistrationCallback,
+    public AttributionAndPermissionUtilsEncapsulator
 {
     friend class BinderService<CameraService>;
     friend class CameraOfflineSessionClient;
@@ -119,7 +122,9 @@
                         // Non-null arguments for cameraServiceProxyWrapper should be provided for
                         // testing purposes only.
                         CameraService(std::shared_ptr<CameraServiceProxyWrapper>
-                                cameraServiceProxyWrapper = nullptr);
+                                cameraServiceProxyWrapper = nullptr,
+                                std::shared_ptr<AttributionAndPermissionUtils>
+                                attributionAndPermissionUtils = nullptr);
     virtual             ~CameraService();
 
     /////////////////////////////////////////////////////////////////////
@@ -314,10 +319,20 @@
     // Shared utilities
     static binder::Status filterGetInfoErrorCode(status_t err);
 
+    /**
+     * Returns true if the device is an automotive device and cameraId is system
+     * only camera which has characteristic AUTOMOTIVE_LOCATION value as either
+     * AUTOMOTIVE_LOCATION_EXTERIOR_LEFT,AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT,
+     * AUTOMOTIVE_LOCATION_EXTERIOR_FRONT or AUTOMOTIVE_LOCATION_EXTERIOR_REAR.
+     */
+    bool isAutomotiveExteriorSystemCamera(const std::string& cameraId) const;
+
     /////////////////////////////////////////////////////////////////////
     // CameraClient functionality
 
-    class BasicClient : public virtual RefBase {
+    class BasicClient :
+        public virtual RefBase,
+        public AttributionAndPermissionUtilsEncapsulator {
     friend class CameraService;
     public:
         virtual status_t       initialize(sp<CameraProviderManager> manager,
@@ -428,6 +443,7 @@
     protected:
         BasicClient(const sp<CameraService>& cameraService,
                 const sp<IBinder>& remoteCallback,
+                std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
                 const std::string& clientPackageName,
                 bool nativeClient,
                 const std::optional<std::string>& clientFeatureId,
@@ -541,6 +557,7 @@
         // Interface used by CameraService
         Client(const sp<CameraService>& cameraService,
                 const sp<hardware::ICameraClient>& cameraClient,
+                std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
                 const std::string& clientPackageName,
                 bool systemNativeClient,
                 const std::optional<std::string>& clientFeatureId,
@@ -644,13 +661,6 @@
     int32_t updateAudioRestrictionLocked();
 
 private:
-    /**
-     * Returns true if the device is an automotive device and cameraId is system
-     * only camera which has characteristic AUTOMOTIVE_LOCATION value as either
-     * AUTOMOTIVE_LOCATION_EXTERIOR_LEFT,AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT,
-     * AUTOMOTIVE_LOCATION_EXTERIOR_FRONT or AUTOMOTIVE_LOCATION_EXTERIOR_REAR.
-     */
-    bool isAutomotiveExteriorSystemCamera(const std::string& cameraId) const;
 
     // TODO: b/263304156 update this to make use of a death callback for more
     // robust/fault tolerant logging
@@ -666,30 +676,26 @@
         return activityManager;
     }
 
+    static const sp<IPermissionController>& getPermissionController() {
+        static const char* kPermissionControllerService = "permission";
+        static thread_local sp<IPermissionController> sPermissionController = nullptr;
+
+        if (sPermissionController == nullptr ||
+                !IInterface::asBinder(sPermissionController)->isBinderAlive()) {
+            sp<IServiceManager> sm = defaultServiceManager();
+            sp<IBinder> binder = sm->checkService(toString16(kPermissionControllerService));
+            if (binder == nullptr) {
+                ALOGE("%s: Could not get permission service", __FUNCTION__);
+                sPermissionController = nullptr;
+            } else {
+                sPermissionController = interface_cast<IPermissionController>(binder);
+            }
+        }
+
+        return sPermissionController;
+    }
+
     /**
-     * Pre-grants the permission if the attribution source uid is for an automotive
-     * privileged client. Otherwise uses system service permission checker to check
-     * for the appropriate permission. If this function is called for accessing a specific
-     * camera,then the cameraID must not be empty. CameraId is used only in case of automotive
-     * privileged client so that permission is pre-granted only to access system camera device
-     * which is located outside of the vehicle body frame because camera located inside the vehicle
-     * cabin would need user permission.
-     */
-    bool checkPermission(const std::string& cameraId, const std::string& permission,
-            const content::AttributionSourceState& attributionSource, const std::string& message,
-            int32_t attributedOpCode) const;
-
-    bool hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid, int callingUid)
-            const;
-
-    bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId, int callingPid,
-            int callingUid) const;
-
-    bool hasCameraPermissions() const;
-
-    bool hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const;
-
-   /**
      * Typesafe version of device status, containing both the HAL-layer and the service interface-
      * layer values.
      */
@@ -873,10 +879,14 @@
     // prevented from accessing the camera.
     class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener,
             public virtual IBinder::DeathRecipient,
-            public virtual IServiceManager::LocalRegistrationCallback {
+            public virtual IServiceManager::LocalRegistrationCallback,
+            public AttributionAndPermissionUtilsEncapsulator {
         public:
-            explicit SensorPrivacyPolicy(wp<CameraService> service)
-                    : mService(service), mSensorPrivacyEnabled(false),
+            explicit SensorPrivacyPolicy(wp<CameraService> service,
+                    std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
+                    : AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils),
+                      mService(service),
+                      mSensorPrivacyEnabled(false),
                     mCameraPrivacyState(SensorPrivacyManager::DISABLED), mRegistered(false) {}
 
             void registerSelf();
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index caa6424..c0d9fdf 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -38,7 +38,6 @@
 #include "api1/client2/CallbackProcessor.h"
 #include "api1/client2/ZslProcessor.h"
 #include "device3/RotateAndCropMapper.h"
-#include "utils/CameraThreadState.h"
 #include "utils/CameraServiceProxyWrapper.h"
 
 #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
@@ -56,6 +55,7 @@
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
         const sp<hardware::ICameraClient>& cameraClient,
         std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& clientPackageName,
         const std::optional<std::string>& clientFeatureId,
         const std::string& cameraDeviceId,
@@ -68,7 +68,8 @@
         bool overrideForPerfClass,
         bool overrideToPortrait,
         bool forceSlowJpegMode):
-        Camera2ClientBase(cameraService, cameraClient, cameraServiceProxyWrapper, clientPackageName,
+        Camera2ClientBase(cameraService, cameraClient, cameraServiceProxyWrapper,
+                attributionAndPermissionUtils, clientPackageName,
                 false/*systemNativeClient - since no ndk for api1*/, clientFeatureId,
                 cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
                 clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
@@ -444,7 +445,7 @@
 
     binder::Status res = binder::Status::ok();
     // Allow both client and the cameraserver to disconnect at all times
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = getCallingPid();
     if (callingPid != mClientPid && callingPid != mServicePid) return res;
 
     if (mDevice == 0) return res;
@@ -513,14 +514,14 @@
     ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mBinderSerializationLock);
 
-    if (mClientPid != 0 && CameraThreadState::getCallingPid() != mClientPid) {
+    if (mClientPid != 0 && getCallingPid() != mClientPid) {
         ALOGE("%s: Camera %d: Connection attempt from pid %d; "
                 "current locked to pid %d", __FUNCTION__,
-                mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+                mCameraId, getCallingPid(), mClientPid);
         return BAD_VALUE;
     }
 
-    mClientPid = CameraThreadState::getCallingPid();
+    mClientPid = getCallingPid();
 
     mRemoteCallback = client;
     mSharedCameraCallbacks = client;
@@ -533,16 +534,16 @@
     ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
-            __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
 
     if (mClientPid == 0) {
-        mClientPid = CameraThreadState::getCallingPid();
+        mClientPid = getCallingPid();
         return OK;
     }
 
-    if (mClientPid != CameraThreadState::getCallingPid()) {
+    if (mClientPid != getCallingPid()) {
         ALOGE("%s: Camera %d: Lock call from pid %d; currently locked to pid %d",
-                __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+                __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
         return EBUSY;
     }
 
@@ -554,9 +555,9 @@
     ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
-            __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
 
-    if (mClientPid == CameraThreadState::getCallingPid()) {
+    if (mClientPid == getCallingPid()) {
         SharedParameters::Lock l(mParameters);
         if (l.mParameters.state == Parameters::RECORD ||
                 l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
@@ -570,7 +571,7 @@
     }
 
     ALOGE("%s: Camera %d: Unlock call from pid %d; currently locked to pid %d",
-            __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
     return EBUSY;
 }
 
@@ -1644,7 +1645,7 @@
     ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
     Mutex::Autolock icl(mBinderSerializationLock);
     // The camera service can unconditionally get the parameters at all times
-    if (CameraThreadState::getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
+    if (getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
 
     SharedParameters::ReadLock l(mParameters);
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 2cb7af0..2654a25 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -103,6 +103,7 @@
     Camera2Client(const sp<CameraService>& cameraService,
             const sp<hardware::ICameraClient>& cameraClient,
             std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+            std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
             const std::string& clientPackageName,
             const std::optional<std::string>& clientFeatureId,
             const std::string& cameraDeviceId,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 508d487..9513eeb 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -20,7 +20,6 @@
 
 #include <com_android_internal_camera_flags.h>
 #include <cutils/properties.h>
-#include <utils/CameraThreadState.h>
 #include <utils/Log.h>
 #include <utils/SessionConfigurationUtils.h>
 #include <utils/Trace.h>
@@ -61,6 +60,7 @@
 CameraDeviceClientBase::CameraDeviceClientBase(
         const sp<CameraService>& cameraService,
         const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& clientPackageName,
         bool systemNativeClient,
         const std::optional<std::string>& clientFeatureId,
@@ -74,6 +74,7 @@
         bool overrideToPortrait) :
     BasicClient(cameraService,
             IInterface::asBinder(remoteCallback),
+            attributionAndPermissionUtils,
             clientPackageName,
             systemNativeClient,
             clientFeatureId,
@@ -92,6 +93,7 @@
 CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
         const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
         std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& clientPackageName,
         bool systemNativeClient,
         const std::optional<std::string>& clientFeatureId,
@@ -104,7 +106,8 @@
         bool overrideForPerfClass,
         bool overrideToPortrait,
         const std::string& originalCameraId) :
-    Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper, clientPackageName,
+    Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper,
+            attributionAndPermissionUtils, clientPackageName,
             systemNativeClient, clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing,
             sensorOrientation, clientPid, clientUid, servicePid, overrideForPerfClass,
             overrideToPortrait),
@@ -888,6 +891,11 @@
 
     Mutex::Autolock icl(mBinderSerializationLock);
 
+    if (!outputConfiguration.isComplete()) {
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "OutputConfiguration isn't valid!");
+    }
+
     const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
             outputConfiguration.getGraphicBufferProducers();
     size_t numBufferProducers = bufferProducers.size();
@@ -904,7 +912,7 @@
     bool useReadoutTimestamp = outputConfiguration.useReadoutTimestamp();
 
     res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
-            outputConfiguration.getSurfaceType());
+            outputConfiguration.getSurfaceType(), /*isConfigurationComplete*/true);
     if (!res.isOk()) {
         return res;
     }
@@ -947,7 +955,7 @@
         res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
                 isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
                 mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
-                streamUseCase, timestampBase, mirrorMode, colorSpace);
+                streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
 
         if (!res.isOk())
             return res;
@@ -1060,6 +1068,10 @@
     if (!mDevice.get()) {
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
+    if (!outputConfiguration.isComplete()) {
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "OutputConfiguration isn't valid!");
+    }
 
     // Infer the surface info for deferred surface stream creation.
     width = outputConfiguration.getWidth();
@@ -1252,6 +1264,10 @@
     if (!mDevice.get()) {
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
+    if (!outputConfiguration.isComplete()) {
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "OutputConfiguration isn't valid!");
+    }
 
     const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
             outputConfiguration.getGraphicBufferProducers();
@@ -1319,7 +1335,7 @@
         res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
                 /*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
                 mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
-                streamUseCase, timestampBase, mirrorMode, colorSpace);
+                streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
         if (!res.isOk())
             return res;
 
@@ -1632,6 +1648,11 @@
 
     Mutex::Autolock icl(mBinderSerializationLock);
 
+    if (!outputConfiguration.isComplete()) {
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "OutputConfiguration isn't valid!");
+    }
+
     const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
             outputConfiguration.getGraphicBufferProducers();
     const std::string &physicalId = outputConfiguration.getPhysicalCameraId();
@@ -1697,7 +1718,7 @@
         res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
                 true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
                 mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile,
-                streamUseCase, timestampBase, mirrorMode, colorSpace);
+                streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
 
         if (!res.isOk())
             return res;
@@ -1900,9 +1921,9 @@
     sp<CameraOfflineSessionClient> offlineClient;
     if (offlineSession.get() != nullptr) {
         offlineClient = new CameraOfflineSessionClient(sCameraService,
-                offlineSession, offlineCompositeStreamMap, cameraCb, mClientPackageName,
-                mClientFeatureId, mCameraIdStr, mCameraFacing, mOrientation, mClientPid, mClientUid,
-                mServicePid);
+                offlineSession, offlineCompositeStreamMap, cameraCb, mAttributionAndPermissionUtils,
+                mClientPackageName, mClientFeatureId, mCameraIdStr, mCameraFacing, mOrientation,
+                mClientPid, mClientUid, mServicePid);
         ret = sCameraService->addOfflineClient(mCameraIdStr, offlineClient);
     }
 
@@ -2182,7 +2203,7 @@
 // TODO: move to Camera2ClientBase
 bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
 
-    const int pid = CameraThreadState::getCallingPid();
+    const int pid = getCallingPid();
     const int selfPid = getpid();
     camera_metadata_entry_t entry;
 
@@ -2221,7 +2242,7 @@
         String16 permissionString =
             toString16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
         if (!checkCallingPermission(permissionString)) {
-            const int uid = CameraThreadState::getCallingUid();
+            const int uid = getCallingUid();
             ALOGE("Permission Denial: "
                   "can't disable transmit LED pid=%d, uid=%d", pid, uid);
             return false;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index b2c9626..d93eaff 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -50,6 +50,7 @@
 protected:
     CameraDeviceClientBase(const sp<CameraService>& cameraService,
             const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
+            std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
             const std::string& clientPackageName,
             bool systemNativeClient,
             const std::optional<std::string>& clientFeatureId,
@@ -181,6 +182,7 @@
     CameraDeviceClient(const sp<CameraService>& cameraService,
             const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
             std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+            std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
             const std::string& clientPackageName,
             bool clientPackageOverride,
             const std::optional<std::string>& clientFeatureId,
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index dc9e0c1..93564ac 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -19,7 +19,6 @@
 //#define LOG_NDEBUG 0
 
 #include "CameraOfflineSessionClient.h"
-#include "utils/CameraThreadState.h"
 #include <utils/Trace.h>
 #include <camera/StringUtils.h>
 
@@ -163,7 +162,7 @@
         return res;
     }
     // Allow both client and the media server to disconnect at all times
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = getCallingPid();
     if (callingPid != mClientPid &&
             callingPid != mServicePid) {
         return res;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 804498f..c6f3e06 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -47,6 +47,7 @@
             sp<CameraOfflineSessionBase> session,
             const KeyedVector<sp<IBinder>, sp<CompositeStream>>& offlineCompositeStreamMap,
             const sp<ICameraDeviceCallbacks>& remoteCallback,
+            std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
             const std::string& clientPackageName,
             const std::optional<std::string>& clientFeatureId,
             const std::string& cameraIdStr, int cameraFacing, int sensorOrientation,
@@ -54,6 +55,7 @@
             CameraService::BasicClient(
                     cameraService,
                     IInterface::asBinder(remoteCallback),
+                    attributionAndPermissionUtils,
                     // (v)ndk doesn't have offline session support
                     clientPackageName, /*overridePackageName*/false, clientFeatureId,
                     cameraIdStr, cameraFacing, sensorOrientation, clientPid, clientUid, servicePid,
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index a126f61..34964d4 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -37,7 +37,6 @@
 #include "device3/Camera3Device.h"
 #include "device3/aidl/AidlCamera3Device.h"
 #include "device3/hidl/HidlCamera3Device.h"
-#include "utils/CameraThreadState.h"
 
 namespace android {
 
@@ -50,6 +49,7 @@
         const sp<CameraService>& cameraService,
         const sp<TCamCallbacks>& remoteCallback,
         std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& clientPackageName,
         bool systemNativeClient,
         const std::optional<std::string>& clientFeatureId,
@@ -63,9 +63,9 @@
         bool overrideForPerfClass,
         bool overrideToPortrait,
         bool legacyClient):
-        TClientBase(cameraService, remoteCallback, clientPackageName, systemNativeClient,
-                clientFeatureId, cameraId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
-                clientUid, servicePid, overrideToPortrait),
+        TClientBase(cameraService, remoteCallback, attributionAndPermissionUtils, clientPackageName,
+                systemNativeClient, clientFeatureId, cameraId, api1CameraId, cameraFacing,
+                sensorOrientation, clientPid, clientUid, servicePid, overrideToPortrait),
         mSharedCameraCallbacks(remoteCallback),
         mCameraServiceProxyWrapper(cameraServiceProxyWrapper),
         mDeviceActive(false), mApi1CameraId(api1CameraId)
@@ -82,7 +82,7 @@
 status_t Camera2ClientBase<TClientBase>::checkPid(const char* checkLocation)
         const {
 
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = TClientBase::getCallingPid();
     if (callingPid == TClientBase::mClientPid) return NO_ERROR;
 
     ALOGE("%s: attempt to use a locked camera from a different process"
@@ -115,12 +115,14 @@
         case IPCTransport::HIDL:
             mDevice =
                     new HidlCamera3Device(mCameraServiceProxyWrapper,
+                            TClientBase::mAttributionAndPermissionUtils,
                             TClientBase::mCameraIdStr, mOverrideForPerfClass,
                             TClientBase::mOverrideToPortrait, mLegacyClient);
             break;
         case IPCTransport::AIDL:
             mDevice =
                     new AidlCamera3Device(mCameraServiceProxyWrapper,
+                            TClientBase::mAttributionAndPermissionUtils,
                             TClientBase::mCameraIdStr, mOverrideForPerfClass,
                             TClientBase::mOverrideToPortrait, mLegacyClient);
              break;
@@ -266,7 +268,7 @@
     ALOGD("Camera %s: serializationLock acquired", TClientBase::mCameraIdStr.c_str());
     binder::Status res = binder::Status::ok();
     // Allow both client and the media server to disconnect at all times
-    int callingPid = CameraThreadState::getCallingPid();
+    int callingPid = TClientBase::getCallingPid();
     if (callingPid != TClientBase::mClientPid &&
         callingPid != TClientBase::mServicePid) return res;
 
@@ -305,18 +307,18 @@
     Mutex::Autolock icl(mBinderSerializationLock);
 
     if (TClientBase::mClientPid != 0 &&
-        CameraThreadState::getCallingPid() != TClientBase::mClientPid) {
+        TClientBase::getCallingPid() != TClientBase::mClientPid) {
 
         ALOGE("%s: Camera %s: Connection attempt from pid %d; "
                 "current locked to pid %d",
                 __FUNCTION__,
                 TClientBase::mCameraIdStr.c_str(),
-                CameraThreadState::getCallingPid(),
+                TClientBase::getCallingPid(),
                 TClientBase::mClientPid);
         return BAD_VALUE;
     }
 
-    TClientBase::mClientPid = CameraThreadState::getCallingPid();
+    TClientBase::mClientPid = TClientBase::getCallingPid();
 
     TClientBase::mRemoteCallback = client;
     mSharedCameraCallbacks = client;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 2bb90d9..b8a6d8b 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -21,6 +21,7 @@
 #include "camera/CameraMetadata.h"
 #include "camera/CaptureResult.h"
 #include "utils/CameraServiceProxyWrapper.h"
+#include "utils/AttributionAndPermissionUtils.h"
 #include "CameraServiceWatchdog.h"
 
 namespace android {
@@ -51,6 +52,7 @@
     Camera2ClientBase(const sp<CameraService>& cameraService,
                       const sp<TCamCallbacks>& remoteCallback,
                       std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+                      std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
                       const std::string& clientPackageName,
                       bool systemNativeClient,
                       const std::optional<std::string>& clientFeatureId,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9792089..ecebad4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -45,6 +45,7 @@
 #include <utility>
 
 #include <android-base/stringprintf.h>
+#include <sched.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <utils/Timers.h>
@@ -64,7 +65,6 @@
 #include "device3/Camera3InputStream.h"
 #include "device3/Camera3OutputStream.h"
 #include "device3/Camera3SharedOutputStream.h"
-#include "utils/CameraThreadState.h"
 #include "utils/CameraTraces.h"
 #include "utils/SchedulingPolicyUtils.h"
 #include "utils/SessionConfigurationUtils.h"
@@ -84,8 +84,10 @@
 namespace android {
 
 Camera3Device::Camera3Device(std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string &id, bool overrideForPerfClass, bool overrideToPortrait,
         bool legacyClient):
+        AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils),
         mCameraServiceProxyWrapper(cameraServiceProxyWrapper),
         mId(id),
         mLegacyClient(legacyClient),
@@ -1432,7 +1434,7 @@
 
     if (templateId <= 0 || templateId >= CAMERA_TEMPLATE_COUNT) {
         android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26866110",
-                CameraThreadState::getCallingUid(), nullptr, 0);
+                getCallingUid(), nullptr, 0);
         return BAD_VALUE;
     }
 
@@ -2387,6 +2389,42 @@
     return ret;
 }
 
+Camera3Device::RunThreadWithRealtimePriority::RunThreadWithRealtimePriority(int tid) : mTid(tid),
+        mPreviousPolicy(sched_getscheduler(tid)) {
+    if (flags::surface_ipc()) {
+        auto res = sched_getparam(mTid, &mPreviousParams);
+        if (res != OK) {
+            ALOGE("Can't retrieve thread scheduler parameters: %s (%d)",
+                    strerror(-res), res);
+            return;
+        }
+
+        struct sched_param param = {0};
+        param.sched_priority = kRequestThreadPriority;
+
+        res = sched_setscheduler(mTid, SCHED_FIFO, &param);
+        if (res != OK) {
+            ALOGW("Can't set realtime priority for thread: %s (%d)",
+                    strerror(-res), res);
+        } else {
+            ALOGD("Set real time priority for thread (tid %d)", mTid);
+            mPolicyBumped = true;
+        }
+    }
+}
+
+Camera3Device::RunThreadWithRealtimePriority::~RunThreadWithRealtimePriority() {
+    if (mPolicyBumped && flags::surface_ipc()) {
+        auto res = sched_setscheduler(mTid, mPreviousPolicy, &mPreviousParams);
+        if (res != OK) {
+            ALOGE("Can't set regular priority for thread: %s (%d)",
+                    strerror(-res), res);
+        } else {
+            ALOGD("Set regular priority for thread (tid %d)", mTid);
+        }
+    }
+}
+
 status_t Camera3Device::configureStreamsLocked(int operatingMode,
         const CameraMetadata& sessionParams, bool notifyRequestThread) {
     ATRACE_CALL();
@@ -2582,43 +2620,51 @@
         }
         mRequestThread->setHalBufferManagedStreams(mHalBufManagedStreamIds);
     }
-    // Finish all stream configuration immediately.
-    // TODO: Try to relax this later back to lazy completion, which should be
-    // faster
 
-    if (mInputStream != NULL && mInputStream->isConfiguring()) {
-        bool streamReConfigured = false;
-        res = mInputStream->finishConfiguration(&streamReConfigured);
-        if (res != OK) {
-            CLOGE("Can't finish configuring input stream %d: %s (%d)",
-                    mInputStream->getId(), strerror(-res), res);
-            cancelStreamsConfigurationLocked();
-            if ((res == NO_INIT || res == DEAD_OBJECT) && mInputStream->isAbandoned()) {
-                return DEAD_OBJECT;
-            }
-            return BAD_VALUE;
-        }
-        if (streamReConfigured) {
-            mInterface->onStreamReConfigured(mInputStream->getId());
-        }
-    }
+    {
+        // Stream/surface setup can include a lot of binder IPC. Raise the
+        // thread priority when running the binder IPC heavy configuration
+        // sequence.
+        RunThreadWithRealtimePriority priorityBump;
 
-    for (size_t i = 0; i < mOutputStreams.size(); i++) {
-        sp<Camera3OutputStreamInterface> outputStream = mOutputStreams[i];
-        if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
+        // Finish all stream configuration immediately.
+        // TODO: Try to relax this later back to lazy completion, which should be
+        // faster
+
+        if (mInputStream != NULL && mInputStream->isConfiguring()) {
             bool streamReConfigured = false;
-            res = outputStream->finishConfiguration(&streamReConfigured);
+            res = mInputStream->finishConfiguration(&streamReConfigured);
             if (res != OK) {
-                CLOGE("Can't finish configuring output stream %d: %s (%d)",
-                        outputStream->getId(), strerror(-res), res);
+                CLOGE("Can't finish configuring input stream %d: %s (%d)",
+                        mInputStream->getId(), strerror(-res), res);
                 cancelStreamsConfigurationLocked();
-                if ((res == NO_INIT || res == DEAD_OBJECT) && outputStream->isAbandoned()) {
+                if ((res == NO_INIT || res == DEAD_OBJECT) && mInputStream->isAbandoned()) {
                     return DEAD_OBJECT;
                 }
                 return BAD_VALUE;
             }
             if (streamReConfigured) {
-                mInterface->onStreamReConfigured(outputStream->getId());
+                mInterface->onStreamReConfigured(mInputStream->getId());
+            }
+        }
+
+        for (size_t i = 0; i < mOutputStreams.size(); i++) {
+            sp<Camera3OutputStreamInterface> outputStream = mOutputStreams[i];
+            if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
+                bool streamReConfigured = false;
+                res = outputStream->finishConfiguration(&streamReConfigured);
+                if (res != OK) {
+                    CLOGE("Can't finish configuring output stream %d: %s (%d)",
+                            outputStream->getId(), strerror(-res), res);
+                    cancelStreamsConfigurationLocked();
+                    if ((res == NO_INIT || res == DEAD_OBJECT) && outputStream->isAbandoned()) {
+                        return DEAD_OBJECT;
+                    }
+                    return BAD_VALUE;
+                }
+                if (streamReConfigured) {
+                    mInterface->onStreamReConfigured(outputStream->getId());
+                }
             }
         }
     }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ac4b039..5b37f6c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -47,6 +47,7 @@
 #include "device3/Camera3OutputInterface.h"
 #include "device3/Camera3OfflineSession.h"
 #include "device3/Camera3StreamInterface.h"
+#include "utils/AttributionAndPermissionUtils.h"
 #include "utils/TagMonitor.h"
 #include "utils/IPCTransport.h"
 #include "utils/LatencyHistogram.h"
@@ -79,12 +80,14 @@
             public camera3::SetErrorInterface,
             public camera3::InflightRequestUpdateInterface,
             public camera3::RequestBufferInterface,
-            public camera3::FlushBufferInterface {
+            public camera3::FlushBufferInterface,
+            public AttributionAndPermissionUtilsEncapsulator {
   friend class HidlCamera3Device;
   friend class AidlCamera3Device;
   public:
 
     explicit Camera3Device(std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
+            std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
             const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
             bool legacyClient = false);
 
@@ -1060,7 +1063,7 @@
         static const nsecs_t kRequestTimeout = 50e6; // 50 ms
 
         // TODO: does this need to be adjusted for long exposure requests?
-        static const nsecs_t kRequestSubmitTimeout = 200e6; // 200 ms
+        static const nsecs_t kRequestSubmitTimeout = 500e6; // 500 ms
 
         // Used to prepare a batch of requests.
         struct NextRequest {
@@ -1610,6 +1613,35 @@
 
     void overrideStreamUseCaseLocked();
 
+    // An instance of this class will raise the scheduling policy of a given
+    // given thread to real time and keep it this way throughout the lifetime
+    // of the object. The thread scheduling policy will revert back to its original
+    // state after the instances is released. By default the implementation will
+    // raise the priority of the current thread unless clients explicitly specify
+    // another thread id.
+    // Client must avoid:
+    //  - Keeping an instance of this class for extended and long running operations.
+    //    This is only intended for short/temporarily priority bumps that mitigate
+    //    scheduling delays within critical camera paths.
+    //  - Allocating instances of this class on the memory heap unless clients have
+    //    complete control over the object lifetime. It is preferable to allocate
+    //    instances of this class on the stack instead.
+    //  - Nesting multiple instances of this class using the same default or same thread id.
+    class RunThreadWithRealtimePriority final {
+        public:
+            RunThreadWithRealtimePriority(int tid = gettid());
+            ~RunThreadWithRealtimePriority();
+
+            RunThreadWithRealtimePriority(const RunThreadWithRealtimePriority&) = delete;
+            RunThreadWithRealtimePriority& operator=(const RunThreadWithRealtimePriority&) = delete;
+
+        private:
+            int mTid;
+            int mPreviousPolicy;
+            bool mPolicyBumped = false;
+            struct sched_param mPreviousParams;
+    };
+
 }; // class Camera3Device
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
index 75162bf..55467c3 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
@@ -68,7 +68,7 @@
     return INVALID_OPERATION;
 }
 
-void Camera3FakeStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3FakeStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
     std::string lines;
     lines += fmt::sprintf("    Stream[%d]: Fake\n", mId);
     write(fd, lines.c_str(), lines.size());
@@ -99,12 +99,12 @@
     return OK;
 }
 
-status_t Camera3FakeStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3FakeStream::getEndpointUsage(uint64_t *usage) {
     *usage = FAKE_USAGE;
     return OK;
 }
 
-bool Camera3FakeStream::isVideoStream() const {
+bool Camera3FakeStream::isVideoStream() {
     return false;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.h b/services/camera/libcameraservice/device3/Camera3FakeStream.h
index 1d82190..7addb90 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.h
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.h
@@ -50,7 +50,7 @@
      * Camera3Stream interface
      */
 
-    virtual void     dump(int fd, const Vector<String16> &args) const;
+    virtual void     dump(int fd, const Vector<String16> &args);
 
     status_t         setTransform(int transform, bool mayChangeMirror);
 
@@ -70,7 +70,7 @@
     /**
      * Return if this output stream is for video encoding.
      */
-    bool isVideoStream() const;
+    bool isVideoStream();
 
     /**
      * Return if the consumer configuration of this stream is deferred.
@@ -144,7 +144,7 @@
 
     virtual status_t configureQueueLocked();
 
-    virtual status_t getEndpointUsage(uint64_t *usage) const;
+    virtual status_t getEndpointUsage(uint64_t *usage);
 
 }; // class Camera3FakeStream
 
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 152687e..22d2716 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -77,7 +77,7 @@
     return false;
 }
 
-void Camera3IOStreamBase::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3IOStreamBase::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
     std::ostringstream lines;
 
     uint64_t consumerUsage = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 239fc71..7e73662 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -52,7 +52,7 @@
      * Camera3Stream interface
      */
 
-    virtual void     dump(int fd, const Vector<String16> &args) const;
+    virtual void     dump(int fd, const Vector<String16> &args);
 
     int              getMaxTotalBuffers() const { return mTotalBufferCount; }
   protected:
@@ -108,7 +108,7 @@
     virtual size_t   getCachedOutputBufferCountLocked() const;
     virtual size_t   getMaxCachedOutputBuffersLocked() const;
 
-    virtual status_t getEndpointUsage(uint64_t *usage) const = 0;
+    virtual status_t getEndpointUsage(uint64_t *usage) = 0;
 
     status_t getBufferPreconditionCheckLocked() const;
     status_t returnBufferPreconditionCheckLocked() const;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 54ffbd7..283322e 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -216,7 +216,7 @@
     return OK;
 }
 
-void Camera3InputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3InputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
     std::string lines;
     lines += fmt::sprintf("    Stream[%d]: Input\n", mId);
     write(fd, lines.c_str(), lines.size());
@@ -297,7 +297,7 @@
     return OK;
 }
 
-status_t Camera3InputStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3InputStream::getEndpointUsage(uint64_t *usage) {
     // Per HAL3 spec, input streams have 0 for their initial usage field.
     *usage = 0;
     return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index d4f4b15..a99c364 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -43,7 +43,7 @@
     Camera3InputStream(int id, uint32_t width, uint32_t height, int format);
     ~Camera3InputStream();
 
-    virtual void     dump(int fd, const Vector<String16> &args) const;
+    virtual void     dump(int fd, const Vector<String16> &args);
 
     // TODO: expose an interface to get the IGraphicBufferProducer
 
@@ -81,7 +81,7 @@
 
     virtual status_t configureQueueLocked();
 
-    virtual status_t getEndpointUsage(uint64_t *usage) const;
+    virtual status_t getEndpointUsage(uint64_t *usage);
 
     /**
      * BufferItemConsumer::BufferFreedListener interface
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 2ce04e8..8c6fa8f 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -27,6 +27,7 @@
 #include "aidl/android/hardware/graphics/common/Dataspace.h"
 
 #include <android-base/unique_fd.h>
+#include <com_android_internal_camera_flags.h>
 #include <cutils/properties.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/Log.h>
@@ -43,6 +44,8 @@
     (type *)((char*)(ptr) - offsetof(type, member))
 #endif
 
+namespace flags = com::android::internal::camera::flags;
+
 namespace android {
 
 namespace camera3 {
@@ -165,7 +168,6 @@
         mState = STATE_ERROR;
     }
 
-    mConsumerName = "Deferred";
     bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
     mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 }
@@ -464,10 +466,11 @@
     return res;
 }
 
-void Camera3OutputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3OutputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
     std::string lines;
     lines += fmt::sprintf("    Stream[%d]: Output\n", mId);
-    lines += fmt::sprintf("      Consumer name: %s\n", mConsumerName);
+    lines += fmt::sprintf("      Consumer name: %s\n", (mConsumer.get() != nullptr) ?
+            mConsumer->getConsumerName() : "Deferred");
     write(fd, lines.c_str(), lines.size());
 
     Camera3IOStreamBase::dump(fd, args);
@@ -560,8 +563,6 @@
         return res;
     }
 
-    mConsumerName = mConsumer->getConsumerName();
-
     res = native_window_set_usage(mConsumer.get(), mUsage);
     if (res != OK) {
         ALOGE("%s: Unable to configure usage %" PRIu64 " for stream %d",
@@ -609,7 +610,7 @@
         return res;
     }
 
-    int maxConsumerBuffers;
+    int maxConsumerBuffers = 0;
     res = static_cast<ANativeWindow*>(mConsumer.get())->query(
             mConsumer.get(),
             NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
@@ -686,8 +687,11 @@
         }
     }
 
-    res = native_window_set_buffer_count(mConsumer.get(),
-            mTotalBufferCount);
+    if (flags::surface_ipc()) {
+        res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
+    } else {
+        res = native_window_set_buffer_count(mConsumer.get(), mTotalBufferCount);
+    }
     if (res != OK) {
         ALOGE("%s: Unable to set buffer count for stream %d",
                 __FUNCTION__, mId);
@@ -989,7 +993,7 @@
     return OK;
 }
 
-status_t Camera3OutputStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3OutputStream::getEndpointUsage(uint64_t *usage) {
 
     status_t res;
 
@@ -1025,17 +1029,21 @@
 }
 
 status_t Camera3OutputStream::getEndpointUsageForSurface(uint64_t *usage,
-        const sp<Surface>& surface) const {
-    status_t res;
-    uint64_t u = 0;
+        const sp<Surface>& surface) {
+    if (mConsumerUsageCachedValue.has_value() && flags::surface_ipc()) {
+        *usage = mConsumerUsageCachedValue.value();
+        return OK;
+    }
 
-    res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(surface.get()), &u);
-    applyZSLUsageQuirk(camera_stream::format, &u);
-    *usage = u;
+    status_t res;
+
+    res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(surface.get()), usage);
+    applyZSLUsageQuirk(camera_stream::format, usage);
+    mConsumerUsageCachedValue = *usage;
     return res;
 }
 
-bool Camera3OutputStream::isVideoStream() const {
+bool Camera3OutputStream::isVideoStream() {
     uint64_t usage = 0;
     status_t res = getEndpointUsage(&usage);
     if (res != OK) {
@@ -1216,7 +1224,7 @@
     return OK;
 }
 
-bool Camera3OutputStream::isConsumedByHWComposer() const {
+bool Camera3OutputStream::isConsumedByHWComposer() {
     uint64_t usage = 0;
     status_t res = getEndpointUsage(&usage);
     if (res != OK) {
@@ -1227,7 +1235,7 @@
     return (usage & GRALLOC_USAGE_HW_COMPOSER) != 0;
 }
 
-bool Camera3OutputStream::isConsumedByHWTexture() const {
+bool Camera3OutputStream::isConsumedByHWTexture() {
     uint64_t usage = 0;
     status_t res = getEndpointUsage(&usage);
     if (res != OK) {
@@ -1238,7 +1246,7 @@
     return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
 }
 
-bool Camera3OutputStream::isConsumedByCPU() const {
+bool Camera3OutputStream::isConsumedByCPU() {
     uint64_t usage = 0;
     status_t res = getEndpointUsage(&usage);
     if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index da0ed87..8a93ed8 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -18,6 +18,7 @@
 #define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H
 
 #include <mutex>
+#include <optional>
 #include <utils/RefBase.h>
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
@@ -143,7 +144,7 @@
      * Camera3Stream interface
      */
 
-    virtual void     dump(int fd, const Vector<String16> &args) const;
+    virtual void     dump(int fd, const Vector<String16> &args);
 
     /**
      * Set the transform on the output stream; one of the
@@ -154,21 +155,21 @@
     /**
      * Return if this output stream is for video encoding.
      */
-    bool isVideoStream() const;
+    bool isVideoStream();
     /**
      * Return if this output stream is consumed by hardware composer.
      */
-    bool isConsumedByHWComposer() const;
+    bool isConsumedByHWComposer();
 
     /**
      * Return if this output stream is consumed by hardware texture.
      */
-    bool isConsumedByHWTexture() const;
+    bool isConsumedByHWTexture();
 
     /**
      * Return if this output stream is consumed by CPU.
      */
-    bool isConsumedByCPU() const;
+    bool isConsumedByCPU();
 
     /**
      * Return if the consumer configuration of this stream is deferred.
@@ -304,8 +305,7 @@
     virtual status_t disconnectLocked();
     status_t fixUpHidlJpegBlobHeader(ANativeWindowBuffer* anwBuffer, int fence);
 
-    status_t getEndpointUsageForSurface(uint64_t *usage,
-            const sp<Surface>& surface) const;
+    status_t getEndpointUsageForSurface(uint64_t *usage, const sp<Surface>& surface);
     status_t configureConsumerQueueLocked(bool allowPreviewRespace);
 
     // Consumer as the output of camera HAL
@@ -326,9 +326,6 @@
 
     bool mTraceFirstBuffer;
 
-    // Name of Surface consumer
-    std::string           mConsumerName;
-
     /**
      * GraphicBuffer manager this stream is registered to. Used to replace the buffer
      * allocation/deallocation role of BufferQueue.
@@ -366,6 +363,11 @@
      */
     uint64_t    mConsumerUsage;
 
+    /**
+     * Consumer end point usage flag retrieved from the buffer queue.
+     */
+    std::optional<uint64_t>    mConsumerUsageCachedValue;
+
     // Whether to drop valid buffers.
     bool mDropBuffers;
 
@@ -399,7 +401,7 @@
 
     virtual status_t configureQueueLocked();
 
-    virtual status_t getEndpointUsage(uint64_t *usage) const;
+    virtual status_t getEndpointUsage(uint64_t *usage);
 
     /**
      * Private methods
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 1ab8162..77edfbe 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -39,7 +39,7 @@
     /**
      * Return if this output stream is for video encoding.
      */
-    virtual bool isVideoStream() const = 0;
+    virtual bool isVideoStream() = 0;
 
     /**
      * Return if the consumer configuration of this stream is deferred.
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 22f97bf..485f3f0 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -279,7 +279,7 @@
     return res;
 }
 
-status_t Camera3SharedOutputStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3SharedOutputStream::getEndpointUsage(uint64_t *usage) {
 
     status_t res = OK;
     uint64_t u = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 90914d4..818ce17 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -137,7 +137,7 @@
 
     virtual status_t disconnectLocked();
 
-    virtual status_t getEndpointUsage(uint64_t *usage) const;
+    virtual status_t getEndpointUsage(uint64_t *usage);
 
 }; // class Camera3SharedOutputStream
 
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 79a767a..4934203 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -957,7 +957,7 @@
     }
 }
 
-void Camera3Stream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const
+void Camera3Stream::dump(int fd, [[maybe_unused]] const Vector<String16> &args)
 {
     mBufferLimitLatency.dump(fd,
             "      Latency histogram for wait on max_buffers");
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 0df09cd..ccd1044 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -423,7 +423,7 @@
     /**
      * Debug dump of the stream's state.
      */
-    virtual void     dump(int fd, const Vector<String16> &args) const;
+    virtual void     dump(int fd, const Vector<String16> &args);
 
     /**
      * Add a camera3 buffer listener. Adding the same listener twice has
@@ -562,7 +562,7 @@
 
     // Get the usage flags for the other endpoint, or return
     // INVALID_OPERATION if they cannot be obtained.
-    virtual status_t getEndpointUsage(uint64_t *usage) const = 0;
+    virtual status_t getEndpointUsage(uint64_t *usage) = 0;
 
     // Return whether the buffer is in the list of outstanding buffers.
     bool isOutstandingBuffer(const camera_stream_buffer& buffer) const;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 26fa04f..4df8193 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -479,7 +479,7 @@
     /**
      * Debug dump of the stream's state.
      */
-    virtual void     dump(int fd, const Vector<String16> &args) const = 0;
+    virtual void     dump(int fd, const Vector<String16> &args) = 0;
 
     virtual void     addBufferListener(
             wp<Camera3StreamBufferListener> listener) = 0;
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index e8ef692..7f30f5e 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -68,7 +68,6 @@
 #include "device3/aidl/AidlCamera3OutputUtils.h"
 #include "device3/aidl/AidlCamera3OfflineSession.h"
 #include "CameraService.h"
-#include "utils/CameraThreadState.h"
 #include "utils/SessionConfigurationUtils.h"
 #include "utils/TraceHFR.h"
 #include "utils/CameraServiceProxyWrapper.h"
@@ -173,10 +172,11 @@
 
 AidlCamera3Device::AidlCamera3Device(
         std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
         bool legacyClient) :
-        Camera3Device(cameraServiceProxyWrapper, id, overrideForPerfClass, overrideToPortrait,
-        legacyClient) {
+        Camera3Device(cameraServiceProxyWrapper, attributionAndPermissionUtils, id,
+                overrideForPerfClass, overrideToPortrait, legacyClient) {
     mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
 }
 
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
index f0a5f7e..ac29bbc 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -41,6 +41,7 @@
     friend class AidlCameraDeviceCallbacks;
     explicit AidlCamera3Device(
             std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
+            std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
             const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
             bool legacyClient = false);
 
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
index 350b072..f11db5d 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -33,10 +33,11 @@
 
     explicit HidlCamera3Device(
         std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
         const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
         bool legacyClient = false) :
-        Camera3Device(cameraServiceProxyWrapper, id, overrideForPerfClass, overrideToPortrait,
-                legacyClient) { }
+        Camera3Device(cameraServiceProxyWrapper, attributionAndPermissionUtils, id,
+                overrideForPerfClass, overrideToPortrait, legacyClient) { }
 
     virtual ~HidlCamera3Device() {}
 
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
new file mode 100644
index 0000000..93b440b
--- /dev/null
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AttributionAndPermissionUtils.h"
+
+#include <binder/AppOpsManager.h>
+#include <binder/PermissionController.h>
+#include <com_android_internal_camera_flags.h>
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+
+#include "CameraService.h"
+
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <binderthreadstate/CallerUtils.h>
+
+namespace android {
+
+namespace flags = com::android::internal::camera::flags;
+
+const std::string AttributionAndPermissionUtils::sDumpPermission("android.permission.DUMP");
+const std::string AttributionAndPermissionUtils::sManageCameraPermission(
+        "android.permission.MANAGE_CAMERA");
+const std::string AttributionAndPermissionUtils::sCameraPermission(
+        "android.permission.CAMERA");
+const std::string AttributionAndPermissionUtils::sSystemCameraPermission(
+        "android.permission.SYSTEM_CAMERA");
+const std::string AttributionAndPermissionUtils::sCameraHeadlessSystemUserPermission(
+        "android.permission.CAMERA_HEADLESS_SYSTEM_USER");
+const std::string AttributionAndPermissionUtils::sCameraPrivacyAllowlistPermission(
+        "android.permission.CAMERA_PRIVACY_ALLOWLIST");
+const std::string AttributionAndPermissionUtils::sCameraSendSystemEventsPermission(
+        "android.permission.CAMERA_SEND_SYSTEM_EVENTS");
+const std::string AttributionAndPermissionUtils::sCameraOpenCloseListenerPermission(
+        "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
+const std::string AttributionAndPermissionUtils::sCameraInjectExternalCameraPermission(
+        "android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
+
+int AttributionAndPermissionUtils::getCallingUid() {
+    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+        return hardware::IPCThreadState::self()->getCallingUid();
+    }
+    return IPCThreadState::self()->getCallingUid();
+}
+
+int AttributionAndPermissionUtils::getCallingPid() {
+    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+        return hardware::IPCThreadState::self()->getCallingPid();
+    }
+    return IPCThreadState::self()->getCallingPid();
+}
+
+int64_t AttributionAndPermissionUtils::clearCallingIdentity() {
+    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+        return hardware::IPCThreadState::self()->clearCallingIdentity();
+    }
+    return IPCThreadState::self()->clearCallingIdentity();
+}
+
+void AttributionAndPermissionUtils::restoreCallingIdentity(int64_t token) {
+    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+        hardware::IPCThreadState::self()->restoreCallingIdentity(token);
+    } else {
+        IPCThreadState::self()->restoreCallingIdentity(token);
+    }
+    return;
+}
+
+bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(const std::string &cameraId,
+        const AttributionSourceState &attributionSource) {
+    if (isAutomotivePrivilegedClient(attributionSource.uid)) {
+        // If cameraId is empty, then it means that this check is not used for the
+        // purpose of accessing a specific camera, hence grant permission just
+        // based on uid to the automotive privileged client.
+        if (cameraId.empty())
+            return true;
+
+        auto cameraService = mCameraService.promote();
+        if (cameraService == nullptr) {
+            ALOGE("%s: CameraService unavailable.", __FUNCTION__);
+            return false;
+        }
+
+        // If this call is used for accessing a specific camera then cam_id must be provided.
+        // In that case, only pre-grants the permission for accessing the exterior system only
+        // camera.
+        return cameraService->isAutomotiveExteriorSystemCamera(cameraId);
+    }
+
+    return false;
+}
+
+bool AttributionAndPermissionUtils::checkPermissionForPreflight(const std::string &cameraId,
+        const std::string &permission, const AttributionSourceState &attributionSource,
+        const std::string& message, int32_t attributedOpCode) {
+    if (checkAutomotivePrivilegedClient(cameraId, attributionSource)) {
+        return true;
+    }
+
+    if (!flags::cache_permission_services()) {
+        PermissionChecker permissionChecker;
+        return permissionChecker.checkPermissionForPreflight(
+                       toString16(permission), attributionSource, toString16(message),
+                       attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
+    } else {
+        return mPermissionChecker->checkPermissionForPreflight(
+                       toString16(permission), attributionSource, toString16(message),
+                       attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
+    }
+}
+
+// Can camera service trust the caller based on the calling UID?
+bool AttributionAndPermissionUtils::isTrustedCallingUid(uid_t uid) {
+    switch (uid) {
+        case AID_MEDIA:        // mediaserver
+        case AID_CAMERASERVER: // cameraserver
+        case AID_RADIO:        // telephony
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool AttributionAndPermissionUtils::isAutomotiveDevice() {
+    // Checks the property ro.hardware.type and returns true if it is
+    // automotive.
+    char value[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", value, "");
+    return strncmp(value, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
+bool AttributionAndPermissionUtils::isHeadlessSystemUserMode() {
+    // Checks if the device is running in headless system user mode
+    // by checking the property ro.fw.mu.headless_system_user.
+    char value[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.fw.mu.headless_system_user", value, "");
+    return strncmp(value, "true", PROPERTY_VALUE_MAX) == 0;
+}
+
+bool AttributionAndPermissionUtils::isAutomotivePrivilegedClient(int32_t uid) {
+    // Returns false if this is not an automotive device type.
+    if (!isAutomotiveDevice())
+        return false;
+
+    // Returns true if the uid is AID_AUTOMOTIVE_EVS which is a
+    // privileged client uid used for safety critical use cases such as
+    // rear view and surround view.
+    return uid == AID_AUTOMOTIVE_EVS;
+}
+
+status_t AttributionAndPermissionUtils::getUidForPackage(const std::string &packageName,
+        int userId, /*inout*/uid_t& uid, int err) {
+    PermissionController pc;
+    uid = pc.getPackageUid(toString16(packageName), 0);
+    if (uid <= 0) {
+        ALOGE("Unknown package: '%s'", packageName.c_str());
+        dprintf(err, "Unknown package: '%s'\n", packageName.c_str());
+        return BAD_VALUE;
+    }
+
+    if (userId < 0) {
+        ALOGE("Invalid user: %d", userId);
+        dprintf(err, "Invalid user: %d\n", userId);
+        return BAD_VALUE;
+    }
+
+    uid = multiuser_get_uid(userId, uid);
+    return NO_ERROR;
+}
+
+bool AttributionAndPermissionUtils::isCallerCameraServerNotDelegating() {
+    return (getCallingPid() == getpid());
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForCamera(const std::string& cameraId,
+        const AttributionSourceState& attributionSource) {
+    return checkPermissionForPreflight(cameraId, sCameraPermission,
+            attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(const std::string& cameraId,
+        const AttributionSourceState& attributionSource, bool checkCameraPermissions) {
+    bool systemCameraPermission = checkPermissionForPreflight(cameraId,
+            sSystemCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
+    return systemCameraPermission && (!checkCameraPermissions
+            || hasPermissionsForCamera(cameraId, attributionSource));
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForCameraHeadlessSystemUser(
+        const std::string& cameraId, const AttributionSourceState& attributionSource) {
+    return checkPermissionForPreflight(cameraId, sCameraHeadlessSystemUserPermission,
+            attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForCameraPrivacyAllowlist(
+        const AttributionSourceState& attributionSource) {
+    return checkPermissionForPreflight(std::string(), sCameraPrivacyAllowlistPermission,
+            attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForOpenCloseListener(
+        const AttributionSourceState& attributionSource) {
+    return checkPermissionForPreflight(std::string(), sCameraOpenCloseListenerPermission,
+            attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
new file mode 100644
index 0000000..db6457f
--- /dev/null
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
+#define ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
+
+#include <android/content/AttributionSourceState.h>
+#include <android/permission/PermissionChecker.h>
+#include <binder/BinderService.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+class CameraService;
+
+using content::AttributionSourceState;
+using permission::PermissionChecker;
+
+/**
+ * Utility class consolidating methods/data for verifying permissions and the identity of the
+ * caller.
+ */
+class AttributionAndPermissionUtils {
+  public:
+    AttributionAndPermissionUtils() { }
+    virtual ~AttributionAndPermissionUtils() {}
+
+    void setCameraService(wp<CameraService> cameraService) {
+        mCameraService = cameraService;
+    }
+
+    // Utilities handling Binder calling identities (previously in CameraThreadState)
+    virtual int getCallingUid();
+    virtual int getCallingPid();
+    virtual int64_t clearCallingIdentity();
+    virtual void restoreCallingIdentity(int64_t token);
+
+    /**
+     * Pre-grants the permission if the attribution source uid is for an automotive
+     * privileged client. Otherwise uses system service permission checker to check
+     * for the appropriate permission. If this function is called for accessing a specific
+     * camera,then the cameraID must not be empty. CameraId is used only in case of automotive
+     * privileged client so that permission is pre-granted only to access system camera device
+     * which is located outside of the vehicle body frame because camera located inside the vehicle
+     * cabin would need user permission.
+     */
+    virtual bool checkPermissionForPreflight(const std::string &cameraId,
+            const std::string &permission, const AttributionSourceState& attributionSource,
+            const std::string& message, int32_t attributedOpCode);
+
+    // Can camera service trust the caller based on the calling UID?
+    virtual bool isTrustedCallingUid(uid_t uid);
+
+    virtual bool isAutomotiveDevice();
+    virtual bool isHeadlessSystemUserMode();
+
+    /**
+     * Returns true if the client has uid AID_AUTOMOTIVE_EVS and the device is an automotive device.
+     */
+    virtual bool isAutomotivePrivilegedClient(int32_t uid);
+
+    virtual status_t getUidForPackage(const std::string &packageName, int userId,
+            /*inout*/uid_t& uid, int err);
+    virtual bool isCallerCameraServerNotDelegating();
+
+    // Utils for checking specific permissions
+    virtual bool hasPermissionsForCamera(const std::string& cameraId,
+            const AttributionSourceState& attributionSource);
+    virtual bool hasPermissionsForSystemCamera(const std::string& cameraId,
+            const AttributionSourceState& attributionSource, bool checkCameraPermissions = true);
+    virtual bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId,
+            const AttributionSourceState& attributionSource);
+    virtual bool hasPermissionsForCameraPrivacyAllowlist(
+            const AttributionSourceState& attributionSource);
+    virtual bool hasPermissionsForOpenCloseListener(
+            const AttributionSourceState& attributionSource);
+
+    static const std::string sDumpPermission;
+    static const std::string sManageCameraPermission;
+    static const std::string sCameraPermission;
+    static const std::string sSystemCameraPermission;
+    static const std::string sCameraHeadlessSystemUserPermission;
+    static const std::string sCameraPrivacyAllowlistPermission;
+    static const std::string sCameraSendSystemEventsPermission;
+    static const std::string sCameraOpenCloseListenerPermission;
+    static const std::string sCameraInjectExternalCameraPermission;
+
+  protected:
+    wp<CameraService> mCameraService;
+
+    bool checkAutomotivePrivilegedClient(const std::string &cameraId,
+            const AttributionSourceState &attributionSource);
+
+  private:
+    std::unique_ptr<permission::PermissionChecker> mPermissionChecker =
+            std::make_unique<permission::PermissionChecker>();
+};
+
+/**
+ * Class to be inherited by classes encapsulating AttributionAndPermissionUtils. Provides an
+ * additional utility layer above AttributionAndPermissionUtils calls, and avoids verbosity
+ * in the encapsulating class's methods.
+ */
+class AttributionAndPermissionUtilsEncapsulator {
+protected:
+    std::shared_ptr<AttributionAndPermissionUtils> mAttributionAndPermissionUtils;
+
+public:
+    AttributionAndPermissionUtilsEncapsulator(
+        std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
+            : mAttributionAndPermissionUtils(attributionAndPermissionUtils) { }
+
+    static AttributionSourceState buildAttributionSource(int callingPid, int callingUid) {
+        AttributionSourceState attributionSource{};
+        attributionSource.pid = callingPid;
+        attributionSource.uid = callingUid;
+        return attributionSource;
+    }
+
+    static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
+            const std::string& packageName) {
+        AttributionSourceState attributionSource = buildAttributionSource(callingPid, callingUid);
+        attributionSource.packageName = packageName;
+        return attributionSource;
+    }
+
+    int getCallingUid() const {
+        return mAttributionAndPermissionUtils->getCallingUid();
+    }
+
+    int getCallingPid() const {
+        return mAttributionAndPermissionUtils->getCallingPid();
+    }
+
+    int64_t clearCallingIdentity() const {
+        return mAttributionAndPermissionUtils->clearCallingIdentity();
+    }
+
+    void restoreCallingIdentity(int64_t token) const {
+        mAttributionAndPermissionUtils->restoreCallingIdentity(token);
+    }
+
+    // The word 'System' here does not refer to callers only on the system
+    // partition. They just need to have an android system uid.
+    bool callerHasSystemUid() const {
+        return (getCallingUid() < AID_APP_START);
+    }
+
+    bool hasPermissionsForCamera(int callingPid, int callingUid) const {
+        return hasPermissionsForCamera(std::string(), callingPid, callingUid);
+    }
+
+    bool hasPermissionsForCamera(int callingPid, int callingUid,
+            const std::string& packageName) const {
+        return hasPermissionsForCamera(std::string(), callingPid, callingUid, packageName);
+    }
+
+    bool hasPermissionsForCamera(const std::string& cameraId, int callingPid,
+            int callingUid) const {
+        auto attributionSource = buildAttributionSource(callingPid, callingUid);
+        return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
+    }
+
+    bool hasPermissionsForCamera(const std::string& cameraId, int callingPid, int callingUid,
+            const std::string& packageName) const {
+        auto attributionSource = buildAttributionSource(callingPid, callingUid, packageName);
+        return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
+    }
+
+    bool hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid, int callingUid,
+            bool checkCameraPermissions = true) const  {
+        auto attributionSource = buildAttributionSource(callingPid, callingUid);
+        return mAttributionAndPermissionUtils->hasPermissionsForSystemCamera(
+                    cameraId, attributionSource, checkCameraPermissions);
+    }
+
+    bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId, int callingPid,
+            int callingUid) const {
+        auto attributionSource = buildAttributionSource(callingPid, callingUid);
+        return mAttributionAndPermissionUtils->hasPermissionsForCameraHeadlessSystemUser(
+                    cameraId, attributionSource);
+    }
+
+    bool hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const {
+        auto attributionSource = buildAttributionSource(callingPid, callingUid);
+        return mAttributionAndPermissionUtils->hasPermissionsForCameraPrivacyAllowlist(
+                attributionSource);
+    }
+
+    bool hasPermissionsForOpenCloseListener(int callingPid, int callingUid) const {
+        auto attributionSource = buildAttributionSource(callingPid, callingUid);
+        return mAttributionAndPermissionUtils->hasPermissionsForOpenCloseListener(
+                attributionSource);
+    }
+
+    bool isAutomotiveDevice() const {
+        return mAttributionAndPermissionUtils->isAutomotiveDevice();
+    }
+
+    bool isAutomotivePrivilegedClient(int32_t uid) const {
+        return mAttributionAndPermissionUtils->isAutomotivePrivilegedClient(uid);
+    }
+
+    bool isTrustedCallingUid(uid_t uid) const {
+        return mAttributionAndPermissionUtils->isTrustedCallingUid(uid);
+    }
+
+    bool isHeadlessSystemUserMode() const {
+        return mAttributionAndPermissionUtils->isHeadlessSystemUserMode();
+    }
+
+    status_t getUidForPackage(const std::string &packageName, int userId,
+            /*inout*/uid_t& uid, int err) const {
+        return mAttributionAndPermissionUtils->getUidForPackage(packageName, userId, uid, err);
+    }
+
+    bool isCallerCameraServerNotDelegating() const {
+        return mAttributionAndPermissionUtils->isCallerCameraServerNotDelegating();
+    }
+};
+
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.cpp b/services/camera/libcameraservice/utils/CameraThreadState.cpp
deleted file mode 100644
index 2352b80..0000000
--- a/services/camera/libcameraservice/utils/CameraThreadState.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "CameraThreadState.h"
-#include <binder/IPCThreadState.h>
-#include <hwbinder/IPCThreadState.h>
-#include <binderthreadstate/CallerUtils.h>
-#include <unistd.h>
-
-namespace android {
-
-int CameraThreadState::getCallingUid() {
-    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
-        return hardware::IPCThreadState::self()->getCallingUid();
-    }
-    return IPCThreadState::self()->getCallingUid();
-}
-
-int CameraThreadState::getCallingPid() {
-    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
-        return hardware::IPCThreadState::self()->getCallingPid();
-    }
-    return IPCThreadState::self()->getCallingPid();
-}
-
-int64_t CameraThreadState::clearCallingIdentity() {
-    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
-        return hardware::IPCThreadState::self()->clearCallingIdentity();
-    }
-    return IPCThreadState::self()->clearCallingIdentity();
-}
-
-void CameraThreadState::restoreCallingIdentity(int64_t token) {
-    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
-        hardware::IPCThreadState::self()->restoreCallingIdentity(token);
-    } else {
-        IPCThreadState::self()->restoreCallingIdentity(token);
-    }
-    return;
-}
-
-} // android
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.h b/services/camera/libcameraservice/utils/CameraThreadState.h
deleted file mode 100644
index e1a70de..0000000
--- a/services/camera/libcameraservice/utils/CameraThreadState.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-namespace android {
-class CameraThreadState {
-public:
-  static int64_t clearCallingIdentity();
-
-  static void restoreCallingIdentity(int64_t token);
-
-  static int getCallingUid();
-
-  static int getCallingPid();
-};
-
-} // android
diff --git a/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp b/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp
index 92a1030..f3afc69 100644
--- a/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp
+++ b/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp
@@ -20,7 +20,6 @@
 #include <pthread.h>
 #include <sched.h>
 
-#include "CameraThreadState.h"
 #include <private/android_filesystem_config.h>
 #include <processgroup/processgroup.h>
 #include <processgroup/sched_policy.h>
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 11ef9b7..23aed6e 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -432,7 +432,7 @@
         const std::string &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
         const std::vector<int32_t> &sensorPixelModesUsed, int64_t dynamicRangeProfile,
         int64_t streamUseCase, int timestampBase, int mirrorMode,
-        int32_t colorSpace) {
+        int32_t colorSpace, bool respectSurfaceSize) {
     // bufferProducer must be non-null
     if (gbp == nullptr) {
         std::string msg = fmt::sprintf("Camera %s: Surface is NULL", logicalCameraId.c_str());
@@ -529,8 +529,10 @@
         // we can use the default stream configuration map
         foundInMaxRes = true;
     }
-    // Round dimensions to the nearest dimensions available for this format
-    if (flexibleConsumer && isPublicFormat(format) &&
+    // Round dimensions to the nearest dimensions available for this format.
+    // Only do the rounding if the client doesn't ask to respect the surface
+    // size.
+    if (flexibleConsumer && isPublicFormat(format) && !respectSurfaceSize &&
             !SessionConfigurationUtils::roundBufferDimensionNearest(width, height,
             format, dataSpace, physicalCameraMetadata, foundInMaxRes, /*out*/&width,
             /*out*/&height)) {
@@ -753,6 +755,7 @@
         const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
             it.getGraphicBufferProducers();
         bool deferredConsumer = it.isDeferred();
+        bool isConfigurationComplete = it.isComplete();
         const std::string &physicalCameraId = it.getPhysicalCameraId();
 
         int64_t dynamicRangeProfile = it.getDynamicRangeProfile();
@@ -768,7 +771,8 @@
         int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
         OutputStreamInfo streamInfo;
 
-        res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType());
+        res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType(),
+                               isConfigurationComplete);
         if (!res.isOk()) {
             return res;
         }
@@ -781,15 +785,38 @@
         int64_t streamUseCase = it.getStreamUseCase();
         int timestampBase = it.getTimestampBase();
         int mirrorMode = it.getMirrorMode();
-        if (deferredConsumer) {
+        // If the configuration is a deferred consumer, or a not yet completed
+        // configuration with no buffer producers attached.
+        if (deferredConsumer || (!isConfigurationComplete && numBufferProducers == 0)) {
             streamInfo.width = it.getWidth();
             streamInfo.height = it.getHeight();
-            streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-            streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
             auto surfaceType = it.getSurfaceType();
-            streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
-            if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
-                streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
+            switch (surfaceType) {
+                case OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE:
+                    streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
+                    streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+                    streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+                    break;
+                case OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW:
+                    streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE
+                            | GraphicBuffer::USAGE_HW_COMPOSER;
+                    streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+                    streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+                    break;
+                case OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER:
+                case OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC:
+                    streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_VIDEO_ENCODER;
+                    streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+                    streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+                    break;
+                case OutputConfiguration::SURFACE_TYPE_IMAGE_READER:
+                    streamInfo.consumerUsage = it.getUsage();
+                    streamInfo.format = it.getFormat();
+                    streamInfo.dataSpace = (android_dataspace)it.getDataspace();
+                    break;
+                default:
+                    return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                                        "Invalid surface type.");
             }
             streamInfo.dynamicRangeProfile = it.getDynamicRangeProfile();
             if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed,
@@ -815,7 +842,8 @@
             sp<Surface> surface;
             res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
                     logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
-                    streamUseCase, timestampBase, mirrorMode, colorSpace);
+                    streamUseCase, timestampBase, mirrorMode, colorSpace,
+                    /*respectSurfaceSize*/true);
 
             if (!res.isOk())
                 return res;
@@ -912,22 +940,37 @@
 }
 
 binder::Status checkSurfaceType(size_t numBufferProducers,
-        bool deferredConsumer, int surfaceType)  {
+        bool deferredConsumer, int surfaceType, bool isConfigurationComplete)  {
     if (numBufferProducers > MAX_SURFACES_PER_STREAM) {
         ALOGE("%s: GraphicBufferProducer count %zu for stream exceeds limit of %d",
                 __FUNCTION__, numBufferProducers, MAX_SURFACES_PER_STREAM);
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Surface count is too high");
-    } else if ((numBufferProducers == 0) && (!deferredConsumer)) {
+    } else if ((numBufferProducers == 0) && (!deferredConsumer) && isConfigurationComplete) {
         ALOGE("%s: Number of consumers cannot be smaller than 1", __FUNCTION__);
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "No valid consumers.");
     }
 
-    bool validSurfaceType = ((surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
-            (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
-
-    if (deferredConsumer && !validSurfaceType) {
-        ALOGE("%s: Target surface has invalid surfaceType = %d.", __FUNCTION__, surfaceType);
-        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
+    if (deferredConsumer) {
+        bool validSurfaceType = (
+                (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
+                (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
+        if (!validSurfaceType) {
+            std::string msg = fmt::sprintf("Deferred target surface has invalid "
+                    "surfaceType = %d.", surfaceType);
+            ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+        }
+    } else if (!isConfigurationComplete && numBufferProducers == 0) {
+        bool validSurfaceType = (
+                (surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER) ||
+                (surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC) ||
+                (surfaceType == OutputConfiguration::SURFACE_TYPE_IMAGE_READER));
+        if (!validSurfaceType) {
+            std::string msg = fmt::sprintf("OutputConfiguration target surface has invalid "
+                    "surfaceType = %d.", surfaceType);
+            ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+        }
     }
 
     return binder::Status::ok();
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 0545cea..a226829 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -112,7 +112,7 @@
         const std::string &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
         const std::vector<int32_t> &sensorPixelModesUsed,  int64_t dynamicRangeProfile,
         int64_t streamUseCase, int timestampBase, int mirrorMode,
-        int32_t colorSpace);
+        int32_t colorSpace, bool respectSurfaceSize);
 
 //check if format is 10-bit output compatible
 bool is10bitCompatibleFormat(int32_t format, android_dataspace_t dataSpace);
@@ -143,10 +143,10 @@
 const std::string &logicalCameraId);
 
 binder::Status checkSurfaceType(size_t numBufferProducers,
-bool deferredConsumer, int surfaceType);
+        bool deferredConsumer, int surfaceType, bool isConfigurationComplete);
 
 binder::Status checkOperatingMode(int operatingMode,
-const CameraMetadata &staticInfo, const std::string &cameraId);
+        const CameraMetadata &staticInfo, const std::string &cameraId);
 
 binder::Status
 convertToHALStreamCombination(
diff --git a/services/camera/virtualcamera/TEST_MAPPING b/services/camera/virtualcamera/TEST_MAPPING
index 25fca73..e976704 100644
--- a/services/camera/virtualcamera/TEST_MAPPING
+++ b/services/camera/virtualcamera/TEST_MAPPING
@@ -9,7 +9,8 @@
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
-      ]
+      ],
+      "keywords": ["primary-device"]
     }
   ]
 }
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc
index 7636cbd..a5301e5 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.cc
+++ b/services/camera/virtualcamera/VirtualCameraDevice.cc
@@ -124,9 +124,9 @@
          kOutputFormats.end();
 }
 
-std::vector<MetadataBuilder::FpsRange> fpsRangesForInputConfig(
+std::vector<FpsRange> fpsRangesForInputConfig(
     const std::vector<SupportedStreamConfiguration>& configs) {
-  std::set<MetadataBuilder::FpsRange> availableRanges;
+  std::set<FpsRange> availableRanges;
 
   for (const SupportedStreamConfiguration& config : configs) {
     availableRanges.insert({.minFps = kMinFps, .maxFps = config.maxFps});
@@ -141,8 +141,7 @@
     availableRanges.insert({.minFps = 30, .maxFps = 30});
   }
 
-  return std::vector<MetadataBuilder::FpsRange>(availableRanges.begin(),
-                                                availableRanges.end());
+  return std::vector<FpsRange>(availableRanges.begin(), availableRanges.end());
 }
 
 std::optional<Resolution> getMaxResolution(
@@ -297,18 +296,47 @@
                                     ANDROID_CONTROL_ZOOM_RATIO,
                                     ANDROID_FLASH_MODE,
                                     ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+                                    ANDROID_JPEG_ORIENTATION,
                                     ANDROID_JPEG_QUALITY,
                                     ANDROID_JPEG_THUMBNAIL_QUALITY,
+                                    ANDROID_JPEG_THUMBNAIL_SIZE,
                                     ANDROID_NOISE_REDUCTION_MODE,
                                     ANDROID_STATISTICS_FACE_DETECT_MODE})
-          .setAvailableResultKeys(
-              {ANDROID_COLOR_CORRECTION_ABERRATION_MODE, ANDROID_CONTROL_AE_MODE,
-               ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, ANDROID_CONTROL_AF_MODE,
-               ANDROID_CONTROL_AWB_MODE, ANDROID_CONTROL_EFFECT_MODE,
-               ANDROID_CONTROL_MODE, ANDROID_FLASH_MODE, ANDROID_FLASH_STATE,
-               ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, ANDROID_JPEG_QUALITY,
-               ANDROID_JPEG_THUMBNAIL_QUALITY, ANDROID_LENS_FOCAL_LENGTH,
-               ANDROID_SENSOR_TIMESTAMP, ANDROID_NOISE_REDUCTION_MODE})
+          .setAvailableResultKeys({
+              ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+              ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+              ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+              ANDROID_CONTROL_AE_LOCK,
+              ANDROID_CONTROL_AE_MODE,
+              ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+              ANDROID_CONTROL_AE_STATE,
+              ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+              ANDROID_CONTROL_AF_MODE,
+              ANDROID_CONTROL_AF_STATE,
+              ANDROID_CONTROL_AF_TRIGGER,
+              ANDROID_CONTROL_AWB_LOCK,
+              ANDROID_CONTROL_AWB_MODE,
+              ANDROID_CONTROL_AWB_STATE,
+              ANDROID_CONTROL_CAPTURE_INTENT,
+              ANDROID_CONTROL_EFFECT_MODE,
+              ANDROID_CONTROL_MODE,
+              ANDROID_CONTROL_SCENE_MODE,
+              ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+              ANDROID_STATISTICS_FACE_DETECT_MODE,
+              ANDROID_FLASH_MODE,
+              ANDROID_FLASH_STATE,
+              ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+              ANDROID_JPEG_QUALITY,
+              ANDROID_JPEG_THUMBNAIL_QUALITY,
+              ANDROID_LENS_FOCAL_LENGTH,
+              ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+              ANDROID_NOISE_REDUCTION_MODE,
+              ANDROID_REQUEST_PIPELINE_DEPTH,
+              ANDROID_SENSOR_TIMESTAMP,
+              ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
+              ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+              ANDROID_STATISTICS_SCENE_FLICKER,
+          })
           .setAvailableCapabilities(
               {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE});
 
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.h b/services/camera/virtualcamera/VirtualCameraDevice.h
index c274dc9..0aebf6e 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.h
+++ b/services/camera/virtualcamera/VirtualCameraDevice.h
@@ -24,6 +24,7 @@
 #include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
 #include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
 #include "aidl/android/hardware/camera/device/BnCameraDevice.h"
+#include "system/camera_metadata.h"
 #include "util/Util.h"
 
 namespace android {
@@ -121,6 +122,15 @@
   // Default JPEG compression quality.
   static constexpr uint8_t kDefaultJpegQuality = 80;
 
+  // Default JPEG orientation.
+  static constexpr uint8_t kDefaultJpegOrientation = 0;
+
+  // Default Make and Model for Exif
+  static constexpr char kDefaultMakeAndModel[] = "Android Virtual Camera";
+
+  static constexpr camera_metadata_enum_android_control_capture_intent_t
+      kDefaultCaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+
  private:
   std::shared_ptr<VirtualCameraDevice> sharedFromThis();
 
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.cc b/services/camera/virtualcamera/VirtualCameraProvider.cc
index e4a68f5..eed3e85 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.cc
+++ b/services/camera/virtualcamera/VirtualCameraProvider.cc
@@ -42,10 +42,6 @@
 using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
 using ::aidl::android::hardware::camera::provider::ICameraProviderCallback;
 
-// TODO(b/301023410) Make camera id range configurable / dynamic
-// based on already registered devices.
-std::atomic_int VirtualCameraProvider::sNextId{42};
-
 ndk::ScopedAStatus VirtualCameraProvider::setCallback(
     const std::shared_ptr<ICameraProviderCallback>& in_callback) {
   ALOGV("%s", __func__);
@@ -154,9 +150,15 @@
 }
 
 std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::createCamera(
-    const VirtualCameraConfiguration& configuration) {
+    const VirtualCameraConfiguration& configuration, const int cameraId) {
+  if (cameraId < 0) {
+    ALOGE("%s: Cannot create camera with negative id. cameraId: %d", __func__,
+          cameraId);
+    return nullptr;
+  }
+
   auto camera =
-      ndk::SharedRefBase::make<VirtualCameraDevice>(sNextId++, configuration);
+      ndk::SharedRefBase::make<VirtualCameraDevice>(cameraId, configuration);
   std::shared_ptr<ICameraProviderCallback> callback;
   {
     const std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.h b/services/camera/virtualcamera/VirtualCameraProvider.h
index 11d3123..c1283a0 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.h
+++ b/services/camera/virtualcamera/VirtualCameraProvider.h
@@ -76,7 +76,8 @@
   // Returns nullptr if creation was not successful.
   std::shared_ptr<VirtualCameraDevice> createCamera(
       const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
-          configuration);
+          configuration,
+      int cameraId);
 
   std::shared_ptr<VirtualCameraDevice> getCamera(const std::string& name);
 
@@ -91,9 +92,6 @@
 
   std::map<std::string, std::shared_ptr<VirtualCameraDevice>> mCameras
       GUARDED_BY(mLock);
-
-  // Numerical id to assign to next created camera.
-  static std::atomic_int sNextId;
 };
 
 }  // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 9b0fc07..25cc270 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "system/camera_metadata.h"
 #define LOG_TAG "VirtualCameraRenderThread"
 #include "VirtualCameraRenderThread.h"
 
@@ -45,7 +44,9 @@
 #include "android-base/thread_annotations.h"
 #include "android/binder_auto_utils.h"
 #include "android/hardware_buffer.h"
+#include "system/camera_metadata.h"
 #include "ui/GraphicBuffer.h"
+#include "ui/Rect.h"
 #include "util/EglFramebuffer.h"
 #include "util/JpegUtil.h"
 #include "util/MetadataUtil.h"
@@ -92,30 +93,68 @@
     const std::chrono::nanoseconds timestamp,
     const RequestSettings& requestSettings,
     const Resolution reportedSensorSize) {
-  std::unique_ptr<CameraMetadata> metadata =
+  // All of the keys used in the response needs to be referenced in
+  // availableResultKeys in CameraCharacteristics (see initCameraCharacteristics
+  // in VirtualCameraDevice.cc).
+  MetadataBuilder builder =
       MetadataBuilder()
           .setAberrationCorrectionMode(
               ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF)
+          .setControlAeAvailableAntibandingModes(
+              {ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF})
+          .setControlAeAntibandingMode(ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF)
+          .setControlAeExposureCompensation(0)
+          .setControlAeLockAvailable(false)
+          .setControlAeLock(ANDROID_CONTROL_AE_LOCK_OFF)
           .setControlAeMode(ANDROID_CONTROL_AE_MODE_ON)
           .setControlAePrecaptureTrigger(
               ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
+          .setControlAeState(ANDROID_CONTROL_AE_STATE_INACTIVE)
           .setControlAfMode(ANDROID_CONTROL_AF_MODE_OFF)
+          .setControlAfTrigger(ANDROID_CONTROL_AF_TRIGGER_IDLE)
+          .setControlAfState(ANDROID_CONTROL_AF_STATE_INACTIVE)
           .setControlAwbMode(ANDROID_CONTROL_AWB_MODE_AUTO)
+          .setControlAwbLock(ANDROID_CONTROL_AWB_LOCK_OFF)
+          .setControlAwbState(ANDROID_CONTROL_AWB_STATE_INACTIVE)
+          .setControlCaptureIntent(requestSettings.captureIntent)
           .setControlEffectMode(ANDROID_CONTROL_EFFECT_MODE_OFF)
           .setControlMode(ANDROID_CONTROL_MODE_AUTO)
+          .setControlSceneMode(ANDROID_CONTROL_SCENE_MODE_DISABLED)
+          .setControlVideoStabilizationMode(
+              ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF)
           .setCropRegion(0, 0, reportedSensorSize.width,
                          reportedSensorSize.height)
           .setFaceDetectMode(ANDROID_STATISTICS_FACE_DETECT_MODE_OFF)
           .setFlashState(ANDROID_FLASH_STATE_UNAVAILABLE)
+          .setFlashMode(ANDROID_FLASH_MODE_OFF)
           .setFocalLength(VirtualCameraDevice::kFocalLength)
           .setJpegQuality(requestSettings.jpegQuality)
+          .setJpegOrientation(requestSettings.jpegOrientation)
           .setJpegThumbnailSize(requestSettings.thumbnailResolution.width,
                                 requestSettings.thumbnailResolution.height)
           .setJpegThumbnailQuality(requestSettings.thumbnailJpegQuality)
+          .setLensOpticalStabilizationMode(
+              ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF)
           .setNoiseReductionMode(ANDROID_NOISE_REDUCTION_MODE_OFF)
           .setPipelineDepth(kPipelineDepth)
           .setSensorTimestamp(timestamp)
-          .build();
+          .setStatisticsHotPixelMapMode(
+              ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF)
+          .setStatisticsLensShadingMapMode(
+              ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF)
+          .setStatisticsSceneFlicker(ANDROID_STATISTICS_SCENE_FLICKER_NONE);
+
+  if (requestSettings.fpsRange.has_value()) {
+    builder.setControlAeTargetFpsRange(requestSettings.fpsRange.value());
+  }
+
+  if (requestSettings.gpsCoordinates.has_value()) {
+    const GpsCoordinates& coordinates = requestSettings.gpsCoordinates.value();
+    builder.setJpegGpsCoordinates(coordinates);
+  }
+
+  std::unique_ptr<CameraMetadata> metadata = builder.build();
+
   if (metadata == nullptr) {
     ALOGE("%s: Failed to build capture result metadata", __func__);
     return CameraMetadata();
@@ -192,12 +231,24 @@
 }
 
 std::vector<uint8_t> createExif(
-    Resolution imageSize, const std::vector<uint8_t>& compressedThumbnail = {}) {
+    Resolution imageSize, const CameraMetadata resultMetadata,
+    const std::vector<uint8_t>& compressedThumbnail = {}) {
   std::unique_ptr<ExifUtils> exifUtils(ExifUtils::create());
   exifUtils->initialize();
-  exifUtils->setImageWidth(imageSize.width);
-  exifUtils->setImageHeight(imageSize.height);
-  // TODO(b/324383963) Set Make/Model and orientation.
+
+  // Make a copy of the metadata in order to converting it the HAL metadata
+  // format (as opposed to the AIDL class) and use the setFromMetadata method
+  // from ExifUtil
+  camera_metadata_t* rawSettings =
+      clone_camera_metadata((camera_metadata_t*)resultMetadata.metadata.data());
+  if (rawSettings != nullptr) {
+    android::hardware::camera::common::helper::CameraMetadata halMetadata(
+        rawSettings);
+    exifUtils->setFromMetadata(halMetadata, imageSize.width, imageSize.height);
+  }
+  exifUtils->setMake(VirtualCameraDevice::kDefaultMakeAndModel);
+  exifUtils->setModel(VirtualCameraDevice::kDefaultMakeAndModel);
+  exifUtils->setFlash(0);
 
   std::vector<uint8_t> app1Data;
 
@@ -347,6 +398,12 @@
     processCaptureRequest(*task);
   }
 
+  // Destroy EGL utilities still on the render thread.
+  mEglSurfaceTexture.reset();
+  mEglTextureRgbProgram.reset();
+  mEglTextureYuvProgram.reset();
+  mEglDisplayContext.reset();
+
   ALOGV("Render thread exiting");
 }
 
@@ -395,7 +452,8 @@
     auto status = streamConfig->format == PixelFormat::BLOB
                       ? renderIntoBlobStreamBuffer(
                             reqBuffer.getStreamId(), reqBuffer.getBufferId(),
-                            request.getRequestSettings(), reqBuffer.getFence())
+                            captureResult.result, request.getRequestSettings(),
+                            reqBuffer.getFence())
                       : renderIntoImageStreamBuffer(reqBuffer.getStreamId(),
                                                     reqBuffer.getBufferId(),
                                                     reqBuffer.getFence());
@@ -431,7 +489,7 @@
     return;
   }
 
-  ALOGD("%s: Successfully called processCaptureResult", __func__);
+  ALOGV("%s: Successfully called processCaptureResult", __func__);
 }
 
 void VirtualCameraRenderThread::flushCaptureRequest(
@@ -484,8 +542,9 @@
 
   ALOGV("%s: Creating thumbnail with size %d x %d, quality %d", __func__,
         resolution.width, resolution.height, quality);
+  Resolution bufferSize = roundTo2DctSize(resolution);
   std::shared_ptr<EglFrameBuffer> framebuffer = allocateTemporaryFramebuffer(
-      mEglDisplayContext->getEglDisplay(), resolution.width, resolution.height);
+      mEglDisplayContext->getEglDisplay(), bufferSize.width, bufferSize.height);
   if (framebuffer == nullptr) {
     ALOGE(
         "Failed to allocate temporary framebuffer for JPEG thumbnail "
@@ -496,38 +555,23 @@
   // TODO(b/324383963) Add support for letterboxing if the thumbnail size
   // doesn't correspond
   //  to input texture aspect ratio.
-  if (!renderIntoEglFramebuffer(*framebuffer).isOk()) {
+  if (!renderIntoEglFramebuffer(*framebuffer, /*fence=*/nullptr,
+                                Rect(resolution.width, resolution.height))
+           .isOk()) {
     ALOGE(
         "Failed to render input texture into temporary framebuffer for JPEG "
         "thumbnail");
     return {};
   }
 
-  std::shared_ptr<AHardwareBuffer> inHwBuffer = framebuffer->getHardwareBuffer();
-  GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(inHwBuffer.get());
-
-  if (gBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_YCbCr_420_888) {
-    // This should never happen since we're allocating the temporary buffer
-    // with YUV420 layout above.
-    ALOGE("%s: Cannot compress non-YUV buffer (pixelFormat %d)", __func__,
-          gBuffer->getPixelFormat());
-    return {};
-  }
-
-  YCbCrLockGuard yCbCrLock(inHwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
-  if (yCbCrLock.getStatus() != NO_ERROR) {
-    ALOGE("%s: Failed to lock graphic buffer while generating thumbnail: %d",
-          __func__, yCbCrLock.getStatus());
-    return {};
-  }
-
   std::vector<uint8_t> compressedThumbnail;
   compressedThumbnail.resize(kJpegThumbnailBufferSize);
-  ALOGE("%s: Compressing thumbnail %d x %d", __func__, gBuffer->getWidth(),
-        gBuffer->getHeight());
-  std::optional<size_t> compressedSize = compressJpeg(
-      gBuffer->getWidth(), gBuffer->getHeight(), quality, *yCbCrLock, {},
-      compressedThumbnail.size(), compressedThumbnail.data());
+  ALOGE("%s: Compressing thumbnail %d x %d", __func__, resolution.width,
+        resolution.height);
+  std::optional<size_t> compressedSize =
+      compressJpeg(resolution.width, resolution.height, quality,
+                   framebuffer->getHardwareBuffer(), {},
+                   compressedThumbnail.size(), compressedThumbnail.data());
   if (!compressedSize.has_value()) {
     ALOGE("%s: Failed to compress jpeg thumbnail", __func__);
     return {};
@@ -537,7 +581,7 @@
 }
 
 ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoBlobStreamBuffer(
-    const int streamId, const int bufferId,
+    const int streamId, const int bufferId, const CameraMetadata& resultMetadata,
     const RequestSettings& requestSettings, sp<Fence> fence) {
   std::shared_ptr<AHardwareBuffer> hwBuffer =
       mSessionContext.fetchHardwareBuffer(streamId, bufferId);
@@ -558,15 +602,22 @@
 
   // Let's create YUV framebuffer and render the surface into this.
   // This will take care about rescaling as well as potential format conversion.
+  // The buffer dimensions need to be rounded to nearest multiple of JPEG DCT
+  // size, however we pass the viewport corresponding to size of the stream so
+  // the image will be only rendered to the area corresponding to the stream
+  // size.
+  Resolution bufferSize =
+      roundTo2DctSize(Resolution(stream->width, stream->height));
   std::shared_ptr<EglFrameBuffer> framebuffer = allocateTemporaryFramebuffer(
-      mEglDisplayContext->getEglDisplay(), stream->width, stream->height);
+      mEglDisplayContext->getEglDisplay(), bufferSize.width, bufferSize.height);
   if (framebuffer == nullptr) {
     ALOGE("Failed to allocate temporary framebuffer for JPEG compression");
     return cameraStatus(Status::INTERNAL_ERROR);
   }
 
   // Render into temporary framebuffer.
-  ndk::ScopedAStatus status = renderIntoEglFramebuffer(*framebuffer);
+  ndk::ScopedAStatus status = renderIntoEglFramebuffer(
+      *framebuffer, /*fence=*/nullptr, Rect(stream->width, stream->height));
   if (!status.isOk()) {
     ALOGE("Failed to render input texture into temporary framebuffer");
     return status;
@@ -578,38 +629,14 @@
     return cameraStatus(Status::INTERNAL_ERROR);
   }
 
-  std::shared_ptr<AHardwareBuffer> inHwBuffer = framebuffer->getHardwareBuffer();
-  GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(inHwBuffer.get());
-
-  if (gBuffer == nullptr) {
-    ALOGE(
-        "%s: Encountered invalid temporary buffer while rendering JPEG "
-        "into BLOB stream",
-        __func__);
-    return cameraStatus(Status::INTERNAL_ERROR);
-  }
-
-  if (gBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_YCbCr_420_888) {
-    // This should never happen since we're allocating the temporary buffer
-    // with YUV420 layout above.
-    ALOGE("%s: Cannot compress non-YUV buffer (pixelFormat %d)", __func__,
-          gBuffer->getPixelFormat());
-    return cameraStatus(Status::INTERNAL_ERROR);
-  }
-
-  YCbCrLockGuard yCbCrLock(inHwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
-  if (yCbCrLock.getStatus() != OK) {
-    return cameraStatus(Status::INTERNAL_ERROR);
-  }
-
   std::vector<uint8_t> app1ExifData =
-      createExif(Resolution(stream->width, stream->height),
+      createExif(Resolution(stream->width, stream->height), resultMetadata,
                  createThumbnail(requestSettings.thumbnailResolution,
                                  requestSettings.thumbnailJpegQuality));
   std::optional<size_t> compressedSize = compressJpeg(
-      gBuffer->getWidth(), gBuffer->getHeight(), requestSettings.jpegQuality,
-      *yCbCrLock, app1ExifData, stream->bufferSize - sizeof(CameraBlob),
-      (*planesLock).planes[0].data);
+      stream->width, stream->height, requestSettings.jpegQuality,
+      framebuffer->getHardwareBuffer(), app1ExifData,
+      stream->bufferSize - sizeof(CameraBlob), (*planesLock).planes[0].data);
 
   if (!compressedSize.has_value()) {
     ALOGE("%s: Failed to compress JPEG image", __func__);
@@ -663,7 +690,7 @@
 }
 
 ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoEglFramebuffer(
-    EglFrameBuffer& framebuffer, sp<Fence> fence) {
+    EglFrameBuffer& framebuffer, sp<Fence> fence, std::optional<Rect> viewport) {
   ALOGV("%s", __func__);
   // Wait for fence to clear.
   if (fence != nullptr && fence->isValid()) {
@@ -677,6 +704,11 @@
   mEglDisplayContext->makeCurrent();
   framebuffer.beforeDraw();
 
+  Rect viewportRect =
+      viewport.value_or(Rect(framebuffer.getWidth(), framebuffer.getHeight()));
+  glViewport(viewportRect.leftTop().x, viewportRect.leftTop().y,
+             viewportRect.getWidth(), viewportRect.getHeight());
+
   sp<GraphicBuffer> textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
   if (textureBuffer == nullptr) {
     // If there's no current buffer, nothing was written to the surface and
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index 86dad0b..90757a0 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -33,6 +33,7 @@
 #include "util/EglFramebuffer.h"
 #include "util/EglProgram.h"
 #include "util/EglSurfaceTexture.h"
+#include "util/MetadataUtil.h"
 #include "util/Util.h"
 
 namespace android {
@@ -56,8 +57,13 @@
 
 struct RequestSettings {
   int jpegQuality = VirtualCameraDevice::kDefaultJpegQuality;
+  int jpegOrientation = VirtualCameraDevice::kDefaultJpegOrientation;
   Resolution thumbnailResolution = Resolution(0, 0);
   int thumbnailJpegQuality = VirtualCameraDevice::kDefaultJpegQuality;
+  std::optional<FpsRange> fpsRange;
+  camera_metadata_enum_android_control_capture_intent_t captureIntent =
+      VirtualCameraDevice::kDefaultCaptureIntent;
+  std::optional<GpsCoordinates> gpsCoordinates;
 };
 
 // Represents single capture request to fill set of buffers.
@@ -149,6 +155,8 @@
   // Always called on render thread.
   ndk::ScopedAStatus renderIntoBlobStreamBuffer(
       const int streamId, const int bufferId,
+      const ::aidl::android::hardware::camera::device::CameraMetadata&
+          resultMetadata,
       const RequestSettings& requestSettings, sp<Fence> fence = nullptr);
 
   // Render current image to the YCbCr buffer.
@@ -162,8 +170,9 @@
   // If fence is specified, this function will block until the fence is cleared
   // before writing to the buffer.
   // Always called on the render thread.
-  ndk::ScopedAStatus renderIntoEglFramebuffer(EglFrameBuffer& framebuffer,
-                                              sp<Fence> fence = nullptr);
+  ndk::ScopedAStatus renderIntoEglFramebuffer(
+      EglFrameBuffer& framebuffer, sp<Fence> fence = nullptr,
+      std::optional<Rect> viewport = std::nullopt);
 
   // Camera callback
   const std::shared_ptr<
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 1144997..18961c0 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -46,6 +46,10 @@
 using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
 using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
 
+// TODO(b/301023410) Make camera id range configurable / dynamic
+// based on already registered devices.
+std::atomic_int VirtualCameraService::sNextId{1000};
+
 namespace {
 
 constexpr int kVgaWidth = 640;
@@ -110,6 +114,13 @@
 ndk::ScopedAStatus VirtualCameraService::registerCamera(
     const ::ndk::SpAIBinder& token,
     const VirtualCameraConfiguration& configuration, bool* _aidl_return) {
+  return registerCamera(token, configuration, sNextId++, _aidl_return);
+}
+
+ndk::ScopedAStatus VirtualCameraService::registerCamera(
+    const ::ndk::SpAIBinder& token,
+    const VirtualCameraConfiguration& configuration, const int cameraId,
+    bool* _aidl_return) {
   if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
     ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
           getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -141,7 +152,7 @@
   }
 
   std::shared_ptr<VirtualCameraDevice> camera =
-      mVirtualCameraProvider->createCamera(configuration);
+      mVirtualCameraProvider->createCamera(configuration, cameraId);
   if (camera == nullptr) {
     ALOGE("Failed to create camera for binder token 0x%" PRIxPTR,
           reinterpret_cast<uintptr_t>(token.get()));
@@ -175,11 +186,12 @@
 
   mVirtualCameraProvider->removeCamera(it->second);
 
+  mTokenToCameraName.erase(it);
   return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus VirtualCameraService::getCameraId(
-        const ::ndk::SpAIBinder& token, int32_t* _aidl_return) {
+    const ::ndk::SpAIBinder& token, int32_t* _aidl_return) {
   if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
     ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
           getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -188,7 +200,7 @@
 
   if (_aidl_return == nullptr) {
     return ndk::ScopedAStatus::fromServiceSpecificError(
-            Status::EX_ILLEGAL_ARGUMENT);
+        Status::EX_ILLEGAL_ARGUMENT);
   }
 
   auto camera = getCamera(token);
@@ -235,7 +247,15 @@
   }
   const char* const cmd = args[0];
   if (strcmp(kEnableTestCameraCmd, cmd) == 0) {
-    enableTestCameraCmd(in, err);
+    int cameraId = 0;
+    if (numArgs > 1 && args[1] != nullptr) {
+      cameraId = atoi(args[1]);
+    }
+    if (cameraId == 0) {
+      cameraId = sNextId++;
+    }
+
+    enableTestCameraCmd(in, err, cameraId);
   } else if (strcmp(kDisableTestCameraCmd, cmd) == 0) {
     disableTestCameraCmd(in);
   } else {
@@ -246,7 +266,8 @@
   return STATUS_OK;
 }
 
-void VirtualCameraService::enableTestCameraCmd(const int out, const int err) {
+void VirtualCameraService::enableTestCameraCmd(const int out, const int err,
+                                               const int cameraId) {
   if (mTestCameraToken != nullptr) {
     dprintf(out, "Test camera is already enabled (%s).",
             getCamera(mTestCameraToken)->getCameraName().c_str());
@@ -263,7 +284,7 @@
                                                   Format::YUV_420_888,
                                                   .maxFps = kMaxFps});
   configuration.lensFacing = LensFacing::EXTERNAL;
-  registerCamera(mTestCameraToken, configuration, &ret);
+  registerCamera(mTestCameraToken, configuration, cameraId, &ret);
   if (ret) {
     dprintf(out, "Successfully registered test camera %s",
             getCamera(mTestCameraToken)->getCameraName().c_str());
diff --git a/services/camera/virtualcamera/VirtualCameraService.h b/services/camera/virtualcamera/VirtualCameraService.h
index d573986..d447fc7 100644
--- a/services/camera/virtualcamera/VirtualCameraService.h
+++ b/services/camera/virtualcamera/VirtualCameraService.h
@@ -45,6 +45,13 @@
           configuration,
       bool* _aidl_return) override EXCLUDES(mLock);
 
+  // Register camera corresponding to the binder token.
+  ndk::ScopedAStatus registerCamera(
+      const ::ndk::SpAIBinder& token,
+      const ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
+          configuration,
+      int cameraId, bool* _aidl_return) EXCLUDES(mLock);
+
   // Unregisters camera corresponding to the binder token.
   ndk::ScopedAStatus unregisterCamera(const ::ndk::SpAIBinder& token) override
       EXCLUDES(mLock);
@@ -64,7 +71,7 @@
 
  private:
   // Create and enable test camera instance if there's none.
-  void enableTestCameraCmd(int out, int err);
+  void enableTestCameraCmd(int out, int err, int cameraId);
   // Disable and destroy test camera instance if there's one.
   void disableTestCameraCmd(int out);
 
@@ -84,6 +91,9 @@
 
   // Local binder token for test camera instance, or nullptr if there's none.
   ::ndk::SpAIBinder mTestCameraToken;
+
+  // Numerical id to assign to next created camera.
+  static std::atomic_int sNextId;
 };
 
 }  // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraSession.cc b/services/camera/virtualcamera/VirtualCameraSession.cc
index 2a691c1..7c17d7c 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.cc
+++ b/services/camera/virtualcamera/VirtualCameraSession.cc
@@ -148,7 +148,7 @@
           .setControlMode(ANDROID_CONTROL_MODE_AUTO)
           .setControlAeMode(ANDROID_CONTROL_AE_MODE_ON)
           .setControlAeExposureCompensation(0)
-          .setControlAeTargetFpsRange(maxFps, maxFps)
+          .setControlAeTargetFpsRange(FpsRange{maxFps, maxFps})
           .setControlAeAntibandingMode(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO)
           .setControlAePrecaptureTrigger(
               ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
@@ -257,10 +257,15 @@
   return RequestSettings{
       .jpegQuality = getJpegQuality(metadata).value_or(
           VirtualCameraDevice::kDefaultJpegQuality),
+      .jpegOrientation = getJpegOrientation(metadata),
       .thumbnailResolution =
           getJpegThumbnailSize(metadata).value_or(Resolution(0, 0)),
       .thumbnailJpegQuality = getJpegThumbnailQuality(metadata).value_or(
-          VirtualCameraDevice::kDefaultJpegQuality)};
+          VirtualCameraDevice::kDefaultJpegQuality),
+      .fpsRange = getFpsRange(metadata),
+      .captureIntent = getCaptureIntent(metadata).value_or(
+          ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW),
+      .gpsCoordinates = getGpsCoordinates(metadata)};
 }
 
 }  // namespace
@@ -513,7 +518,7 @@
 
 ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
     const CaptureRequest& request) {
-  ALOGD("%s: request: %s", __func__, request.toString().c_str());
+  ALOGV("%s: request: %s", __func__, request.toString().c_str());
 
   std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
   RequestSettings requestSettings;
diff --git a/services/camera/virtualcamera/flags/Android.bp b/services/camera/virtualcamera/flags/Android.bp
index 5fa53d8..5fa8852 100644
--- a/services/camera/virtualcamera/flags/Android.bp
+++ b/services/camera/virtualcamera/flags/Android.bp
@@ -35,27 +35,3 @@
     export_include_dirs: ["."],
     defaults: ["virtual_device_build_flags_defaults"],
 }
-
-soong_config_module_type {
-    name: "virtual_device_build_flags_java_library",
-    module_type: "java_library",
-    config_namespace: "vdm",
-    bool_variables: [
-        "virtual_camera_service_enabled",
-    ],
-    properties: [
-        "srcs",
-    ],
-}
-
-virtual_device_build_flags_java_library {
-    name: "virtual_device_build_flag_java",
-    soong_config_variables: {
-        virtual_camera_service_enabled: {
-            srcs: ["java/enabled/**/*.java"],
-            conditions_default: {
-                srcs: ["java/disabled/**/*.java"],
-            },
-        },
-    },
-}
diff --git a/services/camera/virtualcamera/flags/java/disabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java b/services/camera/virtualcamera/flags/java/disabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
deleted file mode 100644
index 128d93c..0000000
--- a/services/camera/virtualcamera/flags/java/disabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.companion.virtualdevice.flags;
-
-/** This file is included only if RELEASE_PACKAGE_VIRTUAL_CAMERA build flag isn't set.*/
-public class VirtualCameraServiceBuildFlag {
-
-    public static boolean isVirtualCameraServiceBuildFlagEnabled() {
-        return false;
-    }
-}
diff --git a/services/camera/virtualcamera/flags/java/enabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java b/services/camera/virtualcamera/flags/java/enabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
deleted file mode 100644
index 02816fb..0000000
--- a/services/camera/virtualcamera/flags/java/enabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.companion.virtualdevice.flags;
-
-/** This file is included only if RELEASE_PACKAGE_VIRTUAL_CAMERA build flag is set.*/
-public class VirtualCameraServiceBuildFlag {
-
-    public static boolean isVirtualCameraServiceBuildFlagEnabled() {
-        return true;
-    }
-}
diff --git a/services/camera/virtualcamera/tests/Android.bp b/services/camera/virtualcamera/tests/Android.bp
index c51b4a3..543cc10 100644
--- a/services/camera/virtualcamera/tests/Android.bp
+++ b/services/camera/virtualcamera/tests/Android.bp
@@ -17,6 +17,7 @@
     ],
     srcs: [
         "EglUtilTest.cc",
+        "JpegUtilTest.cc",
         "VirtualCameraDeviceTest.cc",
         "VirtualCameraProviderTest.cc",
         "VirtualCameraRenderThreadTest.cc",
diff --git a/services/camera/virtualcamera/tests/JpegUtilTest.cc b/services/camera/virtualcamera/tests/JpegUtilTest.cc
new file mode 100644
index 0000000..e6481f0
--- /dev/null
+++ b/services/camera/virtualcamera/tests/JpegUtilTest.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+
+#include "system/graphics.h"
+#define LOG_TAG "JpegUtilTest"
+
+#include <array>
+#include <cstdint>
+#include <cstring>
+
+#include "android/hardware_buffer.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "jpeglib.h"
+#include "util/JpegUtil.h"
+#include "util/Util.h"
+#include "utils/Errors.h"
+
+namespace android {
+namespace companion {
+namespace virtualcamera {
+namespace {
+
+using testing::Eq;
+using testing::Gt;
+using testing::Optional;
+using testing::VariantWith;
+
+constexpr int kOutputBufferSize = 1024 * 1024;  // 1 MiB.
+constexpr int kJpegQuality = 80;
+
+// Create black YUV420 buffer for testing purposes.
+std::shared_ptr<AHardwareBuffer> createHardwareBufferForTest(const int width,
+                                                             const int height) {
+  const AHardwareBuffer_Desc desc{.width = static_cast<uint32_t>(width),
+                                  .height = static_cast<uint32_t>(height),
+                                  .layers = 1,
+                                  .format = AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
+                                  .usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+                                  .stride = 0,
+                                  .rfu0 = 0,
+                                  .rfu1 = 0};
+
+  AHardwareBuffer* hwBufferPtr;
+  int status = AHardwareBuffer_allocate(&desc, &hwBufferPtr);
+  if (status != NO_ERROR) {
+    ALOGE(
+        "%s: Failed to allocate hardware buffer for temporary framebuffer: %d",
+        __func__, status);
+    return nullptr;
+  }
+
+  std::shared_ptr<AHardwareBuffer> hwBuffer(hwBufferPtr,
+                                            AHardwareBuffer_release);
+
+  YCbCrLockGuard yCbCrLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN);
+  const android_ycbcr& ycbr = (*yCbCrLock);
+
+  uint8_t* y = reinterpret_cast<uint8_t*>(ycbr.y);
+  for (int r = 0; r < height; r++) {
+    memset(y + r * ycbr.ystride, 0x00, width);
+  }
+
+  uint8_t* cb = reinterpret_cast<uint8_t*>(ycbr.cb);
+  uint8_t* cr = reinterpret_cast<uint8_t*>(ycbr.cr);
+  for (int r = 0; r < height / 2; r++) {
+    for (int c = 0; c < width / 2; c++) {
+      cb[r * ycbr.cstride + c * ycbr.chroma_step] = 0xff / 2;
+      cr[r * ycbr.cstride + c * ycbr.chroma_step] = 0xff / 2;
+    }
+  }
+
+  return hwBuffer;
+}
+
+// Decode JPEG header, return image resolution on success or error message on error.
+std::variant<std::string, Resolution> verifyHeaderAndGetResolution(
+    const uint8_t* data, int size) {
+  struct jpeg_decompress_struct ctx;
+  struct jpeg_error_mgr jerr;
+
+  struct DecompressionError {
+    bool success = true;
+    std::string error;
+  } result;
+
+  ctx.client_data = &result;
+
+  ctx.err = jpeg_std_error(&jerr);
+  ctx.err->error_exit = [](j_common_ptr cinfo) {
+    reinterpret_cast<DecompressionError*>(cinfo->client_data)->success = false;
+  };
+  ctx.err->output_message = [](j_common_ptr cinfo) {
+    char buffer[JMSG_LENGTH_MAX];
+    (*cinfo->err->format_message)(cinfo, buffer);
+    reinterpret_cast<DecompressionError*>(cinfo->client_data)->error = buffer;
+    ALOGE("libjpeg error: %s", buffer);
+  };
+
+  jpeg_create_decompress(&ctx);
+  jpeg_mem_src(&ctx, data, size);
+  jpeg_read_header(&ctx, /*require_image=*/true);
+
+  if (!result.success) {
+    jpeg_destroy_decompress(&ctx);
+    return result.error;
+  }
+
+  Resolution resolution(ctx.image_width, ctx.image_height);
+  jpeg_destroy_decompress(&ctx);
+  return resolution;
+}
+
+TEST(JpegUtil, roundToDctSize) {
+  EXPECT_THAT(roundTo2DctSize(Resolution(640, 480)), Eq(Resolution(640, 480)));
+  EXPECT_THAT(roundTo2DctSize(Resolution(5, 5)), Eq(Resolution(16, 16)));
+  EXPECT_THAT(roundTo2DctSize(Resolution(32, 32)), Eq(Resolution(32, 32)));
+  EXPECT_THAT(roundTo2DctSize(Resolution(33, 32)), Eq(Resolution(48, 32)));
+  EXPECT_THAT(roundTo2DctSize(Resolution(32, 33)), Eq(Resolution(32, 48)));
+}
+
+class JpegUtilTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    std::fill(mOutputBuffer.begin(), mOutputBuffer.end(), 0);
+  }
+
+ protected:
+  std::optional<size_t> compress(int imageWidth, int imageHeight,
+                                 std::shared_ptr<AHardwareBuffer> inBuffer) {
+    return compressJpeg(imageWidth, imageHeight, kJpegQuality, inBuffer,
+                        /*app1ExifData=*/{}, mOutputBuffer.size(),
+                        mOutputBuffer.data());
+  }
+
+  std::array<uint8_t, kOutputBufferSize> mOutputBuffer;
+};
+
+TEST_F(JpegUtilTest, compressImageSizeAlignedWithDctSucceeds) {
+  std::shared_ptr<AHardwareBuffer> inBuffer =
+      createHardwareBufferForTest(640, 480);
+
+  std::optional<size_t> compressedSize = compress(640, 480, inBuffer);
+
+  EXPECT_THAT(compressedSize, Optional(Gt(0)));
+  EXPECT_THAT(verifyHeaderAndGetResolution(mOutputBuffer.data(),
+                                           compressedSize.value()),
+              VariantWith<Resolution>(Resolution(640, 480)));
+}
+
+TEST_F(JpegUtilTest, compressImageSizeNotAlignedWidthDctSucceeds) {
+  std::shared_ptr<AHardwareBuffer> inBuffer =
+      createHardwareBufferForTest(640, 480);
+
+  std::optional<size_t> compressedSize = compress(630, 470, inBuffer);
+
+  EXPECT_THAT(compressedSize, Optional(Gt(0)));
+  EXPECT_THAT(verifyHeaderAndGetResolution(mOutputBuffer.data(),
+                                           compressedSize.value()),
+              VariantWith<Resolution>(Resolution(630, 470)));
+}
+
+TEST_F(JpegUtilTest, compressImageWithBufferNotAlignedWithDctFails) {
+  std::shared_ptr<AHardwareBuffer> inBuffer =
+      createHardwareBufferForTest(641, 480);
+
+  std::optional<size_t> compressedSize = compress(640, 480, inBuffer);
+
+  EXPECT_THAT(compressedSize, Eq(std::nullopt));
+}
+
+TEST_F(JpegUtilTest, compressImageWithBufferTooSmallFails) {
+  std::shared_ptr<AHardwareBuffer> inBuffer =
+      createHardwareBufferForTest(634, 464);
+
+  std::optional<size_t> compressedSize = compress(640, 480, inBuffer);
+
+  EXPECT_THAT(compressedSize, Eq(std::nullopt));
+}
+
+}  // namespace
+}  // namespace virtualcamera
+}  // namespace companion
+}  // namespace android
diff --git a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
index ab647a4..cd64ca5 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
@@ -53,6 +53,7 @@
 constexpr int kVgaWidth = 640;
 constexpr int kVgaHeight = 480;
 constexpr int kMaxFps = 30;
+constexpr int kCameraId = 9999;
 constexpr char kVirtualCameraNameRegex[] =
     "device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
 
@@ -118,7 +119,7 @@
 
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
   std::shared_ptr<VirtualCameraDevice> camera =
-      mCameraProvider->createCamera(mInputConfig);
+      mCameraProvider->createCamera(mInputConfig, kCameraId);
   EXPECT_THAT(camera, Not(IsNull()));
   EXPECT_THAT(camera->getCameraName(), MatchesRegex(kVirtualCameraNameRegex));
 
@@ -136,7 +137,7 @@
       .WillOnce(Return(ndk::ScopedAStatus::ok()));
 
   std::shared_ptr<VirtualCameraDevice> camera =
-      mCameraProvider->createCamera(mInputConfig);
+      mCameraProvider->createCamera(mInputConfig, kCameraId);
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
 
   // Created camera should be in the list of cameras.
@@ -148,7 +149,7 @@
 TEST_F(VirtualCameraProviderTest, RemoveCamera) {
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
   std::shared_ptr<VirtualCameraDevice> camera =
-      mCameraProvider->createCamera(mInputConfig);
+      mCameraProvider->createCamera(mInputConfig, kCameraId);
 
   EXPECT_CALL(*mMockCameraProviderCallback,
               cameraDeviceStatusChange(Eq(camera->getCameraName()),
@@ -165,7 +166,7 @@
 TEST_F(VirtualCameraProviderTest, RemoveNonExistingCamera) {
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
   std::shared_ptr<VirtualCameraDevice> camera =
-      mCameraProvider->createCamera(mInputConfig);
+      mCameraProvider->createCamera(mInputConfig, kCameraId);
 
   // Removing non-existing camera should fail.
   const std::string cameraName = "DefinitelyNoTCamera";
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index d4d00a2..f729f73 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -142,6 +142,14 @@
         Eq(NO_ERROR));
   }
 
+  void execute_shell_command(const std::string cmd, const std::string cameraId) {
+    std::array<const char*, 2> args{cmd.data(), cameraId.data()};
+    ASSERT_THAT(
+        mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd,
+                                           args.data(), args.size()),
+        Eq(NO_ERROR));
+  }
+
   std::vector<std::string> getCameraIds() {
     std::vector<std::string> cameraIds;
     EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
@@ -238,17 +246,6 @@
   EXPECT_THAT(getCameraIds(), IsEmpty());
 }
 
-TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
-  bool aidlRet;
-  VirtualCameraConfiguration config =
-      createConfiguration(641, 481, Format::YUV_420_888, kMaxFps);
-
-  ASSERT_FALSE(
-      mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
-  EXPECT_FALSE(aidlRet);
-  EXPECT_THAT(getCameraIds(), IsEmpty());
-}
-
 TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
   bool aidlRet;
   VirtualCameraConfiguration config =
@@ -381,6 +378,18 @@
   EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
 }
 
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) {
+  execute_shell_command("enable_test_camera", "12345");
+
+  std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
+  EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
+
+  execute_shell_command("disable_test_camera");
+
+  std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
+  EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
+}
+
 }  // namespace
 }  // namespace virtualcamera
 }  // namespace companion
diff --git a/services/camera/virtualcamera/util/JpegUtil.cc b/services/camera/virtualcamera/util/JpegUtil.cc
index 8569eff..b034584 100644
--- a/services/camera/virtualcamera/util/JpegUtil.cc
+++ b/services/camera/virtualcamera/util/JpegUtil.cc
@@ -14,19 +14,20 @@
  * limitations under the License.
  */
 // #define LOG_NDEBUG 0
+#include "system/graphics.h"
 #define LOG_TAG "JpegUtil"
-#include "JpegUtil.h"
-
 #include <cstddef>
 #include <cstdint>
 #include <optional>
 #include <vector>
 
+#include "JpegUtil.h"
 #include "android/hardware_buffer.h"
 #include "jpeglib.h"
 #include "log/log.h"
 #include "ui/GraphicBuffer.h"
 #include "ui/GraphicBufferMapper.h"
+#include "util/Util.h"
 #include "utils/Errors.h"
 
 namespace android {
@@ -34,6 +35,8 @@
 namespace virtualcamera {
 namespace {
 
+constexpr int k2DCTSIZE = 2 * DCTSIZE;
+
 class LibJpegContext {
  public:
   LibJpegContext(int width, int height, int quality, const size_t outBufferSize,
@@ -98,23 +101,55 @@
     return *this;
   }
 
-  std::optional<size_t> compress(const android_ycbcr& ycbr) {
-    // TODO(b/301023410) - Add support for compressing image sizes not aligned
-    // with DCT size.
-    if (mWidth % (2 * DCTSIZE) || (mHeight % (2 * DCTSIZE))) {
+  std::optional<size_t> compress(std::shared_ptr<AHardwareBuffer> inBuffer) {
+    GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(inBuffer.get());
+
+    if (gBuffer == nullptr) {
+      ALOGE("%s: Input graphic buffer is nullptr", __func__);
+      return std::nullopt;
+    }
+
+    if (gBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+      // This should never happen since we're allocating the temporary buffer
+      // with YUV420 layout above.
+      ALOGE("%s: Cannot compress non-YUV buffer (pixelFormat %d)", __func__,
+            gBuffer->getPixelFormat());
+      return std::nullopt;
+    }
+
+    YCbCrLockGuard yCbCrLock(inBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+    if (yCbCrLock.getStatus() != OK) {
+      ALOGE("%s: Failed to lock the input buffer: %s", __func__,
+            statusToString(yCbCrLock.getStatus()).c_str());
+      return std::nullopt;
+    }
+    const android_ycbcr& ycbr = *yCbCrLock;
+
+    const int inBufferWidth = gBuffer->getWidth();
+    const int inBufferHeight = gBuffer->getHeight();
+
+    if (inBufferWidth % k2DCTSIZE || (inBufferHeight % k2DCTSIZE)) {
       ALOGE(
-          "%s: Compressing YUV420 image with size %dx%d not aligned with 2 * "
+          "%s: Compressing YUV420 buffer with size %dx%d not aligned with 2 * "
           "DCTSIZE (%d) is not currently supported.",
-          __func__, mWidth, mHeight, 2 * DCTSIZE);
+          __func__, inBufferWidth, inBufferHeight, DCTSIZE);
+      return std::nullopt;
+    }
+
+    if (inBufferWidth < mWidth || inBufferHeight < mHeight) {
+      ALOGE(
+          "%s: Input buffer has smaller size (%dx%d) than image to be "
+          "compressed (%dx%d)",
+          __func__, inBufferWidth, inBufferHeight, mWidth, mHeight);
       return std::nullopt;
     }
 
     // Chroma planes have 1/2 resolution of the original image.
-    const int cHeight = mHeight / 2;
-    const int cWidth = mWidth / 2;
+    const int cHeight = inBufferHeight / 2;
+    const int cWidth = inBufferWidth / 2;
 
     // Prepare arrays of pointers to scanlines of each plane.
-    std::vector<JSAMPROW> yLines(mHeight);
+    std::vector<JSAMPROW> yLines(inBufferHeight);
     std::vector<JSAMPROW> cbLines(cHeight);
     std::vector<JSAMPROW> crLines(cHeight);
 
@@ -142,12 +177,12 @@
     }
 
     // Collect pointers to individual scanline of each plane.
-    for (int i = 0; i < mHeight; ++i) {
+    for (int i = 0; i < inBufferHeight; ++i) {
       yLines[i] = y + i * ycbr.ystride;
     }
     for (int i = 0; i < cHeight; ++i) {
-      cbLines[i] = cb_plane.data() + i * (mWidth / 2);
-      crLines[i] = cr_plane.data() + i * (mWidth / 2);
+      cbLines[i] = cb_plane.data() + i * cWidth;
+      crLines[i] = cr_plane.data() + i * cWidth;
     }
 
     return compress(yLines, cbLines, crLines);
@@ -254,17 +289,28 @@
   boolean mSuccess = true;
 };
 
+int roundTo2DCTMultiple(const int n) {
+  const int mod = n % k2DCTSIZE;
+  return mod == 0 ? n : n + (k2DCTSIZE - mod);
+}
+
 }  // namespace
 
 std::optional<size_t> compressJpeg(const int width, const int height,
-                                   const int quality, const android_ycbcr& ycbcr,
+                                   const int quality,
+                                   std::shared_ptr<AHardwareBuffer> inBuffer,
                                    const std::vector<uint8_t>& app1ExifData,
                                    size_t outBufferSize, void* outBuffer) {
   LibJpegContext context(width, height, quality, outBufferSize, outBuffer);
   if (!app1ExifData.empty()) {
     context.setApp1Data(app1ExifData.data(), app1ExifData.size());
   }
-  return context.compress(ycbcr);
+  return context.compress(inBuffer);
+}
+
+Resolution roundTo2DctSize(const Resolution resolution) {
+  return Resolution(roundTo2DCTMultiple(resolution.width),
+                    roundTo2DCTMultiple(resolution.height));
 }
 
 }  // namespace virtualcamera
diff --git a/services/camera/virtualcamera/util/JpegUtil.h b/services/camera/virtualcamera/util/JpegUtil.h
index 83ed74b..184dd56 100644
--- a/services/camera/virtualcamera/util/JpegUtil.h
+++ b/services/camera/virtualcamera/util/JpegUtil.h
@@ -19,17 +19,20 @@
 
 #include <optional>
 
-#include "system/graphics.h"
+#include "android/hardware_buffer.h"
+#include "util/Util.h"
 
 namespace android {
 namespace companion {
 namespace virtualcamera {
 
 // Jpeg-compress image into the output buffer.
-// * width - width of the image
-// * heigh - height of the image
+// * width - width of the image, can be less than width of inBuffer.
+// * heigh - height of the image, can be less than height of inBuffer.
 // * quality - 0-100, higher number corresponds to higher quality.
-// * ycbr - android_ycbr structure describing layout of input YUV420 image.
+// * inBuffer - Input buffer, the dimensions of the buffer must be aligned to
+//   2*DCT_SIZE (16) to include necessary padding in case width and height of
+//   image is not aligned with 2*DCT_SIZE.
 // * app1ExifData - vector containing data to be included in APP1
 //   segment. Can be empty.
 // * outBufferSize - capacity of the output buffer.
@@ -37,10 +40,14 @@
 // Returns size of compressed data if the compression was successful,
 // empty optional otherwise.
 std::optional<size_t> compressJpeg(int width, int height, int quality,
-                                   const android_ycbcr& ycbcr,
+                                   std::shared_ptr<AHardwareBuffer> inBuffer,
                                    const std::vector<uint8_t>& app1ExifData,
                                    size_t outBufferSize, void* outBuffer);
 
+// Round the resolution to the closest higher resolution where width and height
+// are divisible by 2*DCT_SIZE ().
+Resolution roundTo2DctSize(Resolution resolution);
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.cc b/services/camera/virtualcamera/util/MetadataUtil.cc
index e3d9e28..c7dc80e 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.cc
+++ b/services/camera/virtualcamera/util/MetadataUtil.cc
@@ -23,6 +23,8 @@
 #include <cstdint>
 #include <iterator>
 #include <memory>
+#include <optional>
+#include <string>
 #include <utility>
 #include <variant>
 #include <vector>
@@ -59,7 +61,7 @@
 }  // namespace
 
 MetadataBuilder& MetadataBuilder::setSupportedHardwareLevel(
-    camera_metadata_enum_android_info_supported_hardware_level_t hwLevel) {
+    const camera_metadata_enum_android_info_supported_hardware_level_t hwLevel) {
   mEntryMap[ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL] =
       asVectorOf<uint8_t>(hwLevel);
   return *this;
@@ -86,7 +88,7 @@
 }
 
 MetadataBuilder& MetadataBuilder::setLensFacing(
-    camera_metadata_enum_android_lens_facing lensFacing) {
+    const camera_metadata_enum_android_lens_facing lensFacing) {
   mEntryMap[ANDROID_LENS_FACING] = asVectorOf<uint8_t>(lensFacing);
   return *this;
 }
@@ -175,6 +177,12 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlSceneMode(
+    const camera_metadata_enum_android_control_scene_mode sceneMode) {
+  mEntryMap[ANDROID_CONTROL_SCENE_MODE] = asVectorOf<uint8_t>(sceneMode);
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setControlAvailableEffects(
     const std::vector<camera_metadata_enum_android_control_effect_mode>&
         availableEffects) {
@@ -198,6 +206,14 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlVideoStabilizationMode(
+    const camera_metadata_enum_android_control_video_stabilization_mode
+        stabilizationMode) {
+  mEntryMap[ANDROID_CONTROL_VIDEO_STABILIZATION_MODE] =
+      asVectorOf<uint8_t>(stabilizationMode);
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setControlAfAvailableModes(
     const std::vector<camera_metadata_enum_android_control_af_mode_t>&
         availableModes) {
@@ -212,6 +228,12 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlAfState(
+    const camera_metadata_enum_android_control_af_state afState) {
+  mEntryMap[ANDROID_CONTROL_AF_STATE] = asVectorOf<uint8_t>(afState);
+  return *this;
+}
+
 // See ANDROID_CONTROL_AF_TRIGGER_MODE in CameraMetadataTag.aidl.
 MetadataBuilder& MetadataBuilder::setControlAfTrigger(
     const camera_metadata_enum_android_control_af_trigger_t trigger) {
@@ -232,14 +254,14 @@
 }
 
 MetadataBuilder& MetadataBuilder::setControlAeTargetFpsRange(
-    const int32_t minFps, const int32_t maxFps) {
+    const FpsRange fpsRange) {
   mEntryMap[ANDROID_CONTROL_AE_TARGET_FPS_RANGE] =
-      std::vector<int32_t>({minFps, maxFps});
+      std::vector<int32_t>({fpsRange.minFps, fpsRange.maxFps});
   return *this;
 }
 
 MetadataBuilder& MetadataBuilder::setControlAeMode(
-    camera_metadata_enum_android_control_ae_mode_t mode) {
+    const camera_metadata_enum_android_control_ae_mode_t mode) {
   mEntryMap[ANDROID_CONTROL_AE_MODE] = asVectorOf<uint8_t>(mode);
   return *this;
 }
@@ -277,6 +299,12 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlAwbState(
+    const camera_metadata_enum_android_control_awb_state awbState) {
+  mEntryMap[ANDROID_CONTROL_AWB_STATE] = asVectorOf<uint8_t>(awbState);
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setControlAwbLockAvailable(
     const bool awbLockAvailable) {
   const uint8_t lockAvailable = awbLockAvailable
@@ -287,6 +315,12 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlAwbLock(
+    const camera_metadata_enum_android_control_awb_lock awbLock) {
+  mEntryMap[ANDROID_CONTROL_AWB_LOCK] = asVectorOf<uint8_t>(awbLock);
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setControlAeAvailableAntibandingModes(
     const std::vector<camera_metadata_enum_android_control_ae_antibanding_mode_t>&
         antibandingModes) {
@@ -313,6 +347,12 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlAeLock(
+    const camera_metadata_enum_android_control_ae_lock aeLock) {
+  mEntryMap[ANDROID_CONTROL_AE_LOCK] = asVectorOf<uint8_t>(aeLock);
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setControlAeRegions(
     const std::vector<ControlRegion>& aeRegions) {
   std::vector<int32_t> regions;
@@ -396,6 +436,29 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setJpegGpsCoordinates(
+    const GpsCoordinates& gpsCoordinates) {
+  mEntryMap[ANDROID_JPEG_GPS_COORDINATES] =
+      std::vector<double>({gpsCoordinates.latitude, gpsCoordinates.longitude,
+                           gpsCoordinates.altitude});
+
+  if (!gpsCoordinates.provider.empty()) {
+    mEntryMap[ANDROID_JPEG_GPS_PROCESSING_METHOD] = std::vector<uint8_t>{
+        gpsCoordinates.provider.begin(), gpsCoordinates.provider.end()};
+  }
+
+  if (gpsCoordinates.timestamp.has_value()) {
+    mEntryMap[ANDROID_JPEG_GPS_TIMESTAMP] =
+        asVectorOf<int64_t>(gpsCoordinates.timestamp.value());
+  }
+  return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setJpegOrientation(const int32_t orientation) {
+  mEntryMap[ANDROID_JPEG_ORIENTATION] = asVectorOf<int32_t>(orientation);
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setJpegQuality(const uint8_t quality) {
   mEntryMap[ANDROID_JPEG_QUALITY] = asVectorOf<uint8_t>(quality);
   return *this;
@@ -421,7 +484,7 @@
 }
 
 MetadataBuilder& MetadataBuilder::setSyncMaxLatency(
-    camera_metadata_enum_android_sync_max_latency latency) {
+    const camera_metadata_enum_android_sync_max_latency latency) {
   mEntryMap[ANDROID_SYNC_MAX_LATENCY] = asVectorOf<int32_t>(latency);
   return *this;
 }
@@ -506,7 +569,7 @@
 }
 
 MetadataBuilder& MetadataBuilder::setNoiseReductionMode(
-    camera_metadata_enum_android_noise_reduction_mode noiseReductionMode) {
+    const camera_metadata_enum_android_noise_reduction_mode noiseReductionMode) {
   mEntryMap[ANDROID_NOISE_REDUCTION_MODE] =
       asVectorOf<uint8_t>(noiseReductionMode);
   return *this;
@@ -585,6 +648,43 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlAeState(
+    const camera_metadata_enum_android_control_ae_state aeState) {
+  mEntryMap[ANDROID_CONTROL_AE_STATE] = asVectorOf<uint8_t>(aeState);
+  return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setStatisticsSceneFlicker(
+    const camera_metadata_enum_android_statistics_scene_flicker sceneFlicker) {
+  mEntryMap[ANDROID_STATISTICS_SCENE_FLICKER] =
+      asVectorOf<uint8_t>(sceneFlicker);
+  return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setStatisticsHotPixelMapMode(
+    const camera_metadata_enum_android_statistics_hot_pixel_map_mode
+        hotPixelMapMode) {
+  mEntryMap[ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE] =
+      asVectorOf<uint8_t>(hotPixelMapMode);
+  return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setStatisticsLensShadingMapMode(
+    const camera_metadata_enum_android_statistics_lens_shading_map_mode
+        lensShadingMapMode) {
+  mEntryMap[ANDROID_STATISTICS_LENS_SHADING_MAP_MODE] =
+      asVectorOf<uint8_t>(lensShadingMapMode);
+  return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setLensOpticalStabilizationMode(
+    const camera_metadata_enum_android_lens_optical_stabilization_mode_t
+        opticalStabilizationMode) {
+  mEntryMap[ANDROID_LENS_OPTICAL_STABILIZATION_MODE] =
+      asVectorOf<uint8_t>(opticalStabilizationMode);
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setAvailableRequestKeys(
     const std::vector<int32_t>& keys) {
   mEntryMap[ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS] = keys;
@@ -677,6 +777,20 @@
   return *entry.data.i32;
 }
 
+int32_t getJpegOrientation(
+    const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+  auto metadata =
+      reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+  camera_metadata_ro_entry_t entry;
+  if (find_camera_metadata_ro_entry(metadata, ANDROID_JPEG_ORIENTATION,
+                                    &entry) != OK) {
+    return 0;
+  }
+
+  return *entry.data.i32;
+}
+
 std::optional<Resolution> getJpegThumbnailSize(
     const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
   auto metadata =
@@ -724,6 +838,71 @@
   return thumbnailSizes;
 }
 
+std::optional<FpsRange> getFpsRange(
+    const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+  auto metadata =
+      reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+  camera_metadata_ro_entry_t entry;
+  if (find_camera_metadata_ro_entry(
+          metadata, ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry) != OK ||
+      entry.count != 2) {
+    return {};
+  }
+
+  FpsRange range{.minFps = entry.data.i32[0], .maxFps = entry.data.i32[1]};
+  return range;
+}
+
+std::optional<camera_metadata_enum_android_control_capture_intent>
+getCaptureIntent(const aidl::android::hardware::camera::device::CameraMetadata&
+                     cameraMetadata) {
+  auto metadata =
+      reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+  camera_metadata_ro_entry_t entry;
+  if (find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_CAPTURE_INTENT,
+                                    &entry) != OK) {
+    return {};
+  }
+
+  return static_cast<camera_metadata_enum_android_control_capture_intent>(
+      entry.data.u8[0]);
+}
+
+std::optional<GpsCoordinates> getGpsCoordinates(
+    const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+  auto metadata =
+      reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+  camera_metadata_ro_entry_t entry;
+  if (find_camera_metadata_ro_entry(metadata, ANDROID_JPEG_GPS_COORDINATES,
+                                    &entry) != OK) {
+    return std::nullopt;
+  }
+
+  GpsCoordinates coordinates{.latitude = entry.data.d[0],
+                             .longitude = entry.data.d[1],
+                             .altitude = entry.data.d[2]};
+
+  if (find_camera_metadata_ro_entry(metadata, ANDROID_JPEG_GPS_TIMESTAMP,
+                                    &entry) == OK) {
+    coordinates.timestamp = entry.data.i64[0];
+  }
+
+  // According to types.hal, the string describing the GPS processing method has
+  // a 32 characters size
+  static constexpr float kGpsProviderStringLength = 32;
+  if (find_camera_metadata_ro_entry(
+          metadata, ANDROID_JPEG_GPS_PROCESSING_METHOD, &entry) == OK) {
+    coordinates.provider.assign(
+        reinterpret_cast<const char*>(entry.data.u8),
+        std::min(entry.count, static_cast<size_t>(kGpsProviderStringLength)));
+  }
+
+  return coordinates;
+}
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.h b/services/camera/virtualcamera/util/MetadataUtil.h
index b4d60cb..5d16506 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.h
+++ b/services/camera/virtualcamera/util/MetadataUtil.h
@@ -59,16 +59,6 @@
     int32_t weight = 0;
   };
 
-  struct FpsRange {
-    int32_t minFps;
-    int32_t maxFps;
-
-    bool operator<(const FpsRange& other) const {
-      return maxFps == other.maxFps ? minFps < other.minFps
-                                    : maxFps < other.maxFps;
-    }
-  };
-
   MetadataBuilder() = default;
   ~MetadataBuilder() = default;
 
@@ -193,6 +183,10 @@
       const std::vector<camera_metadata_enum_android_control_scene_mode>&
           availableSceneModes);
 
+  // See ANDROID_CONTROL_SCENE_MODE in CameraMetadataTag.aidl
+  MetadataBuilder& setControlSceneMode(
+      camera_metadata_enum_android_control_scene_mode sceneMode);
+
   // See ANDROID_CONTROL_AVAILABLE_EFFECTS in CameraMetadataTag.aidl.
   MetadataBuilder& setControlAvailableEffects(
       const std::vector<camera_metadata_enum_android_control_effect_mode>&
@@ -202,12 +196,17 @@
   MetadataBuilder& setControlEffectMode(
       camera_metadata_enum_android_control_effect_mode_t effectMode);
 
-  // See ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES
+  // See ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES in CameraMetadataTag.aidl.
   MetadataBuilder& setControlAvailableVideoStabilizationModes(
       const std::vector<
           camera_metadata_enum_android_control_video_stabilization_mode_t>&
           videoStabilizationModes);
 
+  // See ANDROID_CONTROL_VIDEO_STABILIZATION_MODE in CameraMetadataTag.aidl.
+  MetadataBuilder& setControlVideoStabilizationMode(
+      camera_metadata_enum_android_control_video_stabilization_mode
+          stabilizationMode);
+
   // See CONTROL_AE_AVAILABLE_ANTIBANDING_MODES in CameraCharacteristics.java.
   MetadataBuilder& setControlAeAvailableAntibandingModes(
       const std::vector<camera_metadata_enum_android_control_ae_antibanding_mode_t>&
@@ -256,7 +255,7 @@
       const std::vector<FpsRange>& fpsRanges);
 
   // See ANDROID_CONTROL_AE_TARGET_FPS_RANGE in CaptureRequest.java.
-  MetadataBuilder& setControlAeTargetFpsRange(int32_t min, int32_t max);
+  MetadataBuilder& setControlAeTargetFpsRange(FpsRange fpsRange);
 
   // See ANDROID_CONTROL_CAPTURE_INTENT in CameraMetadataTag.aidl.
   MetadataBuilder& setControlCaptureIntent(
@@ -278,9 +277,21 @@
   // See CONTROL_AWB_LOCK_AVAILABLE in CameraMetadataTag.aidl.
   MetadataBuilder& setControlAwbLockAvailable(bool awbLockAvailable);
 
+  // See CONTROL_AWB_LOCK in CameraMetadataTag.aidl
+  MetadataBuilder& setControlAwbLock(
+      camera_metadata_enum_android_control_awb_lock awbLock);
+
   // See CONTROL_AE_LOCK_AVAILABLE in CameraMetadataTag.aidl.
   MetadataBuilder& setControlAeLockAvailable(bool aeLockAvailable);
 
+  // See CONTROL_AE_LOCK in CameraMetadataTag.aidl.
+  MetadataBuilder& setControlAeLock(
+      camera_metadata_enum_android_control_ae_lock aeLock);
+
+  // See CONTROL_AE_STATE in CameraMetadataTag.aidl
+  MetadataBuilder& setControlAeState(
+      camera_metadata_enum_android_control_ae_state aeState);
+
   // See ANDROID_CONTROL_AE_REGIONS in CameraMetadataTag.aidl.
   MetadataBuilder& setControlAeRegions(
       const std::vector<ControlRegion>& aeRegions);
@@ -289,6 +300,10 @@
   MetadataBuilder& setControlAwbRegions(
       const std::vector<ControlRegion>& awbRegions);
 
+  // See ANDROID_CONTROL_AWB_STATE in CameraMetadataTag.aidl.
+  MetadataBuilder& setControlAwbState(
+      camera_metadata_enum_android_control_awb_state awbState);
+
   // See ANDROID_SCALER_CROP_REGION in CaptureRequest.java.
   MetadataBuilder& setCropRegion(int32_t x, int32_t y, int32_t width,
                                  int32_t height);
@@ -297,6 +312,10 @@
   MetadataBuilder& setControlAfRegions(
       const std::vector<ControlRegion>& afRegions);
 
+  // See ANDROID_CONTROL_AF_STATE in CameraMetadataTag.aidl.
+  MetadataBuilder& setControlAfState(
+      camera_metadata_enum_android_control_af_state aeftate);
+
   // The size of the compressed JPEG image, in bytes.
   //
   // See ANDROID_JPEG_SIZE in CameraMetadataTag.aidl.
@@ -309,6 +328,12 @@
   MetadataBuilder& setJpegAvailableThumbnailSizes(
       const std::vector<Resolution>& thumbnailSizes);
 
+  // See ANDROID_JPEG_GPS_COORDINATES.
+  MetadataBuilder& setJpegGpsCoordinates(const GpsCoordinates& gpsCoordinates);
+
+  // See JPEG_ORIENTATION in CaptureRequest.java.
+  MetadataBuilder& setJpegOrientation(int32_t orientation);
+
   // See JPEG_QUALITY in CaptureRequest.java.
   MetadataBuilder& setJpegQuality(uint8_t quality);
 
@@ -342,6 +367,24 @@
   // See ANDROID_CONTROL_ZOOM_RATIO_RANGE in CameraMetadataTag.aidl.
   MetadataBuilder& setControlZoomRatioRange(float min, float max);
 
+  // See ANDROID_STATISTICS_SCENE_FLICKER in CameraMetadataTag.aidl.
+  MetadataBuilder& setStatisticsSceneFlicker(
+      camera_metadata_enum_android_statistics_scene_flicker sceneFlicker);
+
+  // See ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE in CameraMetadataTag.aidl.
+  MetadataBuilder& setStatisticsHotPixelMapMode(
+      camera_metadata_enum_android_statistics_hot_pixel_map_mode mode);
+
+  // See ANDROID_STATISTICS_LENS_SHADING_MAP_MODE in CameraMetadataTag.aidl.
+  MetadataBuilder& setStatisticsLensShadingMapMode(
+      camera_metadata_enum_android_statistics_lens_shading_map_mode
+          lensShadingMapMode);
+
+  // See ANDROID_LENS_OPTICAL_STABILIZATION_MODE in CameraMetadataTag.aidl.
+  MetadataBuilder& setLensOpticalStabilizationMode(
+      camera_metadata_enum_android_lens_optical_stabilization_mode_t
+          opticalStabilizationMode);
+
   // See ANDROID_REQUEST_AVAILABLE_CAPABILITIES in CameraMetadataTag.aidl.
   MetadataBuilder& setAvailableRequestCapabilities(
       const std::vector<
@@ -384,10 +427,11 @@
 
  private:
   // Maps metadata tags to vectors of values for the given tag.
-  std::map<camera_metadata_tag_t,
-           std::variant<std::vector<int64_t>, std::vector<int32_t>,
-                        std::vector<uint8_t>, std::vector<float>,
-                        std::vector<camera_metadata_rational_t>>>
+  std::map<
+      camera_metadata_tag_t,
+      std::variant<std::vector<int64_t>, std::vector<int32_t>,
+                   std::vector<uint8_t>, std::vector<float>,
+                   std::vector<camera_metadata_rational_t>, std::vector<double>>>
       mEntryMap;
   // Extend metadata with ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS.
   bool mExtendWithAvailableCharacteristicsKeys = false;
@@ -397,6 +441,10 @@
 std::optional<int32_t> getJpegQuality(
     const aidl::android::hardware::camera::device::CameraMetadata& metadata);
 
+// Return JPEG_ORIENTATION from metadata, or 0 if the key is not present
+int32_t getJpegOrientation(
+    const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
 // Returns JPEG_THUMBNAIL_SIZE from metadata, or nullopt if the key is not present.
 std::optional<Resolution> getJpegThumbnailSize(
     const aidl::android::hardware::camera::device::CameraMetadata& metadata);
@@ -410,6 +458,17 @@
 std::vector<Resolution> getJpegAvailableThumbnailSizes(
     const aidl::android::hardware::camera::device::CameraMetadata& metadata);
 
+std::optional<FpsRange> getFpsRange(
+    const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
+std::optional<camera_metadata_enum_android_control_capture_intent> getCaptureIntent(
+    const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
+// Returns ANDROID_JPEG_GPS_COORDINATES in a GpsCoordinate object or nullopt if
+// the key is not present.
+std::optional<GpsCoordinates> getGpsCoordinates(
+    const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/camera/virtualcamera/util/Util.cc b/services/camera/virtualcamera/util/Util.cc
index b2048bc..0c607d7 100644
--- a/services/camera/virtualcamera/util/Util.cc
+++ b/services/camera/virtualcamera/util/Util.cc
@@ -146,13 +146,6 @@
     return false;
   }
 
-  if (width % kLibJpegDctSize != 0 || height % kLibJpegDctSize != 0) {
-    // Input dimension needs to be multiple of libjpeg DCT size.
-    // TODO(b/301023410) This restriction can be removed once we add support for
-    // unaligned jpeg compression.
-    return false;
-  }
-
   if (maxFps <= 0 || maxFps > kMaxFpsUpperLimit) {
     return false;
   }
diff --git a/services/camera/virtualcamera/util/Util.h b/services/camera/virtualcamera/util/Util.h
index faae010..291e105 100644
--- a/services/camera/virtualcamera/util/Util.h
+++ b/services/camera/virtualcamera/util/Util.h
@@ -20,6 +20,8 @@
 #include <cmath>
 #include <cstdint>
 #include <memory>
+#include <optional>
+#include <string>
 
 #include "aidl/android/companion/virtualcamera/Format.h"
 #include "aidl/android/hardware/camera/common/Status.h"
@@ -142,6 +144,26 @@
   int height = 0;
 };
 
+struct FpsRange {
+  int32_t minFps;
+  int32_t maxFps;
+
+  bool operator<(const FpsRange& other) const {
+    return maxFps == other.maxFps ? minFps < other.minFps
+                                  : maxFps < other.maxFps;
+  }
+};
+
+struct GpsCoordinates {
+  // Represented by a double[] in metadata with index 0 for
+  // latitude and index 1 for longitude, 2 for altitude.
+  double_t latitude;
+  double_t longitude;
+  double_t altitude;
+  std::optional<int64_t> timestamp;
+  std::string provider;
+};
+
 inline bool isApproximatellySameAspectRatio(const Resolution r1,
                                             const Resolution r2) {
   static constexpr float kAspectRatioEpsilon = 0.05;
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 12ce17f..e3601a1 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -69,10 +69,10 @@
     "-android-cloexec-dup", // found in AAudioServiceEndpointMMAP.cpp
     "-bugprone-narrowing-conversions", // found in several interface from size_t to int32_t
 
-    "-google-readability-casting", // C++ casts not always necessary and may be verbose
-    "-google-readability-todo", // do not require TODO(info)
     "-google-build-using-namespace", // Reenable and fix later.
     "-google-global-names-in-headers", // found in several files
+    "-google-readability-casting", // C++ casts not always necessary and may be verbose
+    "-google-readability-todo", // do not require TODO(info)
 
     "-misc-non-private-member-variables-in-classes", // found in aidl generated files
 
@@ -82,27 +82,27 @@
     name: "libaaudioservice_dependencies",
 
     shared_libs: [
+        "aaudio-aidl-cpp",
+        "com.android.media.aaudio-aconfig-cc",
+        "framework-permission-aidl-cpp",
         "libaaudio_internal",
         "libaudioclient",
+        "libaudioclient_aidl_conversion",
         "libaudioutils",
-        "libmedia_helper",
-        "libmediametrics",
-        "libmediautils",
         "libbase",
         "libbinder",
         "libcutils",
         "liblog",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "libutils",
-        "aaudio-aidl-cpp",
-        "framework-permission-aidl-cpp",
-        "libaudioclient_aidl_conversion",
         "packagemanager_aidl-cpp",
-        "com.android.media.aaudio-aconfig-cc",
     ],
 
     static_libs: [
         "libaudioflinger",
-    ]
+    ],
 }
 
 cc_library_static {
@@ -110,8 +110,8 @@
     name: "libaaudioservice",
 
     defaults: [
-        "libaaudioservice_dependencies",
         "latest_android_media_audio_common_types_cpp_shared",
+        "libaaudioservice_dependencies",
     ],
 
     srcs: [
@@ -137,15 +137,15 @@
     ],
 
     cflags: [
-        "-Wthread-safety",
-        "-Wno-unused-parameter",
         "-Wall",
         "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
     ],
 
     export_shared_lib_headers: [
-        "libaaudio_internal",
         "framework-permission-aidl-cpp",
+        "libaaudio_internal",
     ],
 
     header_libs: [
@@ -153,8 +153,8 @@
     ],
 
     include_dirs: [
-        "frameworks/av/media/libnbaio/include_mono",
         "frameworks/av/media/libnbaio/include",
+        "frameworks/av/media/libnbaio/include_mono",
     ],
 
     tidy: true,
@@ -162,5 +162,5 @@
     tidy_checks_as_errors: tidy_errors,
     tidy_flags: [
         "-format-style=file",
-    ]
+    ],
 }
diff --git a/services/oboeservice/fuzzer/Android.bp b/services/oboeservice/fuzzer/Android.bp
index 31ed8ac..97825b3 100644
--- a/services/oboeservice/fuzzer/Android.bp
+++ b/services/oboeservice/fuzzer/Android.bp
@@ -37,22 +37,22 @@
         "oboeservice_fuzzer.cpp",
     ],
     shared_libs: [
+        "aaudio-aidl-cpp",
+        "com.android.media.aaudio-aconfig-cc",
+        "framework-permission-aidl-cpp",
         "libaaudio_internal",
         "libaudioclient",
+        "libaudioclient_aidl_conversion",
         "libaudioflinger",
         "libaudioutils",
-        "libmedia_helper",
-        "libmediametrics",
-        "libmediautils",
         "libbase",
         "libbinder",
         "libcutils",
         "liblog",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "libutils",
-        "aaudio-aidl-cpp",
-        "framework-permission-aidl-cpp",
-        "libaudioclient_aidl_conversion",
-        "com.android.media.aaudio-aconfig-cc",
     ],
     static_libs: [
         "libaaudioservice",
diff --git a/services/tuner/TunerDemux.cpp b/services/tuner/TunerDemux.cpp
index 92fa970..a80a88e 100644
--- a/services/tuner/TunerDemux.cpp
+++ b/services/tuner/TunerDemux.cpp
@@ -50,7 +50,9 @@
 }
 
 TunerDemux::~TunerDemux() {
-    close();
+    if (!isClosed) {
+        close();
+    }
     mDemux = nullptr;
     mTunerService = nullptr;
 }
@@ -125,6 +127,7 @@
 }
 
 ::ndk::ScopedAStatus TunerDemux::close() {
+    isClosed = true;
     return mDemux->close();
 }
 
diff --git a/services/tuner/TunerDemux.h b/services/tuner/TunerDemux.h
index 0c71987..17dd7e0 100644
--- a/services/tuner/TunerDemux.h
+++ b/services/tuner/TunerDemux.h
@@ -64,6 +64,7 @@
     shared_ptr<IDemux> mDemux;
     int mDemuxId;
     shared_ptr<TunerService> mTunerService;
+    bool isClosed = false;
 };
 
 }  // namespace tuner
diff --git a/services/tuner/TunerDescrambler.cpp b/services/tuner/TunerDescrambler.cpp
index ffe0be9..c1214bd 100644
--- a/services/tuner/TunerDescrambler.cpp
+++ b/services/tuner/TunerDescrambler.cpp
@@ -41,7 +41,9 @@
 }
 
 TunerDescrambler::~TunerDescrambler() {
-    close();
+    if (!isClosed) {
+        close();
+    }
     mDescrambler = nullptr;
 }
 
@@ -75,6 +77,7 @@
 }
 
 ::ndk::ScopedAStatus TunerDescrambler::close() {
+    isClosed = true;
     return mDescrambler->close();
 }
 
diff --git a/services/tuner/TunerDescrambler.h b/services/tuner/TunerDescrambler.h
index b1d5fb9..434fc5d 100644
--- a/services/tuner/TunerDescrambler.h
+++ b/services/tuner/TunerDescrambler.h
@@ -48,6 +48,7 @@
 
 private:
     shared_ptr<IDescrambler> mDescrambler;
+    bool isClosed = false;
 };
 
 }  // namespace tuner
diff --git a/services/tuner/TunerDvr.cpp b/services/tuner/TunerDvr.cpp
index fcee966..0e1b0fa 100644
--- a/services/tuner/TunerDvr.cpp
+++ b/services/tuner/TunerDvr.cpp
@@ -37,7 +37,9 @@
 }
 
 TunerDvr::~TunerDvr() {
-    close();
+    if (!isClosed) {
+        close();
+    }
     mDvr = nullptr;
 }
 
@@ -92,6 +94,7 @@
 }
 
 ::ndk::ScopedAStatus TunerDvr::close() {
+    isClosed = true;
     return mDvr->close();
 }
 
diff --git a/services/tuner/TunerDvr.h b/services/tuner/TunerDvr.h
index 2330e7b..1fb7a5c 100644
--- a/services/tuner/TunerDvr.h
+++ b/services/tuner/TunerDvr.h
@@ -77,6 +77,7 @@
 private:
     shared_ptr<IDvr> mDvr;
     DvrType mType;
+    bool isClosed = false;
 };
 
 }  // namespace tuner
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index 478e7ea..84a2b4e 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -47,7 +47,9 @@
         mTunerService(tuner) {}
 
 TunerFilter::~TunerFilter() {
-    close();
+    if (!isClosed) {
+        close();
+    }
     freeSharedFilterToken("");
     {
         Mutex::Autolock _l(mLock);
@@ -266,6 +268,7 @@
     mStarted = false;
     mShared = false;
     mClientPid = -1;
+    isClosed = true;
 
     return res;
 }
diff --git a/services/tuner/TunerFilter.h b/services/tuner/TunerFilter.h
index f6178c4..06735aa 100644
--- a/services/tuner/TunerFilter.h
+++ b/services/tuner/TunerFilter.h
@@ -116,6 +116,7 @@
     shared_ptr<FilterCallback> mFilterCallback;
     Mutex mLock;
     shared_ptr<TunerService> mTunerService;
+    bool isClosed = false;
 };
 
 }  // namespace tuner
diff --git a/services/tuner/TunerFrontend.cpp b/services/tuner/TunerFrontend.cpp
index 1e93d95..081596a 100644
--- a/services/tuner/TunerFrontend.cpp
+++ b/services/tuner/TunerFrontend.cpp
@@ -37,7 +37,9 @@
 }
 
 TunerFrontend::~TunerFrontend() {
-    close();
+    if (!isClosed) {
+        close();
+    }
     mFrontend = nullptr;
     mId = -1;
 }
@@ -89,6 +91,7 @@
 }
 
 ::ndk::ScopedAStatus TunerFrontend::close() {
+    isClosed = true;
     return mFrontend->close();
 }
 
diff --git a/services/tuner/TunerFrontend.h b/services/tuner/TunerFrontend.h
index da471fb..9612124 100644
--- a/services/tuner/TunerFrontend.h
+++ b/services/tuner/TunerFrontend.h
@@ -83,6 +83,7 @@
 private:
     int mId;
     shared_ptr<IFrontend> mFrontend;
+    bool isClosed = false;
 };
 
 }  // namespace tuner
diff --git a/services/tuner/TunerLnb.cpp b/services/tuner/TunerLnb.cpp
index 2fb6135..d27a978 100644
--- a/services/tuner/TunerLnb.cpp
+++ b/services/tuner/TunerLnb.cpp
@@ -36,7 +36,9 @@
 }
 
 TunerLnb::~TunerLnb() {
-    close();
+    if (!isClosed) {
+        close();
+    }
     mLnb = nullptr;
     mId = -1;
 }
@@ -70,6 +72,7 @@
 }
 
 ::ndk::ScopedAStatus TunerLnb::close() {
+    isClosed = true;
     return mLnb->close();
 }
 
diff --git a/services/tuner/TunerLnb.h b/services/tuner/TunerLnb.h
index 72988a6..b0222d7 100644
--- a/services/tuner/TunerLnb.h
+++ b/services/tuner/TunerLnb.h
@@ -66,6 +66,7 @@
 private:
     int mId;
     shared_ptr<ILnb> mLnb;
+    bool isClosed = false;
 };
 
 }  // namespace tuner
diff --git a/services/tuner/TunerTimeFilter.cpp b/services/tuner/TunerTimeFilter.cpp
index 385a063..7a4e200 100644
--- a/services/tuner/TunerTimeFilter.cpp
+++ b/services/tuner/TunerTimeFilter.cpp
@@ -35,7 +35,9 @@
 }
 
 TunerTimeFilter::~TunerTimeFilter() {
-    close();
+    if (!isClosed) {
+        close();
+    }
     mTimeFilter = nullptr;
 }
 
@@ -64,6 +66,7 @@
 }
 
 ::ndk::ScopedAStatus TunerTimeFilter::close() {
+    isClosed = true;
     return mTimeFilter->close();
 }
 
diff --git a/services/tuner/TunerTimeFilter.h b/services/tuner/TunerTimeFilter.h
index 31a47cd..7e40ebe 100644
--- a/services/tuner/TunerTimeFilter.h
+++ b/services/tuner/TunerTimeFilter.h
@@ -45,6 +45,7 @@
 
 private:
     shared_ptr<ITimeFilter> mTimeFilter;
+    bool isClosed = false;
 };
 
 }  // namespace tuner