Merge "Revert "Revert "Revert "Revert^2 "Audio policy: anonymize Bluetooth MAC ...""" into main
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 645a3d4..7d234bb 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2287,12 +2287,11 @@
      * <p>When low light boost is enabled by setting the AE mode to
      * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
      * boost when the light level threshold is exceeded.</p>
-     * <p>This field is present in the CaptureResult when the AE mode is set to
-     * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'. Otherwise, the field is not present.</p>
      * <p>This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
      * indicate when it is not being applied by returning 'INACTIVE'.</p>
      * <p>This key will be absent from the CaptureResult if AE mode is not set to
      * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
+     * <p>The default value will always be 'INACTIVE'.</p>
      */
     ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE =                     // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
             ACAMERA_CONTROL_START + 59,
@@ -2428,27 +2427,27 @@
      * </ul></p>
      *
      * <p>Flash strength level to use in capture mode i.e. when the applications control
-     * flash with either SINGLE or TORCH mode.</p>
+     * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p>
      * <p>Use ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
      * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL to check whether the device supports
      * flash strength control or not.
-     * If the values of android.flash.info.singleStrengthMaxLevel and
+     * If the values of ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
      * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1,
      * then the device supports manual flash strength control.</p>
-     * <p>If the ACAMERA_FLASH_MODE <code>==</code> TORCH the value must be &gt;= 1
+     * <p>If the ACAMERA_FLASH_MODE <code>==</code> <code>TORCH</code> the value must be &gt;= 1
      * and &lt;= ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL.
      * If the application doesn't set the key and
      * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL &gt; 1,
      * then the flash will be fired at the default level set by HAL in
      * ACAMERA_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL.
-     * If the ACAMERA_FLASH_MODE <code>==</code> SINGLE, then the value must be &gt;= 1
+     * If the ACAMERA_FLASH_MODE <code>==</code> <code>SINGLE</code>, then the value must be &gt;= 1
      * and &lt;= ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL.
      * If the application does not set this key and
      * ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL &gt; 1,
      * then the flash will be fired at the default level set by HAL
      * in ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL.
-     * If ACAMERA_CONTROL_AE_MODE is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
-     * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+     * If ACAMERA_CONTROL_AE_MODE is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>,
+     * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p>
      *
      * @see ACAMERA_CONTROL_AE_MODE
      * @see ACAMERA_FLASH_MODE
@@ -2460,7 +2459,7 @@
     ACAMERA_FLASH_STRENGTH_LEVEL =                              // int32
             ACAMERA_FLASH_START + 6,
     /**
-     * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+     * <p>Maximum flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
      *
      * <p>Type: int32</p>
      *
@@ -2470,7 +2469,7 @@
      * </ul></p>
      *
      * <p>Maximum flash brightness level in camera capture mode and
-     * ACAMERA_FLASH_MODE set to SINGLE.
+     * ACAMERA_FLASH_MODE set to <code>SINGLE</code>.
      * Value will be &gt; 1 if the manual flash strength control feature is supported,
      * otherwise the value will be equal to 1.
      * Note that this level is just a number of supported levels (the granularity of control).
@@ -2481,7 +2480,7 @@
     ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL =                   // int32
             ACAMERA_FLASH_START + 7,
     /**
-     * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+     * <p>Default flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
      *
      * <p>Type: int32</p>
      *
@@ -2500,7 +2499,7 @@
     ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL =               // int32
             ACAMERA_FLASH_START + 8,
     /**
-     * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+     * <p>Maximum flash brightness level for manual flash control in <code>TORCH</code> mode</p>
      *
      * <p>Type: int32</p>
      *
@@ -2510,7 +2509,7 @@
      * </ul></p>
      *
      * <p>Maximum flash brightness level in camera capture mode and
-     * ACAMERA_FLASH_MODE set to TORCH.
+     * ACAMERA_FLASH_MODE set to <code>TORCH</code>.
      * Value will be &gt; 1 if the manual flash strength control feature is supported,
      * otherwise the value will be equal to 1.</p>
      * <p>Note that this level is just a number of supported levels(the granularity of control).
@@ -2527,7 +2526,7 @@
     ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL =                    // int32
             ACAMERA_FLASH_START + 9,
     /**
-     * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+     * <p>Default flash brightness level for manual flash control in <code>TORCH</code> mode</p>
      *
      * <p>Type: int32</p>
      *
@@ -5875,10 +5874,16 @@
      *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
      * </ul></p>
      *
-     * <p>If TRUE, all images produced by the camera device in the RAW image formats will
-     * have lens shading correction already applied to it. If FALSE, the images will
-     * not be adjusted for lens shading correction.
-     * See android.request.maxNumOutputRaw for a list of RAW image formats.</p>
+     * <p>If <code>true</code>, all images produced by the camera device in the <code>RAW</code> image formats will have
+     * at least some lens shading correction already applied to it. If <code>false</code>, the images will
+     * not be adjusted for lens shading correction.  See android.request.maxNumOutputRaw for a
+     * list of RAW image formats.</p>
+     * <p>When <code>true</code>, the <code>lensShadingCorrectionMap</code> key may still have values greater than 1.0,
+     * and those will need to be applied to any captured RAW frames for them to match the shading
+     * correction of processed buffers such as <code>YUV</code> or <code>JPEG</code> images. This may occur, for
+     * example, when some basic fixed lens shading correction is applied by hardware to RAW data,
+     * and additional correction is done dynamically in the camera processing pipeline after
+     * demosaicing.</p>
      * <p>This key will be <code>null</code> for all devices do not report this information.
      * Devices with RAW capability will always report this information in this key.</p>
      */
@@ -8305,11 +8310,8 @@
      * <p>If the session configuration is not supported, the AE mode reported in the
      * CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.</p>
      * <p>When this AE mode is enabled, the CaptureResult field
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be present and not null. Otherwise, the
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE field will not be present in the CaptureResult.</p>
-     * <p>The application can observe the CaptureResult field
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE to determine when low light boost is 'ACTIVE' or
-     * 'INACTIVE'.</p>
+     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will indicate when low light boost is 'ACTIVE'
+     * or 'INACTIVE'. By default ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be 'INACTIVE'.</p>
      * <p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
      * upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.
      * This mode will be 'INACTIVE' once the scene lighting condition is greater than the
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index e26290f..5a2ab27 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -289,7 +289,7 @@
 
     std::string toString() const {
         std::stringstream ss;
-        ss << "Interpolator{mInterpolatorType=" << static_cast<int32_t>(mInterpolatorType);
+        ss << "Interpolator{mInterpolatorType=" << media::toString(mInterpolatorType);
         ss << ", mFirstSlope=" << mFirstSlope;
         ss << ", mLastSlope=" << mLastSlope;
         ss << ", {";
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 6208db3..26da363 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -116,6 +116,16 @@
             TYPE_SCALE,
         };
 
+        static std::string toString(Type type) {
+            switch (type) {
+                case TYPE_ID: return "TYPE_ID";
+                case TYPE_SCALE: return "TYPE_SCALE";
+                default:
+                    return std::string("Unknown Type: ")
+                            .append(std::to_string(static_cast<int>(type)));
+            }
+        }
+
         // Must match with VolumeShaper.java in frameworks/base.
         enum OptionFlag : int32_t {
             OPTION_FLAG_NONE           = 0,
@@ -125,6 +135,22 @@
             OPTION_FLAG_ALL            = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
         };
 
+        static std::string toString(OptionFlag flag) {
+            std::string s;
+            for (const auto& flagPair : std::initializer_list<std::pair<OptionFlag, const char*>>{
+                    {OPTION_FLAG_VOLUME_IN_DBFS, "OPTION_FLAG_VOLUME_IN_DBFS"},
+                    {OPTION_FLAG_CLOCK_TIME, "OPTION_FLAG_CLOCK_TIME"},
+                }) {
+                if (flag & flagPair.first) {
+                    if (!s.empty()) {
+                        s.append("|");
+                    }
+                    s.append(flagPair.second);
+                }
+            }
+            return s;
+        }
+
         // Bring from base class; must match with VolumeShaper.java in frameworks/base.
         using InterpolatorType = Interpolator<S, T>::InterpolatorType;
 
@@ -329,10 +355,10 @@
         // Returns a string for debug printing.
         std::string toString() const {
             std::stringstream ss;
-            ss << "VolumeShaper::Configuration{mType=" << static_cast<int32_t>(mType);
+            ss << "VolumeShaper::Configuration{mType=" << toString(mType);
             ss << ", mId=" << mId;
             if (mType != TYPE_ID) {
-                ss << ", mOptionFlags=" << static_cast<int32_t>(mOptionFlags);
+                ss << ", mOptionFlags=" << toString(mOptionFlags);
                 ss << ", mDurationMs=" << mDurationMs;
                 ss << ", " << Interpolator<S, T>::toString().c_str();
             }
@@ -414,6 +440,25 @@
                             | FLAG_CREATE_IF_NECESSARY),
         };
 
+        static std::string toString(Flag flag) {
+            std::string s;
+            for (const auto& flagPair : std::initializer_list<std::pair<Flag, const char*>>{
+                    {FLAG_REVERSE, "FLAG_REVERSE"},
+                    {FLAG_TERMINATE, "FLAG_TERMINATE"},
+                    {FLAG_JOIN, "FLAG_JOIN"},
+                    {FLAG_DELAY, "FLAG_DELAY"},
+                    {FLAG_CREATE_IF_NECESSARY, "FLAG_CREATE_IF_NECESSARY"},
+                }) {
+                if (flag & flagPair.first) {
+                    if (!s.empty()) {
+                        s.append("|");
+                    }
+                    s.append(flagPair.second);
+                }
+            }
+            return s;
+        }
+
         Operation()
             : Operation(FLAG_NONE, -1 /* replaceId */) {
         }
@@ -508,7 +553,7 @@
 
         std::string toString() const {
             std::stringstream ss;
-            ss << "VolumeShaper::Operation{mFlags=" << static_cast<int32_t>(mFlags) ;
+            ss << "VolumeShaper::Operation{mFlags=" << toString(mFlags);
             ss << ", mReplaceId=" << mReplaceId;
             ss << ", mXOffset=" << mXOffset;
             ss << "}";
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index c642a94..c3ae59c 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -60,6 +60,13 @@
 }
 
 flag {
+    name: "music_fx_edge_to_edge"
+    namespace: "media_audio"
+    description: "Enable Edge-to-edge feature for MusicFx and handle insets"
+    bug: "336204940"
+}
+
+flag {
     name: "port_to_piid_simplification"
     namespace: "media_audio"
     description: "PAM only needs for each piid the last portId mapping"
@@ -68,6 +75,14 @@
 }
 
 flag {
+    name: "replace_stream_bt_sco"
+    namespace: "media_audio"
+    description:
+        "Replace internally STREAM_BLUETOOTH_SCO with STREAM_VOICE_CALL"
+    bug: "345024266"
+}
+
+flag {
     name: "ringer_mode_affects_alarm"
     namespace: "media_audio"
     description:
diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig
index 94b60e2..5e70168 100644
--- a/media/audio/aconfig/audioserver.aconfig
+++ b/media/audio/aconfig/audioserver.aconfig
@@ -15,6 +15,13 @@
 }
 
 flag {
+    name: "effect_chain_callback_improve"
+    namespace: "media_audio"
+    description: "Improve effect chain callback mutex logic."
+    bug: "342413767"
+}
+
+flag {
     name: "fdtostring_timeout_fix"
     namespace: "media_audio"
     description: "Improve fdtostring implementation to properly handle timing out."
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 08e2fa6..3e88acd 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -465,6 +465,7 @@
       mTemporalPatternIdx(0),
       mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
       mSignalledOutputEos(false),
+      mHeaderGenerated(false),
       mSignalledError(false) {
     for (int i = 0; i < MAXTEMPORALLAYERS; i++) {
         mTemporalLayerBitrateRatio[i] = 1.0f;
@@ -494,6 +495,7 @@
 
     // this one is not allocated by us
     mCodecInterface = nullptr;
+    mHeaderGenerated = false;
 }
 
 c2_status_t C2SoftVpxEnc::onStop() {
@@ -558,6 +560,7 @@
           (uint32_t)mBitrateControlMode, mTemporalLayers, mIntf->getSyncFramePeriod(),
           mMinQuantizer, mMaxQuantizer);
 
+    mHeaderGenerated = false;
     mCodecConfiguration = new vpx_codec_enc_cfg_t;
     if (!mCodecConfiguration) goto CleanUp;
     codec_return = vpx_codec_enc_config_default(mCodecInterface,
@@ -873,6 +876,27 @@
         return;
     }
 
+    // Header generation is limited to Android V and above, as MediaMuxer did not handle
+    // CSD for VP9 correctly in Android U and before.
+    if (isAtLeastV() && !mHeaderGenerated) {
+        vpx_fixed_buf_t* codec_private_data = vpx_codec_get_global_headers(mCodecContext);
+        if (codec_private_data) {
+            std::unique_ptr<C2StreamInitDataInfo::output> csd =
+                    C2StreamInitDataInfo::output::AllocUnique(codec_private_data->sz, 0u);
+            if (!csd) {
+                ALOGE("CSD allocation failed");
+                mSignalledError = true;
+                work->result = C2_NO_MEMORY;
+                work->workletsProcessed = 1u;
+                return;
+            }
+            memcpy(csd->m.value, codec_private_data->buf, codec_private_data->sz);
+            work->worklets.front()->output.configUpdate.push_back(std::move(csd));
+            ALOGV("CSD Produced of size %zu bytes", codec_private_data->sz);
+        }
+        mHeaderGenerated = true;
+    }
+
     const C2ConstGraphicBlock inBuffer =
         inputBuffer->data().graphicBlocks().front();
     if (inBuffer.width() < mSize->width ||
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
index 980de04..87d24f9 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.h
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -207,6 +207,9 @@
      // Signalled EOS
      bool mSignalledOutputEos;
 
+     // Header generated
+     bool mHeaderGenerated;
+
      // Signalled Error
      bool mSignalledError;
 
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index b95c09e..ea4d045 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -36,7 +36,7 @@
 #include <ostream>
 #include <sstream>
 
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
 #include <codec2/hidl/plugin/FilterPlugin.h>
 #include <dlfcn.h>
 #include <C2Config.h>
@@ -51,7 +51,7 @@
 namespace c2 {
 namespace utils {
 
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
 using ::android::DefaultFilterPlugin;
 using ::android::FilterWrapper;
 #endif
@@ -144,7 +144,15 @@
     ::android::SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -173,8 +181,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -189,7 +196,7 @@
     return mParameterCache;
 }
 
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
 // static
 std::shared_ptr<FilterWrapper> ComponentStore::GetFilterWrapper() {
     constexpr const char kPluginPath[] = "libc2filterplugin.so";
@@ -221,8 +228,13 @@
                 }
             }
             if (!isComponentSupportsLargeAudioFrame) {
+                // TODO - b/342269852: MultiAccessUnitInterface also needs to take multiple
+                // param reflectors. Currently filters work on video domain only,
+                // and the MultiAccessUnitHelper is only enabled on audio domain;
+                // thus we pass the component's param reflector, which is mParamReflectors[0].
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -250,7 +262,7 @@
             mStore->createComponent(name, &c2component);
 
     if (status == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
         c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
 #endif
         onInterfaceLoaded(c2component->intf());
@@ -284,7 +296,7 @@
     std::shared_ptr<C2ComponentInterface> c2interface;
     c2_status_t res = mStore->createInterface(name, &c2interface);
     if (res == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
         c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
 #endif
         onInterfaceLoaded(c2interface);
@@ -347,8 +359,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -401,6 +412,16 @@
     return ScopedAStatus::ok();
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index 746e1bf..b2158a6 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -118,7 +118,7 @@
 
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
@@ -135,6 +135,9 @@
     mutable std::mutex mComponentRosterMutex;
     std::map<Component*, ComponentStatus> mComponentRoster;
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     // Called whenever Component is created.
     void reportComponentBirth(Component* component);
     // Called only from the destructor of Component.
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
index 4c9da33..0638363 100644
--- a/media/codec2/hal/common/Android.bp
+++ b/media/codec2/hal/common/Android.bp
@@ -28,13 +28,9 @@
         "liblog",
         "libstagefright_foundation",
         "server_configurable_flags",
+        "libaconfig_storage_read_api_cc",
     ],
-
     static_libs: ["aconfig_mediacodec_flags_c_lib"],
-
-    defaults: [
-        "aconfig_lib_cc_static_link.defaults",
-    ],
 }
 
 cc_library_static {
@@ -57,6 +53,7 @@
     shared_libs: [
         "libbase",
         "server_configurable_flags",
+        "libaconfig_storage_read_api_cc",
     ],
 
     static_libs: ["aconfig_mediacodec_flags_c_lib"],
@@ -71,5 +68,6 @@
     shared_libs: [
         "libbase",
         "server_configurable_flags",
+        "libaconfig_storage_read_api_cc",
     ],
 }
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index 988ab6f..1ba1889 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
     SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -168,8 +176,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -217,7 +224,8 @@
             }
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -339,8 +347,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -386,6 +393,16 @@
     return mConfigurable;
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index b5d85da..44b8ec1 100644
--- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -117,9 +117,12 @@
     // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index 46af809..1b86958 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
     SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -168,8 +176,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -218,7 +225,8 @@
 
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -340,8 +348,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -423,6 +430,16 @@
     return Void();
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
diff --git a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
index 85862a9..52d2945 100644
--- a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
@@ -125,9 +125,12 @@
     // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index f89c835..2e0386f 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@
     SetPreferredCodec2ComponentStore(store);
 
     // Retrieve struct descriptors
-    mParamReflector = mStore->getParamReflector();
+    mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+    std::shared_ptr<C2ParamReflector> paramReflector =
+        GetFilterWrapper()->getParamReflector();
+    if (paramReflector != nullptr) {
+        ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+        mParamReflectors.push_back(paramReflector);
+    }
+#endif
 
     // Retrieve supported parameters from store
     using namespace std::placeholders;
@@ -168,8 +176,7 @@
         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
         auto it = mStructDescriptors.find(coreIndex);
         if (it == mStructDescriptors.end()) {
-            std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+            std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
             if (!structDesc) {
                 // All supported params must be described
                 res = C2_BAD_INDEX;
@@ -217,7 +224,8 @@
             }
             if (!isComponentSupportsLargeAudioFrame) {
                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
-                        c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+                        c2interface,
+                        std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
             }
         }
     }
@@ -338,8 +346,7 @@
         if (item == mStructDescriptors.end()) {
             // not in the cache, and not known to be unsupported, query local reflector
             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
-                std::shared_ptr<C2StructDescriptor> structDesc =
-                    mParamReflector->describe(coreIndex);
+                std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
                 if (!structDesc) {
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
@@ -457,6 +464,16 @@
     return Void();
 }
 
+std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
+    for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
+        std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
+        if (desc) {
+            return desc;
+        }
+    }
+    return nullptr;
+}
+
 // Called from createComponent() after a successful creation of `component`.
 void ComponentStore::reportComponentBirth(Component* component) {
     ComponentStatus componentStatus;
diff --git a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
index c08fce4..1b209e2 100644
--- a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
@@ -132,9 +132,12 @@
     // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
+    // describe from mParamReflectors
+    std::shared_ptr<C2StructDescriptor> describe(const C2Param::CoreIndex &index);
+
     c2_status_t mInit;
     std::shared_ptr<C2ComponentStore> mStore;
-    std::shared_ptr<C2ParamReflector> mParamReflector;
+    std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
 
     std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
     std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/plugin/FilterWrapper.cpp b/media/codec2/hal/plugin/FilterWrapper.cpp
index b926150..ab6e3eb 100644
--- a/media/codec2/hal/plugin/FilterWrapper.cpp
+++ b/media/codec2/hal/plugin/FilterWrapper.cpp
@@ -1012,4 +1012,11 @@
     return mPlugin->queryParamsForPreviousComponent(intf, params);
 }
 
+std::shared_ptr<C2ParamReflector> FilterWrapper::getParamReflector() {
+    if (mInit != OK) {
+        return nullptr;
+    }
+    return mStore->getParamReflector();
+}
+
 }  // namespace android
diff --git a/media/codec2/hal/plugin/FilterWrapperStub.cpp b/media/codec2/hal/plugin/FilterWrapperStub.cpp
index 3fd5409..a21f6d0 100644
--- a/media/codec2/hal/plugin/FilterWrapperStub.cpp
+++ b/media/codec2/hal/plugin/FilterWrapperStub.cpp
@@ -57,4 +57,8 @@
     return CreateCodec2BlockPool(allocatorParam, component, pool);
 }
 
+std::shared_ptr<C2ParamReflector> FilterWrapper::getParamReflector() {
+    return nullptr;
+}
+
 }  // namespace android
diff --git a/media/codec2/hal/plugin/internal/FilterWrapper.h b/media/codec2/hal/plugin/internal/FilterWrapper.h
index dcffb5c..c27901e 100644
--- a/media/codec2/hal/plugin/internal/FilterWrapper.h
+++ b/media/codec2/hal/plugin/internal/FilterWrapper.h
@@ -104,6 +104,10 @@
             const std::shared_ptr<C2ComponentInterface> &intf,
             std::vector<std::unique_ptr<C2Param>> *params);
 
+    /**
+     * Return the param reflector of the filter plugin store.
+     */
+    std::shared_ptr<C2ParamReflector> getParamReflector();
 private:
     status_t mInit;
     std::unique_ptr<Plugin> mPlugin;
diff --git a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
index b5383ad..47412b7 100644
--- a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
@@ -37,6 +37,19 @@
                 kParamIndexColorAspects | C2Param::CoreIndex::IS_REQUEST_FLAG>
         C2StreamColorAspectsRequestInfo;
 
+// In practice the vendor parameters will be defined in a separate header file,
+// but for the purpose of this sample, we just define it here.
+
+// Vendor-specific type index for filters start from this value. 0x7000 is added to
+// avoid conflict with existing vendor type indices.
+constexpr uint32_t kTypeIndexFilterStart = C2Param::TYPE_INDEX_VENDOR_START + 0x7000;
+// Answer to the Ultimate Question of Life, the Universe, and Everything
+// (Reference to The Hitchhiker's Guide to the Galaxy by Douglas Adams)
+constexpr uint32_t kParamIndexVendorUltimateAnswer = kTypeIndexFilterStart + 0;
+typedef C2StreamParam<C2Info, C2Int32Value, kParamIndexVendorUltimateAnswer>
+        C2StreamVendorUltimateAnswerInfo;
+constexpr char C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER[] = "ultimate-answer";
+
 namespace android {
 
 using namespace std::literals::chrono_literals;
@@ -49,10 +62,9 @@
         static const std::string NAME;
         static const FilterPlugin_V1::Descriptor DESCRIPTOR;
 
-        explicit Interface(c2_node_id_t id)
+        Interface(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
             : mId(id),
-              mReflector(std::make_shared<C2ReflectorHelper>()),
-              mHelper(mReflector) {
+              mHelper(reflector) {
         }
         ~Interface() override = default;
         C2String getName() const override { return NAME; }
@@ -126,7 +138,6 @@
         }
     private:
         const c2_node_id_t mId;
-        std::shared_ptr<C2ReflectorHelper> mReflector;
         struct Helper : public C2InterfaceHelper {
             explicit Helper(std::shared_ptr<C2ReflectorHelper> reflector)
                 : C2InterfaceHelper(reflector) {
@@ -266,6 +277,15 @@
                         .build());
 
                 addParameter(
+                        DefineParam(mVendorUltimateAnswerInfo, C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER)
+                        .withDefault(new C2StreamVendorUltimateAnswerInfo::input(0u))
+                        .withFields({
+                            C2F(mVendorUltimateAnswerInfo, value).any(),
+                        })
+                        .withSetter(VendorUltimateAnswerSetter)
+                        .build());
+
+                addParameter(
                         DefineParam(mOutputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
                         .withDefault(new C2StreamColorAspectsInfo::output(0u))
                         .withFields({
@@ -336,6 +356,15 @@
                 return C2R::Ok();
             }
 
+            static C2R VendorUltimateAnswerSetter(
+                    bool mayBlock,
+                    C2P<C2StreamVendorUltimateAnswerInfo::input> &me) {
+                (void)mayBlock;
+                ALOGI("Answer to the Ultimate Question of Life, the Universe, and Everything "
+                      "set to %d", me.v.value);
+                return C2R::Ok();
+            }
+
             std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
 
             std::shared_ptr<C2ComponentNameSetting> mName;
@@ -362,11 +391,13 @@
             std::shared_ptr<C2StreamColorAspectsInfo::input> mInputColorAspectInfo;
             std::shared_ptr<C2StreamColorAspectsInfo::output> mOutputColorAspectInfo;
             std::shared_ptr<C2StreamColorAspectsRequestInfo::output> mColorAspectRequestInfo;
+
+            std::shared_ptr<C2StreamVendorUltimateAnswerInfo::input> mVendorUltimateAnswerInfo;
         } mHelper;
     };
 
-    explicit SampleToneMappingFilter(c2_node_id_t id)
-        : mIntf(std::make_shared<Interface>(id)) {
+    SampleToneMappingFilter(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
+        : mIntf(std::make_shared<Interface>(id, reflector)) {
     }
     ~SampleToneMappingFilter() override {
         if (mProcessingThread.joinable()) {
@@ -802,7 +833,10 @@
 // static
 const FilterPlugin_V1::Descriptor SampleToneMappingFilter::Interface::DESCRIPTOR = {
     // controlParams
-    { C2StreamColorAspectsRequestInfo::output::PARAM_TYPE },
+    {
+        C2StreamColorAspectsRequestInfo::output::PARAM_TYPE,
+        C2StreamVendorUltimateAnswerInfo::input::PARAM_TYPE,
+    },
     // affectedParams
     {
         C2StreamHdrStaticInfo::output::PARAM_TYPE,
@@ -815,7 +849,7 @@
     SampleC2ComponentStore()
         : mReflector(std::make_shared<C2ReflectorHelper>()),
           mIntf(mReflector),
-          mFactories(CreateFactories()) {
+          mFactories(CreateFactories(mReflector)) {
     }
     ~SampleC2ComponentStore() = default;
 
@@ -892,36 +926,46 @@
     template <class T>
     struct ComponentFactoryImpl : public ComponentFactory {
     public:
-        ComponentFactoryImpl(const std::shared_ptr<const C2Component::Traits> &traits)
-            : ComponentFactory(traits) {
+        ComponentFactoryImpl(
+                const std::shared_ptr<const C2Component::Traits> &traits,
+                const std::shared_ptr<C2ReflectorHelper> &reflector)
+            : ComponentFactory(traits),
+              mReflector(reflector) {
         }
         ~ComponentFactoryImpl() override = default;
         c2_status_t createComponent(
                 c2_node_id_t id,
                 std::shared_ptr<C2Component>* const component) const override {
-            *component = std::make_shared<T>(id);
+            *component = std::make_shared<T>(id, mReflector);
             return C2_OK;
         }
         c2_status_t createInterface(
                 c2_node_id_t id,
                 std::shared_ptr<C2ComponentInterface>* const interface) const override {
-            *interface = std::make_shared<typename T::Interface>(id);
+            *interface = std::make_shared<typename T::Interface>(id, mReflector);
             return C2_OK;
         }
+    private:
+        std::shared_ptr<C2ReflectorHelper> mReflector;
     };
 
     template <class T>
-    static void AddFactory(std::map<C2String, std::unique_ptr<ComponentFactory>> *factories) {
-        std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0)};
+    static void AddFactory(
+            std::map<C2String, std::unique_ptr<ComponentFactory>> *factories,
+            const std::shared_ptr<C2ReflectorHelper> &reflector) {
+        std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0, reflector)};
         std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
         CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
                 << "Failed to fill traits from interface";
-        factories->emplace(traits->name, new ComponentFactoryImpl<T>(traits));
+        factories->emplace(
+                traits->name,
+                new ComponentFactoryImpl<T>(traits, reflector));
     }
 
-    static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories() {
+    static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories(
+            const std::shared_ptr<C2ReflectorHelper> &reflector) {
         std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
-        AddFactory<SampleToneMappingFilter>(&factories);
+        AddFactory<SampleToneMappingFilter>(&factories, reflector);
         return factories;
     }
 
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 7076bac..3c8c1b7 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -84,6 +84,7 @@
         "libui",
         "libutils",
         "server_configurable_flags",
+        "libaconfig_storage_read_api_cc",
     ],
 
     export_shared_lib_headers: [
@@ -91,10 +92,6 @@
         "libcodec2_client",
     ],
 
-    defaults: [
-        "aconfig_lib_cc_static_link.defaults",
-    ],
-
     sanitize: {
         cfi: true,
         misc_undefined: [
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 5d50fc3..3438406 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -533,8 +533,7 @@
             break;
         default:
             ALOGV("Unsupported fence type %d", type);
-            // If this is malformed-handle close the handle here.
-            (void) native_handle_close(handle);
+            // Nothing else to do. The handle is owned by the caller.
             // return a null-fence in this case
             break;
     }
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 9d9b574..21321b9 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -1115,6 +1115,17 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
  *
+ * If you set Usage then you will need to associate the volume keys with the resulting stream.
+ * Otherwise the volume keys may not work correctly.
+ * This is done in Java with the following code block.
+ *
+ * <pre><code>if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ *     AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage)
+ *             .setContentType(contentType).build();
+ *     setVolumeControlStream(attributes.getVolumeControlStream());
+ * }
+ * </code></pre>
+ *
  * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
@@ -1132,6 +1143,17 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
  *
+ * If you set ContentType then you will need to associate the volume keys with the resulting stream.
+ * Otherwise the volume keys may not work correctly.
+ * This is done in Java with the following code block.
+ *
+ * <pre><code>if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ *     AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage)
+ *             .setContentType(contentType).build();
+ *     setVolumeControlStream(attributes.getVolumeControlStream());
+ * }
+ * </code></pre>
+ *
  * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6772201..58e4920 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -3035,6 +3035,7 @@
         const sp<VolumeShaper::Configuration>& configuration,
         const sp<VolumeShaper::Operation>& operation)
 {
+    const int64_t beginNs = systemTime();
     AutoMutex lock(mLock);
     mVolumeHandler->setIdIfNecessary(configuration);
     media::VolumeShaperConfiguration config;
@@ -3042,6 +3043,18 @@
     media::VolumeShaperOperation op;
     operation->writeToParcelable(&op);
     VolumeShaper::Status status;
+
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER)
+                .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
+                .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+                .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+                .set(AMEDIAMETRICS_PROP_TOSTRING, configuration->toString()
+                                 .append(" ")
+                                 .append(operation->toString()))
+                .record(); });
+
     mAudioTrack->applyVolumeShaper(config, op, &status);
 
     if (status == DEAD_OBJECT) {
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index cf3b43a..a707909 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -923,6 +923,11 @@
     return statusTFromBinderStatus(mDelegate->setTracksInternalMute(tracksInternalMuted));
 }
 
+status_t AudioFlingerClientAdapter::resetReferencesForTest() {
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mDelegate->resetReferencesForTest()));
+    return OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // AudioFlingerServerAdapter
 AudioFlingerServerAdapter::AudioFlingerServerAdapter(
@@ -1487,4 +1492,9 @@
     return Status::fromStatusT(mDelegate->setTracksInternalMute(tracksInternalMute));
 }
 
+Status AudioFlingerServerAdapter::resetReferencesForTest() {
+    RETURN_BINDER_IF_ERROR(mDelegate->resetReferencesForTest());
+    return Status::ok();
+}
+
 } // namespace android
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index e213f08..79fcea8 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1264,13 +1264,10 @@
                     nsec += 1000000000;
                 }
 
-                if ((sec + 1) > ((time_t)(INT_MAX / mSamplingRate))) {
-                    mMaxSmp = sec * mSamplingRate;
-                } else {
-                    // mSamplingRate is always > 1000
-                    sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
-                    mMaxSmp = (unsigned int)(((int64_t)sec * mSamplingRate) / 1000);
-                }
+                const uint64_t msec = static_cast<uint64_t>(sec) * 1000 + nsec / 1'000'000;
+                mMaxSmp = std::min(static_cast<uint64_t>(TONEGEN_INF - 1),
+                        msec * mSamplingRate / 1000);
+
                 ALOGV("stopTone() forcing mMaxSmp to %d, total for far %" PRIu64, mMaxSmp,
                       mTotalSmp);
             } else {
@@ -1638,14 +1635,11 @@
 
     mpToneDesc = mpNewToneDesc;
 
-    if (mDurationMs == -1) {
+    if (mDurationMs < 0) {  // mDurationMs is signed, treat all neg numbers as INF.
         mMaxSmp = TONEGEN_INF;
     } else {
-        if (mDurationMs > (int)(TONEGEN_INF / mSamplingRate)) {
-            mMaxSmp = (mDurationMs / 1000) * mSamplingRate;
-        } else {
-            mMaxSmp = (mDurationMs * mSamplingRate) / 1000;
-        }
+        mMaxSmp = std::min(static_cast<uint64_t>(TONEGEN_INF - 1),
+                static_cast<uint64_t>(mDurationMs) * mSamplingRate / 1000);
         ALOGV("prepareWave, duration limited to %d ms", mDurationMs);
     }
 
@@ -1676,7 +1670,8 @@
     if (mpToneDesc->segments[0].duration == TONEGEN_INF) {
         mNextSegSmp = TONEGEN_INF;
     } else{
-        mNextSegSmp = (mpToneDesc->segments[0].duration * mSamplingRate) / 1000;
+        mNextSegSmp = std::min(static_cast<uint64_t>(TONEGEN_INF - 1),
+                static_cast<uint64_t>(mpToneDesc->segments[0].duration) * mSamplingRate / 1000);
     }
 
     return true;
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index e8fcf77..4f00f83 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -299,6 +299,12 @@
      */
     void setTracksInternalMute(in TrackInternalMuteInfo[] tracksInternalMute);
 
+    /*
+     * Reset Circular references in AudioFlinger service.
+     * Test API
+     */
+     void resetReferencesForTest();
+
     // When adding a new method, please review and update
     // IAudioFlinger.h AudioFlingerServerAdapter::Delegate::TransactionCode
     // AudioFlinger.cpp AudioFlinger::onTransactWrapper()
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 860a0bc..211fffa 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -392,6 +392,8 @@
 
     virtual status_t setTracksInternalMute(
             const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) = 0;
+
+    virtual status_t resetReferencesForTest() = 0;
 };
 
 /**
@@ -510,6 +512,7 @@
                              struct audio_port_v7 *mixPort) const override;
     status_t setTracksInternalMute(
             const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override;
+    status_t resetReferencesForTest() override;
 
 private:
     const sp<media::IAudioFlingerService> mDelegate;
@@ -613,6 +616,8 @@
                     media::BnAudioFlingerService::TRANSACTION_getAudioPolicyConfig,
             GET_AUDIO_MIX_PORT = media::BnAudioFlingerService::TRANSACTION_getAudioMixPort,
             SET_TRACKS_INTERNAL_MUTE = media::BnAudioFlingerService::TRANSACTION_setTracksInternalMute,
+            RESET_REFERENCES_FOR_TEST =
+                    media::BnAudioFlingerService::TRANSACTION_resetReferencesForTest,
         };
 
     protected:
@@ -751,6 +756,7 @@
                            media::AudioPortFw* _aidl_return) override;
     Status setTracksInternalMute(
             const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override;
+    Status resetReferencesForTest() override;
 private:
     const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
 };
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index daabdb7..e5373f3 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -65,9 +65,9 @@
          {5, 3, -1, 3, 5}}}; /* Rock Preset */
 
 static const std::vector<Equalizer::Preset> kEqPresets = {
-        {0, "Normal"},      {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
-        {5, "Heavy Metal"}, {6, "Hip Hop"},   {7, "Jazz"},  {8, "Pop"},  {9, "Rock"}};
-
+        {-1, "Custom"}, {0, "Normal"}, {1, "Classical"},   {2, "Dance"},
+        {3, "Flat"},    {4, "Folk"},   {5, "Heavy Metal"}, {6, "Hip Hop"},
+        {7, "Jazz"},    {8, "Pop"},    {9, "Rock"}};
 
 const std::vector<Range::EqualizerRange> kEqRanges = {
         MAKE_RANGE(Equalizer, preset, 0, MAX_NUM_PRESETS - 1),
diff --git a/media/liberror/include/error/BinderResult.h b/media/liberror/include/error/BinderResult.h
new file mode 100644
index 0000000..1f1211c
--- /dev/null
+++ b/media/liberror/include/error/BinderResult.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <binder/Status.h>
+#include <error/expected_utils.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace error {
+
+/**
+ * A convenience short-hand for base::expected, where the error type is a binder::Status, for use
+ * when implementing binder services.
+ * Clients need to link against libbinder, since this library is header only.
+ */
+template <typename T>
+using BinderResult = base::expected<T, binder::Status>;
+
+inline base::unexpected<binder::Status> unexpectedExceptionCode(int32_t exceptionCode,
+                                                                const char* s) {
+    return base::unexpected{binder::Status::fromExceptionCode(exceptionCode, s)};
+}
+
+inline base::unexpected<binder::Status> unexpectedServiceException(int32_t serviceSpecificCode,
+                                                                   const char* s) {
+    return base::unexpected{binder::Status::fromServiceSpecificError(serviceSpecificCode, s)};
+}
+
+}  // namespace error
+}  // namespace android
+
+inline std::string errorToString(const ::android::binder::Status& status) {
+    return std::string{status.toString8().c_str()};
+}
diff --git a/media/liberror/include/error/BinderStatusMatcher.h b/media/liberror/include/error/BinderStatusMatcher.h
new file mode 100644
index 0000000..11d9e65
--- /dev/null
+++ b/media/liberror/include/error/BinderStatusMatcher.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+
+#include <binder/Status.h>
+
+namespace android::error {
+
+class BinderStatusMatcher {
+  public:
+    using is_gtest_matcher = void;
+
+    explicit BinderStatusMatcher(binder::Status status) : status_(std::move(status)) {}
+
+    static BinderStatusMatcher hasException(binder::Status::Exception ex) {
+        return BinderStatusMatcher(binder::Status::fromExceptionCode(ex));
+    }
+
+    static BinderStatusMatcher isOk() { return BinderStatusMatcher(binder::Status::ok()); }
+
+    bool MatchAndExplain(const binder::Status& value,
+                         ::testing::MatchResultListener* listener) const {
+        if (status_.exceptionCode() == value.exceptionCode() &&
+            status_.transactionError() == value.transactionError() &&
+            status_.serviceSpecificErrorCode() == value.serviceSpecificErrorCode()) {
+            return true;
+        }
+        *listener << "received binder status: " << value;
+        return false;
+    }
+
+    void DescribeTo(std::ostream* os) const { *os << "contains binder status " << status_; }
+
+    void DescribeNegationTo(std::ostream* os) const {
+        *os << "does not contain binder status " << status_;
+    }
+
+  private:
+    const binder::Status status_;
+};
+}  // namespace android::error
diff --git a/media/liberror/include/error/ExpectedMatchers.h b/media/liberror/include/error/ExpectedMatchers.h
new file mode 100644
index 0000000..b81adbf
--- /dev/null
+++ b/media/liberror/include/error/ExpectedMatchers.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+#include <type_traits>
+
+namespace android::error {
+
+/**
+ * Example Usage:
+ * Given a function with signature
+ *       Result<T, U> foo()
+ * Matchers can be used as follows:
+ *       EXPECT_THAT(foo(), IsOkAnd(Eq(T{})));
+ *       EXPECT_THAT(foo(), IsErrorAnd(Eq(U{})));
+ */
+template <typename ExpectedT>
+class IsOkAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+  public:
+    using ValueT = std::remove_reference_t<ExpectedT>::value_type;
+
+    template <typename InnerMatcher>
+    explicit IsOkAndImpl(InnerMatcher innerMatcher)
+        : inner_matcher_(::testing::SafeMatcherCast<const ValueT&>(
+                  std::forward<InnerMatcher>(innerMatcher))) {}
+
+    bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+        if (!val.has_value()) {
+            *listener << "which has error " << ::testing::PrintToString(val.error());
+            return false;
+        }
+        const auto res = inner_matcher_.MatchAndExplain(val.value(), listener);
+        if (!res) {
+            *listener << "which has value " << ::testing::PrintToString(val.value());
+        }
+        return res;
+    }
+
+    void DescribeTo(std::ostream* os) const {
+        *os << "contains expected value which ";
+        inner_matcher_.DescribeTo(os);
+    }
+
+    void DescribeNegationTo(std::ostream* os) const {
+        *os << "does not contain expected, or contains expected value which ";
+        inner_matcher_.DescribeNegationTo(os);
+    }
+
+  private:
+    ::testing::Matcher<const ValueT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsOkAnd {
+  public:
+    explicit IsOkAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+    template <typename T>
+    operator ::testing::Matcher<T>() const {
+        return ::testing::Matcher<T>{new IsOkAndImpl<const T&>(inner_matcher_)};
+    }
+
+  private:
+    InnerMatcher inner_matcher_;
+};
+
+template <typename ExpectedT>
+class IsErrorAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+  public:
+    using ErrorT = typename std::remove_reference_t<ExpectedT>::error_type;
+
+    template <typename InnerMatcher>
+    explicit IsErrorAndImpl(InnerMatcher innerMatcher)
+        : inner_matcher_(::testing::SafeMatcherCast<const ErrorT&>(
+                  std::forward<InnerMatcher>(innerMatcher))) {}
+
+    bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+        if (val.has_value()) {
+            *listener << "which has value " << ::testing::PrintToString(val.value());
+            return false;
+        }
+
+        const auto res = inner_matcher_.MatchAndExplain(val.error(), listener);
+        if (!res) {
+            *listener << "which has error " << ::testing::PrintToString(val.error());
+        }
+        return res;
+    }
+
+    void DescribeTo(std::ostream* os) const {
+        *os << "contains error value which ";
+        inner_matcher_.DescribeTo(os);
+    }
+
+    void DescribeNegationTo(std::ostream* os) const {
+        *os << "does not contain error value, or contains error value which ";
+        inner_matcher_.DescribeNegationTo(os);
+    }
+
+  private:
+    ::testing::Matcher<const ErrorT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsErrorAnd {
+  public:
+    explicit IsErrorAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+    template <typename T>
+    operator ::testing::Matcher<T>() const {
+        return ::testing::Matcher<T>{new IsErrorAndImpl<const T&>(inner_matcher_)};
+    }
+
+  private:
+    InnerMatcher inner_matcher_;
+};
+
+}  // namespace android::error
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 26aa375..e60a678 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -213,6 +213,7 @@
                                                              // format to transport packets.
                                                              // Raw byte streams are used if this
                                                              // is false.
+#define AMEDIAMETRICS_PROP_TOSTRING "toString"             // string
 #define AMEDIAMETRICS_PROP_TOTALINPUTBYTES "totalInputBytes" // int32 (MIDI)
 #define AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES "totalOutputBytes" // int32 (MIDI)
 #define AMEDIAMETRICS_PROP_THREADID       "threadId"       // int32 value io handle
@@ -243,6 +244,7 @@
 // Values are strings accepted for a given property.
 
 // An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER "applyVolumeShaper"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE      "close"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE     "create"
diff --git a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
index 652b1ee..15265bf 100644
--- a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
@@ -51,6 +51,69 @@
 
 enum DataSourceType { HTTP, FD, STREAM, FILETYPE, SOCKET, kMaxValue = SOCKET };
 
+constexpr audio_flags_mask_t kAudioFlagsMasks[] = {AUDIO_FLAG_NONE,
+                                                   AUDIO_FLAG_AUDIBILITY_ENFORCED,
+                                                   AUDIO_FLAG_SECURE,
+                                                   AUDIO_FLAG_SCO,
+                                                   AUDIO_FLAG_BEACON,
+                                                   AUDIO_FLAG_HW_AV_SYNC,
+                                                   AUDIO_FLAG_HW_HOTWORD,
+                                                   AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY,
+                                                   AUDIO_FLAG_BYPASS_MUTE,
+                                                   AUDIO_FLAG_LOW_LATENCY,
+                                                   AUDIO_FLAG_DEEP_BUFFER,
+                                                   AUDIO_FLAG_NO_MEDIA_PROJECTION,
+                                                   AUDIO_FLAG_MUTE_HAPTIC,
+                                                   AUDIO_FLAG_NO_SYSTEM_CAPTURE,
+                                                   AUDIO_FLAG_CAPTURE_PRIVATE,
+                                                   AUDIO_FLAG_CONTENT_SPATIALIZED,
+                                                   AUDIO_FLAG_NEVER_SPATIALIZE,
+                                                   AUDIO_FLAG_CALL_REDIRECTION};
+
+constexpr audio_content_type_t kAudioContentTypes[] = {
+        AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_CONTENT_TYPE_SPEECH,       AUDIO_CONTENT_TYPE_MUSIC,
+        AUDIO_CONTENT_TYPE_MOVIE,   AUDIO_CONTENT_TYPE_SONIFICATION, AUDIO_CONTENT_TYPE_ULTRASOUND};
+
+constexpr audio_source_t kAudioSources[] = {AUDIO_SOURCE_INVALID,
+                                            AUDIO_SOURCE_DEFAULT,
+                                            AUDIO_SOURCE_MIC,
+                                            AUDIO_SOURCE_VOICE_UPLINK,
+                                            AUDIO_SOURCE_VOICE_DOWNLINK,
+                                            AUDIO_SOURCE_VOICE_CALL,
+                                            AUDIO_SOURCE_CAMCORDER,
+                                            AUDIO_SOURCE_VOICE_RECOGNITION,
+                                            AUDIO_SOURCE_VOICE_COMMUNICATION,
+                                            AUDIO_SOURCE_REMOTE_SUBMIX,
+                                            AUDIO_SOURCE_UNPROCESSED,
+                                            AUDIO_SOURCE_VOICE_PERFORMANCE,
+                                            AUDIO_SOURCE_ECHO_REFERENCE,
+                                            AUDIO_SOURCE_FM_TUNER,
+                                            AUDIO_SOURCE_HOTWORD,
+                                            AUDIO_SOURCE_ULTRASOUND};
+
+constexpr audio_usage_t kAudioUsages[] = {AUDIO_USAGE_UNKNOWN,
+                                          AUDIO_USAGE_MEDIA,
+                                          AUDIO_USAGE_VOICE_COMMUNICATION,
+                                          AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                                          AUDIO_USAGE_ALARM,
+                                          AUDIO_USAGE_NOTIFICATION,
+                                          AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+                                          AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                                          AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                                          AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                                          AUDIO_USAGE_NOTIFICATION_EVENT,
+                                          AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+                                          AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                                          AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+                                          AUDIO_USAGE_GAME,
+                                          AUDIO_USAGE_VIRTUAL_SOURCE,
+                                          AUDIO_USAGE_ASSISTANT,
+                                          AUDIO_USAGE_CALL_ASSISTANT,
+                                          AUDIO_USAGE_EMERGENCY,
+                                          AUDIO_USAGE_SAFETY,
+                                          AUDIO_USAGE_VEHICLE_STATUS,
+                                          AUDIO_USAGE_ANNOUNCEMENT};
+
 constexpr PixelFormat kPixelFormat[] = {
         PIXEL_FORMAT_UNKNOWN,       PIXEL_FORMAT_NONE,        PIXEL_FORMAT_CUSTOM,
         PIXEL_FORMAT_TRANSLUCENT,   PIXEL_FORMAT_TRANSPARENT, PIXEL_FORMAT_OPAQUE,
@@ -354,7 +417,18 @@
                 [&]() { mMediaPlayer->attachAuxEffect(mFdp.ConsumeIntegral<int32_t>()); },
                 [&]() {
                     int32_t key = mFdp.PickValueInArray(kMediaParamKeys);
-                    request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
+                    request.writeInt32((audio_usage_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_USAGE_UNKNOWN, AUDIO_USAGE_ANNOUNCEMENT) /* usage */);
+                    request.writeInt32((audio_content_type_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_CONTENT_TYPE_UNKNOWN,
+                            AUDIO_CONTENT_TYPE_ULTRASOUND) /* content_type */);
+                    request.writeInt32((audio_source_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_SOURCE_INVALID, AUDIO_SOURCE_ULTRASOUND) /* source */);
+                    request.writeInt32((audio_flags_mask_t)mFdp.ConsumeIntegralInRange<int32_t>(
+                            AUDIO_FLAG_NONE, AUDIO_FLAG_CALL_REDIRECTION) /* flags */);
+                    request.writeInt32(mFdp.ConsumeBool() /* hasFlattenedTag */);
+                    request.writeString16(
+                            String16((mFdp.ConsumeRandomLengthString()).c_str()) /* tags */);
                     request.setDataPosition(0);
                     mMediaPlayer->setParameter(key, request);
                     key = mFdp.PickValueInArray(kMediaParamKeys);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 5b6848c..ac178aa 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -315,13 +315,10 @@
         "libaudioclient_aidl_conversion",
         "packagemanager_aidl-cpp",
         "server_configurable_flags",
+        "libaconfig_storage_read_api_cc",
         "aconfig_mediacodec_flags_c_lib",
     ],
 
-    defaults: [
-        "aconfig_lib_cc_static_link.defaults",
-    ],
-
     static_libs: [
         "android.media.codec-aconfig-cc",
         "libstagefright_esds",
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
index 9f46a74..b29429a 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
@@ -21,105 +21,256 @@
 #include <media/stagefright/MPEG2TSWriter.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/OggWriter.h>
-
-#include "MediaMimeTypes.h"
-
 #include <webm/WebmWriter.h>
 
 namespace android {
-std::string genMimeType(FuzzedDataProvider *dataProvider) {
-    uint8_t idx = dataProvider->ConsumeIntegralInRange<uint8_t>(0, kMimeTypes.size() - 1);
-    return std::string(kMimeTypes[idx]);
-}
 
-sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, std::string mimeType,
-                                      uint16_t maxDataAmount) {
-    uint32_t dataBlobSize = dataProvider->ConsumeIntegralInRange<uint16_t>(0, maxDataAmount);
-    std::vector<uint8_t> data = dataProvider->ConsumeBytes<uint8_t>(dataBlobSize);
-    // data:[<mediatype>][;base64],<data>
-    std::string uri("data:");
-    uri += mimeType;
-    // Currently libstagefright only accepts base64 uris
-    uri += ";base64,";
-    android::AString out;
-    android::encodeBase64(data.data(), data.size(), &out);
-    uri += out.c_str();
-
-    sp<DataSource> source =
-        DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri.c_str());
-
-    if (source == NULL) {
-        return NULL;
-    }
-
-    return MediaExtractorFactory::Create(source);
-}
-
-sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize) {
-    std::string mime = genMimeType(dataProvider);
-    sp<IMediaExtractor> extractor = genMediaExtractor(dataProvider, mime, maxMediaBlobSize);
-
-    if (extractor == NULL) {
-        return NULL;
-    }
-
-    for (size_t i = 0; i < extractor->countTracks(); ++i) {
-        sp<MetaData> meta = extractor->getTrackMetaData(i);
-
-        std::string trackMime = dataProvider->PickValueInArray(kTestedMimeTypes);
-        if (!strcasecmp(mime.c_str(), trackMime.c_str())) {
-            sp<IMediaSource> track = extractor->getTrack(i);
-            if (track == NULL) {
-                return NULL;
-            }
-            return new CallbackMediaSource(track);
-        }
-    }
-
-    return NULL;
-}
-
-sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> fileMeta) {
+sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> writerMeta,
+                             FuzzedDataProvider* fdp) {
     sp<MediaWriter> writer;
+
+    if (fdp->ConsumeBool()) {
+        writerMeta->setInt32(kKeyRealTimeRecording, fdp->ConsumeBool());
+    }
+
     switch (writerType) {
-        case OGG:
-            writer = new OggWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
-            break;
         case AAC:
-            writer = new AACWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+            writer = sp<AACWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+            }
             break;
         case AAC_ADTS:
-            writer = new AACWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
-            break;
-        case WEBM:
-            writer = new WebmWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
-            break;
-        case MPEG4:
-            writer = new MPEG4Writer(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+            writer = sp<AACWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+            }
             break;
         case AMR_NB:
-            writer = new AMRWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+            writer = sp<AMRWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+            }
             break;
         case AMR_WB:
-            writer = new AMRWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+            writer = sp<AMRWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+            }
             break;
         case MPEG2TS:
-            writer = new MPEG2TSWriter(fd);
-            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+            writer = sp<MPEG2TSWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+            }
             break;
-        default:
-            return nullptr;
+        case MPEG4:
+            writer = sp<MPEG4Writer>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+            } else if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_HEIF);
+            } else if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_THREE_GPP);
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKey2ByteNalLength, fdp->ConsumeBool());
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyTimeScale,
+                                     fdp->ConsumeIntegralInRange<int32_t>(600, 96000));
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKey4BitTrackIds, fdp->ConsumeBool());
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt64(kKeyTrackTimeStatus, fdp->ConsumeIntegral<int64_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyRotation, fdp->ConsumeIntegralInRange<uint8_t>(0, 3) * 90);
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt64(kKeyTime, fdp->ConsumeIntegral<int64_t>());
+            }
+            break;
+        case OGG:
+            writer = sp<OggWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+            }
+            break;
+        case WEBM:
+            writer = sp<WebmWriter>::make(fd);
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+            }
+
+            if (fdp->ConsumeBool()) {
+                writerMeta->setInt32(kKeyTimeScale,
+                                     fdp->ConsumeIntegralInRange<int32_t>(600, 96000));
+            }
+            break;
     }
-    if (writer != nullptr) {
-        fileMeta->setInt32(kKeyRealTimeRecording, false);
-    }
+
     return writer;
 }
+
+sp<FuzzSource> createSource(StandardWriters writerType, FuzzedDataProvider* fdp) {
+    sp<MetaData> meta = sp<MetaData>::make();
+
+    switch (writerType) {
+        case AAC:
+        case AAC_ADTS:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+            meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegralInRange<uint8_t>(1, 7));
+            meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyAACProfile, fdp->ConsumeIntegral<int32_t>());
+            }
+            break;
+        case AMR_NB:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
+            meta->setInt32(kKeyChannelCount, 1);
+            meta->setInt32(kKeySampleRate, 8000);
+            break;
+        case AMR_WB:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
+            meta->setInt32(kKeyChannelCount, 1);
+            meta->setInt32(kKeySampleRate, 16000);
+            break;
+        case MPEG2TS:
+            if (fdp->ConsumeBool()) {
+                meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+                meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+            } else {
+                meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+                // The +1s ensure a minimum height and width of 1.
+                meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+                meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+            }
+            break;
+        case MPEG4: {
+            auto mime = fdp->PickValueInArray<std::string>(kMpeg4MimeTypes);
+            meta->setCString(kKeyMIMEType, mime.c_str());
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyBackgroundMode, fdp->ConsumeBool());
+            }
+
+            if (!strncasecmp(mime.c_str(), "audio/", 6)) {
+                meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+
+            } else {
+                // The +1s ensure a minimum height and width of 1.
+                meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+                meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyDisplayWidth, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyDisplayHeight, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyTileWidth, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyTileHeight, fdp->ConsumeIntegral<uint16_t>());
+                }
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<uint8_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<uint8_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyTemporalLayerCount, fdp->ConsumeIntegral<int32_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<uint16_t>());
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<uint16_t>());
+                }
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyBitRate, fdp->ConsumeIntegral<int32_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyMaxBitRate, fdp->ConsumeIntegral<int32_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyTrackIsDefault, fdp->ConsumeBool());
+            }
+            break;
+        }
+        case OGG:
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+            }
+
+            if (fdp->ConsumeBool()) {
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+            }
+            break;
+        case WEBM:
+            if (fdp->ConsumeBool()) {
+                if (fdp->ConsumeBool()) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8);
+                } else {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP9);
+                }
+
+                if (fdp->ConsumeBool()) {
+                    // The +1s ensure a minimum height and width of 1.
+                    meta->setInt32(kKeyWidth, fdp->ConsumeIntegral<uint16_t>() + 1);
+                    meta->setInt32(kKeyHeight, fdp->ConsumeIntegral<uint16_t>() + 1);
+                }
+            } else {
+                if (fdp->ConsumeBool()) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
+                } else {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+                }
+
+                if (fdp->ConsumeBool()) {
+                    meta->setInt32(kKeyChannelCount, fdp->ConsumeIntegral<int32_t>());
+                }
+                meta->setInt32(kKeySampleRate, fdp->PickValueInArray<uint32_t>(kSampleRateTable));
+            }
+
+            break;
+    }
+
+    return sp<FuzzSource>::make(meta, fdp);
+}
 }  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
index 6856ac0..ad1218b 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
@@ -15,20 +15,52 @@
  */
 
 #pragma once
-#include <datasource/DataSourceFactory.h>
+
 #include <fuzzer/FuzzedDataProvider.h>
-#include <android/IMediaExtractor.h>
-#include <media/IMediaHTTPService.h>
-#include <media/mediarecorder.h>
-#include <media/stagefright/CallbackMediaSource.h>
+
+#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MediaWriter.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/foundation/base64.h>
-#include <utils/StrongPointer.h>
 
 namespace android {
+class FuzzSource : public MediaSource {
+  public:
+    FuzzSource(sp<MetaData> meta, FuzzedDataProvider* fdp) : mMetaData(meta), mFdp(fdp) {}
+
+    status_t start(MetaData*) { return OK; }
+
+    virtual status_t stop() { return OK; }
+
+    status_t read(MediaBufferBase** buffer, const ReadOptions*) {
+        // Ensuring that mBuffer has at least two bytes to avoid check failure
+        // in MPEG2TSWriter::SourceInfo::onMessageReceived().
+        if (mFdp->remaining_bytes() > 2) {
+            auto size = mFdp->ConsumeIntegralInRange<uint8_t>(2, INT8_MAX);
+            mBuffer = mFdp->ConsumeBytes<uint8_t>(size);
+            MediaBufferBase* mbb = new MediaBuffer(mBuffer.data(), mBuffer.size());
+
+            size_t length = mFdp->ConsumeIntegralInRange<size_t>(2, mbb->size());
+            size_t offset = mFdp->ConsumeIntegralInRange<size_t>(0, mbb->size() - length);
+            mbb->set_range(offset, length);
+
+            mbb->meta_data().setInt32(kKeyIsEndOfStream, mFdp->ConsumeBool());
+            mbb->meta_data().setInt64(kKeyTime, mFdp->ConsumeIntegral<uint32_t>() / 2);
+            *buffer = mbb;
+
+            return OK;
+        }
+
+        return ERROR_END_OF_STREAM;
+    }
+
+    sp<MetaData> getFormat() { return mMetaData; }
+
+  private:
+    sp<MetaData> mMetaData = nullptr;
+    FuzzedDataProvider* mFdp = nullptr;
+    std::vector<uint8_t> mBuffer;
+};
+
 enum StandardWriters {
     OGG,
     AAC,
@@ -42,54 +74,22 @@
     kMaxValue = MPEG2TS,
 };
 
-static std::string kTestedMimeTypes[] = {"audio/3gpp",
-                                         "audio/amr-wb",
-                                         "audio/vorbis",
-                                         "audio/opus",
-                                         "audio/mp4a-latm",
-                                         "audio/mpeg",
-                                         "audio/mpeg-L1",
-                                         "audio/mpeg-L2",
-                                         "audio/midi",
-                                         "audio/qcelp",
-                                         "audio/g711-alaw",
-                                         "audio/g711-mlaw",
-                                         "audio/flac",
-                                         "audio/aac-adts",
-                                         "audio/gsm",
-                                         "audio/ac3",
-                                         "audio/eac3",
-                                         "audio/eac3-joc",
-                                         "audio/ac4",
-                                         "audio/scrambled",
-                                         "audio/alac",
-                                         "audio/x-ms-wma",
-                                         "audio/x-adpcm-ms",
-                                         "audio/x-adpcm-dvi-ima",
-                                         "video/avc",
-                                         "video/hevc",
-                                         "video/mp4v-es",
-                                         "video/3gpp",
-                                         "video/x-vnd.on2.vp8",
-                                         "video/x-vnd.on2.vp9",
-                                         "video/av01",
-                                         "video/mpeg2",
-                                         "video/dolby-vision",
-                                         "video/scrambled",
-                                         "video/divx",
-                                         "video/divx3",
-                                         "video/xvid",
-                                         "video/x-motion-jpeg",
-                                         "text/3gpp-tt",
-                                         "application/x-subrip",
-                                         "text/vtt",
-                                         "text/cea-608",
-                                         "text/cea-708",
-                                         "application/x-id3v4"};
+static const uint32_t kSampleRateTable[] = {
+        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000,
+};
+static const std::string kMpeg4MimeTypes[] = {
+        MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, MEDIA_MIMETYPE_IMAGE_AVIF,
 
-std::string genMimeType(FuzzedDataProvider *dataProvider);
-sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, uint16_t dataAmount);
-sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize);
+        MEDIA_MIMETYPE_VIDEO_AV1,          MEDIA_MIMETYPE_VIDEO_AVC,
+        MEDIA_MIMETYPE_VIDEO_HEVC,         MEDIA_MIMETYPE_VIDEO_MPEG4,
+        MEDIA_MIMETYPE_VIDEO_H263,         MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
 
-sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> fileMeta);
+        MEDIA_MIMETYPE_AUDIO_AMR_NB,       MEDIA_MIMETYPE_AUDIO_AMR_WB,
+        MEDIA_MIMETYPE_AUDIO_AAC,
+};
+
+sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> writerMeta,
+                             FuzzedDataProvider* fdp);
+
+sp<FuzzSource> createSource(StandardWriters writerType, FuzzedDataProvider* fdp);
 }  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
index 97d1160..cd0a866 100644
--- a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
@@ -13,216 +13,49 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// Authors: corbin.souffrant@leviathansecurity.com
-//          dylan.katz@leviathansecurity.com
-
-#include <android-base/file.h>
-#include <android/content/AttributionSourceState.h>
-#include <ctype.h>
-#include <media/mediarecorder.h>
-#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <stdlib.h>
-#include <utils/StrongPointer.h>
-#include <utils/Vector.h>
-
-#include <functional>
-#include <string>
 
 #include "FuzzerMediaUtility.h"
-#include "fuzzer/FuzzedDataProvider.h"
-
-static constexpr uint16_t kMaxOperations = 5000;
-static constexpr uint8_t kMaxPackageNameLen = 50;
-// For other strings in mpeg we want a higher limit.
-static constexpr uint16_t kMaxMPEGStrLen = 1000;
-static constexpr uint16_t kMaxMediaBlobSize = 1000;
 
 namespace android {
 
-using android::content::AttributionSourceState;
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
 
-std::string getFourCC(FuzzedDataProvider *fdp) {
-    std::string fourCC = fdp->ConsumeRandomLengthString(4);
-    // Replace any existing nulls
-    for (size_t pos = 0; pos < fourCC.length(); pos++) {
-        if (fourCC.at(pos) == '\0') {
-            fourCC.replace(pos, 1, "a");
-        }
+    // memfd_create() creates an anonymous file and returns a file
+    // descriptor that refers to it. MFD_ALLOW_SEALING allows sealing
+    // operations on this file.
+    int32_t fd = memfd_create("WriterFuzzer", MFD_ALLOW_SEALING);
+    if (fd == -1) {
+        ALOGE("memfd_create() failed: %s", strerror(errno));
+        return 0;
     }
 
-    // If our string is too short, fill the remainder with "a"s.
-    while (fourCC.length() < 4) {
-        fourCC += 'a';
-    }
-    return fourCC;
-}
+    StandardWriters writerType = fdp.ConsumeEnum<StandardWriters>();
+    sp<MetaData> writerMeta = sp<MetaData>::make();
 
-typedef std::vector<std::function<void(FuzzedDataProvider*,
-                                    sp<MediaWriter>, sp<MetaData>, int tmpFileFd)>> OperationVec;
-typedef std::vector<std::function<void(FuzzedDataProvider*, MPEG4Writer*)>> MPEG4OperationVec;
-static const OperationVec operations = {
-    [](FuzzedDataProvider*, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->pause();
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
-        bool valid_fd = dataProvider->ConsumeBool();
-        int fd = -1;
-        if (valid_fd) {
-            fd = tmpFd;
-        }
-        // Args don't seem to be used
-        Vector<String16> args;
-        mediaWriter->dump(fd, args);
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
-        bool valid_fd = dataProvider->ConsumeBool();
-        int fd = -1;
-        if (valid_fd) {
-            fd = tmpFd;
-        }
-        mediaWriter->setNextFd(fd);
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setCaptureRate(dataProvider->ConsumeFloatingPoint<float>());
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setStartTimeOffsetMs(dataProvider->ConsumeIntegral<int>());
-
-        // Likely won't do much, but might as well as do a quick check
-        // while we're here.
-        mediaWriter->getStartTimeOffsetMs();
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
-    },
-    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
-        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
-    },
-};
-
-static const MPEG4OperationVec mpeg4Operations = {
-    [](FuzzedDataProvider*, MPEG4Writer *mediaWriter) { mediaWriter->notifyApproachingLimit(); },
-    // Lower level write methods.
-    // High-level startBox/endBox/etc are all called elsewhere,
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint8_t val = dataProvider->ConsumeIntegral<uint8_t>();
-        mediaWriter->writeInt8(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint16_t val = dataProvider->ConsumeIntegral<uint16_t>();
-        mediaWriter->writeInt16(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint32_t val = dataProvider->ConsumeIntegral<uint32_t>();
-        mediaWriter->writeInt32(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint64_t val = dataProvider->ConsumeIntegral<uint64_t>();
-        mediaWriter->writeInt64(val);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        std::string strVal = dataProvider->ConsumeRandomLengthString(kMaxMPEGStrLen);
-        mediaWriter->writeCString(strVal.c_str());
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        std::string fourCC = getFourCC(dataProvider);
-        mediaWriter->writeFourcc(fourCC.c_str());
-    },
-
-    // Misc setters
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint32_t layers = dataProvider->ConsumeIntegral<uint32_t>();
-        mediaWriter->setTemporalLayerCount(layers);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        uint32_t duration = dataProvider->ConsumeIntegral<uint32_t>();
-        mediaWriter->setInterleaveDuration(duration);
-    },
-    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
-        int lat = dataProvider->ConsumeIntegral<int>();
-        int lon = dataProvider->ConsumeIntegral<int>();
-        mediaWriter->setGeoData(lat, lon);
-    },
-};
-
-// Not all writers can always add new sources, so we'll need additional checks.
-void addSource(FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter) {
-    sp<MediaSource> mediaSource = genMediaSource(dataProvider, kMaxMediaBlobSize);
-    if (mediaSource == NULL) {
-        // There's a static check preventing NULLs in addSource.
-        return;
-    }
-    mediaWriter->addSource(mediaSource);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
-    FuzzedDataProvider dataProvider(data, size);
-    TemporaryFile tf;
-    sp<MetaData> fileMeta = new MetaData;
-    StandardWriters writerType = dataProvider.ConsumeEnum<StandardWriters>();
-    sp<MediaWriter> writer = createWriter(tf.fd, writerType, fileMeta);
-
-    AttributionSourceState attributionSource;
-    attributionSource.packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
-    attributionSource.uid = dataProvider.ConsumeIntegral<int32_t>();
-    attributionSource.pid = dataProvider.ConsumeIntegral<int32_t>();
-    attributionSource.token = sp<BBinder>::make();
-    sp<MediaRecorder> mr = new MediaRecorder(attributionSource);
-    writer->setListener(mr);
-
-    uint8_t baseOpLen = operations.size();
-    uint8_t totalLen = baseOpLen;
-    uint8_t maxSources;
-    // Different writers support different amounts of sources.
-    switch (writerType) {
-        case StandardWriters::AAC:
-        case StandardWriters::AAC_ADTS:
-        case StandardWriters::AMR_NB:
-        case StandardWriters::AMR_WB:
-        case StandardWriters::OGG:
-            maxSources = 1;
-            break;
-        case StandardWriters::WEBM:
-            maxSources = 2;
-            break;
-        default:
-            maxSources = UINT8_MAX;
-            break;
-    }
-    // Initialize some number of sources and add them to our writer.
-    uint8_t sourceCount = dataProvider.ConsumeIntegralInRange<uint8_t>(0, maxSources);
-    for (uint8_t i = 0; i < sourceCount; i++) {
-        addSource(&dataProvider, writer);
+    sp<MediaWriter> writer = createWriter(fd, writerType, writerMeta, &fdp);
+    if (writer == nullptr) {
+        close(fd);
+        return 0;
     }
 
-    // Increase our range if additional operations are implemented.
-    // Currently only MPEG4 has additiona public operations on their writer.
-    if (writerType == StandardWriters::MPEG4) {
-        totalLen += mpeg4Operations.size();
+    if (writerType == StandardWriters::WEBM) {
+        // This range is set to avoid CHECK failure in WEBMWriter::reset() -> EbmlVoid::EBmlVoid().
+        writer->setMaxFileSize(fdp.ConsumeIntegralInRange<int64_t>(5 * 1024 * 1024, INT64_MAX));
+    } else {
+        writer->setMaxFileSize(fdp.ConsumeIntegral<int64_t>());
     }
+    writer->setMaxFileDuration(fdp.ConsumeIntegral<int64_t>());
+    writer->setCaptureRate(fdp.ConsumeFloatingPoint<float>());
 
-    // Many operations require the writer to be started.
-    writer->start(fileMeta.get());
-    for (size_t ops_run = 0; dataProvider.remaining_bytes() > 0 && ops_run < kMaxOperations - 1;
-            ops_run++) {
-        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, totalLen - 1);
-        if (op < baseOpLen) {
-            operations[op](&dataProvider, writer, fileMeta, tf.fd);
-        } else if (writerType == StandardWriters::MPEG4) {
-            mpeg4Operations[op - baseOpLen](&dataProvider, (MPEG4Writer*)writer.get());
-        } else {
-            // Here just in case, will error out.
-            operations[op](&dataProvider, writer, fileMeta, tf.fd);
-        }
-    }
+    sp<MediaSource> source = createSource(writerType, &fdp);
+    writer->addSource(source);
+    writer->start(writerMeta.get());
+    writer->pause();
     writer->stop();
 
-    writer.clear();
-    writer = nullptr;
+    close(fd);
+
     return 0;
 }
 }  // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c1d1a63..09edf68 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -193,6 +193,7 @@
 BINDER_METHOD_ENTRY(getSoundDoseInterface) \
 BINDER_METHOD_ENTRY(getAudioPolicyConfig) \
 BINDER_METHOD_ENTRY(getAudioMixPort) \
+BINDER_METHOD_ENTRY(resetReferencesForTest) \
 
 // singleton for Binder Method Statistics for IAudioFlinger
 static auto& getIAudioFlingerStatistics() {
@@ -466,6 +467,8 @@
             sMediaLogService->unregisterWriter(iMemory);
         }
     }
+    mMediaLogNotifier->requestExit();
+    mPatchCommandThread->exit();
 }
 
 //static
@@ -4986,6 +4989,13 @@
     return NO_ERROR;
 }
 
+status_t AudioFlinger::resetReferencesForTest() {
+    mDeviceEffectManager.clear();
+    mPatchPanel.clear();
+    mMelReporter->resetReferencesForTest();
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 status_t AudioFlinger::onTransactWrapper(TransactionCode code,
@@ -5021,6 +5031,7 @@
         case TransactionCode::GET_AUDIO_POLICY_CONFIG:
         case TransactionCode::GET_AUDIO_MIX_PORT:
         case TransactionCode::SET_TRACKS_INTERNAL_MUTE:
+        case TransactionCode::RESET_REFERENCES_FOR_TEST:
             ALOGW("%s: transaction %d received from PID %d",
                   __func__, static_cast<int>(code), IPCThreadState::self()->getCallingPid());
             // return status only for non void methods
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 143a766..501aed1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -62,6 +62,8 @@
 public:
     static void instantiate() ANDROID_API;
 
+    status_t resetReferencesForTest();
+
 private:
 
     // ---- begin IAudioFlinger interface
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index 1d38306..57f4ff6 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -117,6 +117,11 @@
     }
 }
 
+void MelReporter::resetReferencesForTest() {
+    mAfMelReporterCallback.clear();
+    mSoundDoseManager->resetReferencesForTest();
+}
+
 void MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
         const IAfPatchPanel::Patch& patch) {
     if (!mSoundDoseManager->isCsdEnabled()) {
diff --git a/services/audioflinger/MelReporter.h b/services/audioflinger/MelReporter.h
index 0aeb225..8b062f3 100644
--- a/services/audioflinger/MelReporter.h
+++ b/services/audioflinger/MelReporter.h
@@ -103,6 +103,8 @@
             const std::vector<playback_track_metadata_v7_t>& metadataVec)
             EXCLUDES_AudioFlinger_Mutex;
 
+    void resetReferencesForTest();
+
 private:
     struct ActiveMelPatch {
         audio_io_handle_t streamHandle{AUDIO_IO_HANDLE_NONE};
@@ -131,7 +133,7 @@
 
     bool useHalSoundDoseInterface_l() REQUIRES(mutex());
 
-    const sp<IAfMelReporterCallback> mAfMelReporterCallback;
+    sp<IAfMelReporterCallback> mAfMelReporterCallback;
     const sp<IAfPatchPanel> mAfPatchPanel;
 
     /* const */ sp<SoundDoseManager> mSoundDoseManager;  // set onFirstRef
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 3b764d1..cdc36dc 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -753,6 +753,10 @@
     }
 }
 
+void SoundDoseManager::resetReferencesForTest() {
+    mMelReporterCallback.clear();
+}
+
 sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
         const sp<media::ISoundDoseCallback>& callback) {
     ALOGV("%s: Register ISoundDoseCallback", __func__);
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index 52a3fd6..8363d9b 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -157,6 +157,8 @@
 
     void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const override;
 
+    void resetReferencesForTest();
+
 private:
     class SoundDose : public media::BnSoundDose,
                       public IBinder::DeathRecipient {
@@ -229,7 +231,7 @@
 
     mutable std::mutex mLock;
 
-    const sp<IMelReporterCallback> mMelReporterCallback;
+    sp<IMelReporterCallback> mMelReporterCallback;
 
     // no need for lock since MelAggregator is thread-safe
     const sp<audio_utils::MelAggregator> mMelAggregator;
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index ca78ce7..3f9ae19 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -22,6 +22,7 @@
 #include <string>
 #include <string>
 #include <vector>
+#include <unordered_map>
 
 #define LOG_TAG "APM::AudioPolicyEngine/Config"
 //#define LOG_NDEBUG 0
@@ -51,6 +52,27 @@
 
 namespace {
 
+ConversionResult<std::string> aidl2legacy_AudioHalProductStrategy_ProductStrategyType(int id) {
+    using AudioProductStrategyType = media::audio::common::AudioProductStrategyType;
+
+#define STRATEGY_ENTRY(name) {static_cast<int>(AudioProductStrategyType::name), "STRATEGY_" #name}
+    static const std::unordered_map<int, std::string> productStrategyMap = {STRATEGY_ENTRY(MEDIA),
+                            STRATEGY_ENTRY(PHONE),
+                            STRATEGY_ENTRY(SONIFICATION),
+                            STRATEGY_ENTRY(SONIFICATION_RESPECTFUL),
+                            STRATEGY_ENTRY(DTMF),
+                            STRATEGY_ENTRY(ENFORCED_AUDIBLE),
+                            STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER),
+                            STRATEGY_ENTRY(ACCESSIBILITY)};
+#undef STRATEGY_ENTRY
+
+    auto it = productStrategyMap.find(id);
+    if (it == productStrategyMap.end()) {
+        return base::unexpected(BAD_VALUE);
+    }
+    return it->second;
+}
+
 ConversionResult<AttributesGroup> aidl2legacy_AudioHalAttributeGroup_AttributesGroup(
         const media::audio::common::AudioHalAttributesGroup& aidl) {
     AttributesGroup legacy;
@@ -65,7 +87,8 @@
 ConversionResult<ProductStrategy> aidl2legacy_AudioHalProductStrategy_ProductStrategy(
         const media::audio::common::AudioHalProductStrategy& aidl) {
     ProductStrategy legacy;
-    legacy.name = "strategy_" + std::to_string(aidl.id);
+    legacy.name = VALUE_OR_RETURN(
+                    aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id));
     legacy.attributesGroups = VALUE_OR_RETURN(convertContainer<AttributesGroups>(
                     aidl.attributesGroups,
                     aidl2legacy_AudioHalAttributeGroup_AttributesGroup));
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2a99fd8..6a94c81 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -8245,7 +8245,7 @@
     if (deviceTypes.empty()) {
         deviceTypes = outputDesc->devices().types();
         index = curves.getVolumeIndex(deviceTypes);
-        ALOGD("%s if deviceTypes is change from none to device %s, need get index %d",
+        ALOGV("%s if deviceTypes is change from none to device %s, need get index %d",
                 __func__, dumpDeviceTypes(deviceTypes).c_str(), index);
     }
 
diff --git a/services/audiopolicy/permission/NativePermissionController.cpp b/services/audiopolicy/permission/NativePermissionController.cpp
index 9fcf22d..8659f2c 100644
--- a/services/audiopolicy/permission/NativePermissionController.cpp
+++ b/services/audiopolicy/permission/NativePermissionController.cpp
@@ -24,9 +24,9 @@
 #include <cutils/android_filesystem_config.h>
 #include <utils/Errors.h>
 
-using ::android::base::unexpected;
 using ::android::binder::Status;
-using ::android::error::Result;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
 
 namespace com::android::media::permission {
 static std::optional<std::string> getFixedPackageName(uid_t uid) {
@@ -103,23 +103,31 @@
 
 // -- End Binder methods
 
-Result<std::vector<std::string>> NativePermissionController::getPackagesForUid(uid_t uid) const {
+BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
+        uid_t uid) const {
     uid = uid % AID_USER_OFFSET;
     const auto fixed_package_opt = getFixedPackageName(uid);
     if (fixed_package_opt.has_value()) {
-        return Result<std::vector<std::string>>{std::in_place_t{}, {fixed_package_opt.value()}};
+        return BinderResult<std::vector<std::string>>{std::in_place_t{},
+                                                      {fixed_package_opt.value()}};
     }
     std::lock_guard l{m_};
-    if (!is_package_populated_) return unexpected{::android::NO_INIT};
+    if (!is_package_populated_) {
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_STATE,
+                "NPC::getPackagesForUid: controller never populated by system_server");
+    }
     const auto cursor = package_map_.find(uid);
     if (cursor != package_map_.end()) {
         return cursor->second;
     } else {
-        return unexpected{::android::BAD_VALUE};
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_ARGUMENT,
+                ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
     }
 }
 
-Result<bool> NativePermissionController::validateUidPackagePair(
+BinderResult<bool> NativePermissionController::validateUidPackagePair(
         uid_t uid, const std::string& packageName) const {
     uid = uid % AID_USER_OFFSET;
     const auto fixed_package_opt = getFixedPackageName(uid);
@@ -127,20 +135,27 @@
         return packageName == fixed_package_opt.value();
     }
     std::lock_guard l{m_};
-    if (!is_package_populated_) return unexpected{::android::NO_INIT};
+    if (!is_package_populated_) {
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_STATE,
+                "NPC::validatedUidPackagePair: controller never populated by system_server");
+    }
     const auto cursor = package_map_.find(uid);
     return (cursor != package_map_.end()) &&
            (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
             cursor->second.end());
 }
 
-Result<bool> NativePermissionController::checkPermission(PermissionEnum perm, uid_t uid) const {
+BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
+                                                               uid_t uid) const {
     std::lock_guard l{m_};
     const auto& uids = permission_map_[static_cast<size_t>(perm)];
     if (!uids.empty()) {
         return std::binary_search(uids.begin(), uids.end(), uid);
     } else {
-        return unexpected{::android::NO_INIT};
+        return unexpectedExceptionCode(
+                Status::EX_ILLEGAL_STATE,
+                "NPC::checkPermission: controller never populated by system_server");
     }
 }
 
diff --git a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
index 2c32289..f313422 100644
--- a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
+++ b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
@@ -20,31 +20,39 @@
 #include <error/expected_utils.h>
 #include <utils/Log.h>
 
+using ::android::binder::Status;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
+
 namespace com::android::media::permission {
 
-using ::android::base::unexpected;
-
-Result<ValidatedAttributionSourceState> ValidatedAttributionSourceState::createFromBinderContext(
-        AttributionSourceState attr, const IPermissionProvider& provider) {
+BinderResult<ValidatedAttributionSourceState>
+ValidatedAttributionSourceState::createFromBinderContext(AttributionSourceState attr,
+                                                         const IPermissionProvider& provider) {
     attr.pid = ::android::IPCThreadState::self()->getCallingPid();
     attr.uid = ::android::IPCThreadState::self()->getCallingUid();
     return createFromTrustedUidNoPackage(std::move(attr), provider);
 }
 
-Result<ValidatedAttributionSourceState>
+BinderResult<ValidatedAttributionSourceState>
 ValidatedAttributionSourceState::createFromTrustedUidNoPackage(
         AttributionSourceState attr, const IPermissionProvider& provider) {
     if (attr.packageName.has_value() && attr.packageName->size() != 0) {
         if (VALUE_OR_RETURN(provider.validateUidPackagePair(attr.uid, attr.packageName.value()))) {
             return ValidatedAttributionSourceState{std::move(attr)};
         } else {
-            return unexpected{::android::PERMISSION_DENIED};
+            return unexpectedExceptionCode(Status::EX_SECURITY,
+                                           attr.toString()
+                                                   .insert(0, ": invalid attr ")
+                                                   .insert(0, __PRETTY_FUNCTION__)
+                                                   .c_str());
         }
     } else {
         // For APIs which don't appropriately pass attribution sources or packages, we need
         // to populate the package name with our best guess.
         const auto packageNames = VALUE_OR_RETURN(provider.getPackagesForUid(attr.uid));
-        LOG_ALWAYS_FATAL_IF(packageNames.empty());
+        LOG_ALWAYS_FATAL_IF(packageNames.empty(), "%s BUG: empty package list from controller",
+                            __PRETTY_FUNCTION__);
         attr.packageName = std::move(packageNames[0]);
         return ValidatedAttributionSourceState{std::move(attr)};
     }
diff --git a/services/audiopolicy/permission/include/media/IPermissionProvider.h b/services/audiopolicy/permission/include/media/IPermissionProvider.h
index 27a61ea..8d90543 100644
--- a/services/audiopolicy/permission/include/media/IPermissionProvider.h
+++ b/services/audiopolicy/permission/include/media/IPermissionProvider.h
@@ -22,7 +22,7 @@
 #include <vector>
 
 #include <com/android/media/permission/PermissionEnum.h>
-#include <error/Result.h>
+#include <error/BinderResult.h>
 
 namespace com::android::media::permission {
 
@@ -31,19 +31,20 @@
     // Get all package names which run under a certain app-id. Returns non-empty.
     // Not user specific, since packages are across users. Special app-ids (system,
     // shell, etc.) are handled.  Fails if the provider does not know about the
-    // app-id.
-    virtual ::android::error::Result<std::vector<std::string>> getPackagesForUid(
+    // app-id or if the provider has not been initialized.
+    virtual ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
             uid_t uid) const = 0;
     // True iff the provided package name runs under the app-id of uid.
     // Special app-ids (system, shell, etc.) are handled.
-    // Fails if the provider does not know about the app-id.
-    virtual ::android::error::Result<bool> validateUidPackagePair(
+    // Fails if the provider does not know about the app-id or if the provider has not been
+    // initialized.
+    virtual ::android::error::BinderResult<bool> validateUidPackagePair(
             uid_t uid, const std::string& packageName) const = 0;
 
     // True iff the uid holds the permission (user aware).
     // Fails with NO_INIT if cache hasn't been populated.
-    virtual ::android::error::Result<bool> checkPermission(PermissionEnum permission,
-                                                           uid_t uid) const = 0;
+    virtual ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+                                                                 uid_t uid) const = 0;
     virtual ~IPermissionProvider() = default;
 };
 }  // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/include/media/NativePermissionController.h b/services/audiopolicy/permission/include/media/NativePermissionController.h
index d464023..a81c7a2 100644
--- a/services/audiopolicy/permission/include/media/NativePermissionController.h
+++ b/services/audiopolicy/permission/include/media/NativePermissionController.h
@@ -24,6 +24,7 @@
 
 #include <android-base/thread_annotations.h>
 #include <com/android/media/permission/BnNativePermissionController.h>
+#include <error/BinderResult.h>
 
 namespace com::android::media::permission {
 
@@ -36,11 +37,12 @@
     Status populatePermissionState(PermissionEnum permission, const std::vector<int>& uids) final;
     // end binder methods
 
-    ::android::error::Result<std::vector<std::string>> getPackagesForUid(uid_t uid) const final;
-    ::android::error::Result<bool> validateUidPackagePair(
+    ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
+            uid_t uid) const final;
+    ::android::error::BinderResult<bool> validateUidPackagePair(
             uid_t uid, const std::string& packageName) const final;
-    ::android::error::Result<bool> checkPermission(PermissionEnum permission,
-                                                   uid_t uid) const final;
+    ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+                                                         uid_t uid) const final;
 
   private:
     mutable std::mutex m_;
diff --git a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
index 8d9da05..46f7d0a 100644
--- a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
+++ b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
@@ -17,22 +17,22 @@
 #pragma once
 
 #include <android/content/AttributionSourceState.h>
-#include <error/Result.h>
+#include <error/BinderResult.h>
 
 #include "IPermissionProvider.h"
 
 namespace com::android::media::permission {
 
 using ::android::content::AttributionSourceState;
-using ::android::error::Result;
 
 class ValidatedAttributionSourceState {
   public:
     /**
      * Validates an attribution source from within the context of a binder transaction.
-     * Overwrites the uid/pid and validates the packageName
+     * Overwrites the uid/pid and validates the packageName.
+     * Returns EX_SECURITY on package validation fail.
      */
-    static Result<ValidatedAttributionSourceState> createFromBinderContext(
+    static ::android::error::BinderResult<ValidatedAttributionSourceState> createFromBinderContext(
             AttributionSourceState attr, const IPermissionProvider& provider);
 
     /**
@@ -47,9 +47,10 @@
      * Create a ValidatedAttribubtionSourceState in cases where the uid/pid is trusted, but the
      * packages have not been validated. Proper use of the previous two methods should avoid the
      * necessity of this, but it is useful for migration purposes as well as testing this class.
+     * Returns EX_SECURITY on package validation fail.
      */
-    static Result<ValidatedAttributionSourceState> createFromTrustedUidNoPackage(
-            AttributionSourceState attr, const IPermissionProvider& provider);
+    static ::android::error::BinderResult<ValidatedAttributionSourceState>
+    createFromTrustedUidNoPackage(AttributionSourceState attr, const IPermissionProvider& provider);
 
     operator AttributionSourceState() const { return state_; }
 
diff --git a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
index 3f6b787..f2423c1 100644
--- a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
+++ b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
@@ -19,14 +19,22 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include <android-base/expected.h>
+#include <error/BinderStatusMatcher.h>
+#include <error/ExpectedMatchers.h>
 
-using ::android::base::unexpected;
-using ::android::binder::Status;
+using android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using android::binder::Status::EX_ILLEGAL_STATE;
+using android::error::BinderStatusMatcher;
+using android::error::IsErrorAnd;
+using android::error::IsOkAnd;
 using com::android::media::permission::NativePermissionController;
 using com::android::media::permission::PermissionEnum;
 using com::android::media::permission::UidPackageState;
 
+using ::testing::ElementsAre;
+using ::testing::IsFalse;
+using ::testing::IsTrue;
+
 class NativePermissionControllerTest : public ::testing::Test {
   protected:
     android::sp<NativePermissionController> holder_ =
@@ -40,50 +48,37 @@
     return out;
 }
 
-static std::vector<std::string> makeVector(const char* one) {
-    return {one};
-}
-
-static std::vector<std::string> makeVector(const char* one, const char* two) {
-    return {one, two};
-}
-
-#define UNWRAP_EQ(expr, desired_expr)                         \
-    do {                                                      \
-        auto tmp_ = (expr);                                   \
-        EXPECT_TRUE(tmp_.has_value());                        \
-        if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \
-    } while (0)
-
 // ---  Tests for non-populated ----
 TEST_F(NativePermissionControllerTest, getPackagesForUid_NotPopulated) {
     // Verify errors are returned
-    EXPECT_EQ(controller_.getPackagesForUid(10000), unexpected{android::NO_INIT});
-    EXPECT_EQ(controller_.getPackagesForUid(10001), unexpected{android::NO_INIT});
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+    EXPECT_THAT(controller_.getPackagesForUid(10001),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 
     // fixed uids should work
-    UNWRAP_EQ(controller_.getPackagesForUid(1000), makeVector("system"));
+    EXPECT_THAT(controller_.getPackagesForUid(1000), IsOkAnd(ElementsAre(std::string{"system"})));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_NotPopulated) {
     // Verify errors are returned
-    EXPECT_EQ(controller_.validateUidPackagePair(10000, "com.package"),
-              unexpected{android::NO_INIT});
+    EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.package"),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 
     // fixed uids should work
-    UNWRAP_EQ(controller_.validateUidPackagePair(1000, "system"), true);
+    EXPECT_THAT(controller_.validateUidPackagePair(1000, "system"), IsOkAnd(IsTrue()));
 }
+
 // ---  Tests for populatePackagesForUids ----
 TEST_F(NativePermissionControllerTest, populatePackages_EmptyInput) {
     std::vector<UidPackageState> input;
 
     // succeeds
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
     // Verify unknown uid behavior
-    const auto res1 = controller_.getPackagesForUid(10000);
-    ASSERT_FALSE(res1.has_value());
-    EXPECT_EQ(res1.error(), ::android::BAD_VALUE);
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
 }
 
 TEST_F(NativePermissionControllerTest, populatePackages_ValidInput) {
@@ -92,11 +87,11 @@
             createState(10001, {"com.example2.app1"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.getPackagesForUid(10000),
-              makeVector("com.example.app1", "com.example.app2"));
-    UNWRAP_EQ(controller_.getPackagesForUid(10001), makeVector("com.example2.app1"));
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+    EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
 }
 
 // --- Tests for updatePackagesForUid ---
@@ -107,14 +102,14 @@
     };
     UidPackageState newState = createState(12000, {"com.example.other"});
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
-    EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+    EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
 
     // Verify the results: only the updated package should be changed
-    UNWRAP_EQ(controller_.getPackagesForUid(10000),
-              makeVector("com.example.app1", "com.example.app2"));
-    UNWRAP_EQ(controller_.getPackagesForUid(10001), makeVector("com.example2.app1"));
-    UNWRAP_EQ(controller_.getPackagesForUid(12000), makeVector("com.example.other"));
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+    EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
+    EXPECT_THAT(controller_.getPackagesForUid(12000), IsOkAnd(ElementsAre("com.example.other")));
 }
 
 TEST_F(NativePermissionControllerTest, updatePackages_ExistingUid) {
@@ -123,14 +118,14 @@
             createState(10001, {"com.example2.app1"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
     // Update packages for existing uid
     UidPackageState newState = createState(10000, {"com.example.other", "com.example.new"});
-    EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+    EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
 
     // Verify update
-    UNWRAP_EQ(controller_.getPackagesForUid(10000),
-              makeVector("com.example.other", "com.example.new"));
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsOkAnd(ElementsAre("com.example.other", "com.example.new")));
 }
 
 TEST_F(NativePermissionControllerTest, updatePackages_EmptyRemovesEntry) {
@@ -138,15 +133,14 @@
             createState(10000, {"com.example.app1"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
     UidPackageState newState{};  // Empty package list
     newState.uid = 10000;
-    EXPECT_TRUE(controller_.updatePackagesForUid(newState).isOk());
+    EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
     // getPackages for unknown UID should error out
-    const auto res = controller_.getPackagesForUid(10000);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::BAD_VALUE);
+    EXPECT_THAT(controller_.getPackagesForUid(10000),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_ValidPair) {
@@ -154,9 +148,9 @@
             createState(10000, {"com.example.app1", "com.example.app2"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.validateUidPackagePair(10000, "com.example.app1"), true);
+    EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.app1"), IsOkAnd(IsTrue()));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_InvalidPackage) {
@@ -164,9 +158,9 @@
             createState(10000, {"com.example.app1", "com.example.app2"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.validateUidPackagePair(10000, "com.example.other"), false);
+    EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.other"), IsOkAnd(IsFalse()));
 }
 
 TEST_F(NativePermissionControllerTest, validateUidPackagePair_UnknownUid) {
@@ -174,45 +168,44 @@
             createState(10000, {"com.example.app1", "com.example.app2"}),
     };
 
-    EXPECT_TRUE(controller_.populatePackagesForUids(input).isOk());
+    EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
 
-    UNWRAP_EQ(controller_.validateUidPackagePair(12000, "any.package"), false);
+    EXPECT_THAT(controller_.validateUidPackagePair(12000, "any.package"), IsOkAnd(IsFalse()));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_InvalidPermission) {
-    EXPECT_EQ(controller_.populatePermissionState(PermissionEnum::ENUM_SIZE, {}).exceptionCode(),
-              Status::EX_ILLEGAL_ARGUMENT);
-    EXPECT_EQ(controller_
-                      .populatePermissionState(
-                              static_cast<PermissionEnum>(
-                                      static_cast<int>(PermissionEnum::ENUM_SIZE) + 1),
-                              {})
-                      .exceptionCode(),
-              Status::EX_ILLEGAL_ARGUMENT);
+    EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::ENUM_SIZE, {}),
+                BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
+    EXPECT_THAT(
+            controller_.populatePermissionState(
+                    static_cast<PermissionEnum>(static_cast<int>(PermissionEnum::ENUM_SIZE) + 1),
+                    {}),
+            BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_HoldsPermission) {
     // Unsorted
     std::vector<int> uids{3, 1, 2, 4, 5};
 
-    EXPECT_TRUE(
-            controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids).isOk());
+    EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+                BinderStatusMatcher::isOk());
 
-    EXPECT_TRUE(*controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3));
+    EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+                IsOkAnd(IsTrue()));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_DoesNotHoldPermission) {
     // Unsorted
     std::vector<int> uids{3, 1, 2, 4, 5};
 
-    EXPECT_TRUE(
-            controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids).isOk());
+    EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+                BinderStatusMatcher::isOk());
 
-    EXPECT_FALSE(*controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 6));
+    EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 6),
+                IsOkAnd(IsFalse()));
 }
 
 TEST_F(NativePermissionControllerTest, populatePermissionState_NotInitialized) {
-    const auto res = controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::NO_INIT);
+    EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 }
diff --git a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
index efc318b..0dd8814 100644
--- a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
+++ b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
@@ -20,24 +20,35 @@
 #include <gtest/gtest.h>
 
 #include <android-base/expected.h>
+#include <error/ExpectedMatchers.h>
 #include <media/IPermissionProvider.h>
+#include "error/BinderStatusMatcher.h"
 
 using ::android::base::unexpected;
 using ::android::binder::Status;
+using ::android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using ::android::binder::Status::EX_ILLEGAL_STATE;
+using ::android::binder::Status::EX_SECURITY;
 using ::android::content::AttributionSourceState;
-using ::android::error::Result;
+using ::android::error::BinderResult;
+using ::android::error::BinderStatusMatcher;
+using ::android::error::IsErrorAnd;
+using ::android::error::IsOkAnd;
 using ::com::android::media::permission::IPermissionProvider;
 using ::com::android::media::permission::PermissionEnum;
 using ::com::android::media::permission::ValidatedAttributionSourceState;
+
+using ::testing::Eq;
 using ::testing::Return;
 
 class MockPermissionProvider : public IPermissionProvider {
   public:
-    MOCK_METHOD(Result<std::vector<std::string>>, getPackagesForUid, (uid_t uid),
+    MOCK_METHOD(BinderResult<std::vector<std::string>>, getPackagesForUid, (uid_t uid),
                 (override, const));
-    MOCK_METHOD(Result<bool>, validateUidPackagePair, (uid_t uid, const std::string&),
+    MOCK_METHOD(BinderResult<bool>, validateUidPackagePair, (uid_t uid, const std::string&),
                 (override, const));
-    MOCK_METHOD(Result<bool>, checkPermission, (PermissionEnum perm, uid_t), (override, const));
+    MOCK_METHOD(BinderResult<bool>, checkPermission, (PermissionEnum perm, uid_t),
+                (override, const));
 };
 
 class ValidatedAttributionSourceStateTest : public ::testing::Test {
@@ -47,21 +58,14 @@
     const std::vector<std::string> mPackageList{"com.package1", "com.package2"};
 };
 
-#define UNWRAP_EQ(expr, desired_expr)                         \
-    do {                                                      \
-        auto tmp_ = (expr);                                   \
-        EXPECT_TRUE(tmp_.has_value());                        \
-        if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \
-    } while (0)
-
 TEST_F(ValidatedAttributionSourceStateTest, providedPackageValid) {
     const std::string package = "com.package1";
     EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(true));
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = package;
-    UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
-              attr);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsOkAnd(Eq(attr)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, providedPackageInvalid) {
@@ -70,10 +74,8 @@
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = package;
-    const auto res =
-            ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::PERMISSION_DENIED);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_SECURITY)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenMissingPackage) {
@@ -83,8 +85,8 @@
     AttributionSourceState expectedAttr;
     expectedAttr.uid = mUid;
     expectedAttr.packageName = "com.package1";
-    UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
-              expectedAttr);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsOkAnd(Eq(expectedAttr)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenEmptyPackage) {
@@ -95,33 +97,29 @@
     AttributionSourceState expectedAttr;
     expectedAttr.uid = mUid;
     expectedAttr.packageName = "com.package1";
-    UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
-              expectedAttr);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsOkAnd(Eq(expectedAttr)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, controllerNotInitialized) {
     EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
-            .WillOnce(Return(unexpected{::android::NO_INIT}));
+            .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_STATE)}));
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = std::string{};
     AttributionSourceState expectedAttr;
     expectedAttr.uid = mUid;
     expectedAttr.packageName = "com.package1";
-    const auto res =
-            ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::NO_INIT);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
 }
 
 TEST_F(ValidatedAttributionSourceStateTest, uidNotFound) {
     EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
-            .WillOnce(Return(unexpected{::android::BAD_VALUE}));
+            .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_ARGUMENT)}));
     AttributionSourceState attr;
     attr.uid = mUid;
     attr.packageName = std::string{};
-    const auto res =
-            ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider);
-    ASSERT_FALSE(res.has_value());
-    EXPECT_EQ(res.error(), ::android::BAD_VALUE);
+    EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+                IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
 }
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc
index e455378..c3be62b 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.cc
+++ b/services/camera/virtualcamera/VirtualCameraDevice.cc
@@ -68,7 +68,7 @@
 
 using namespace std::chrono_literals;
 
-// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
+// Prefix of camera name - "device@1.1/virtual/{camera_id}"
 const char* kDevicePathPrefix = "device@1.1/virtual/";
 
 constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
@@ -404,8 +404,8 @@
 }  // namespace
 
 VirtualCameraDevice::VirtualCameraDevice(
-    const uint32_t cameraId, const VirtualCameraConfiguration& configuration,
-    int32_t deviceId)
+    const std::string& cameraId,
+    const VirtualCameraConfiguration& configuration, int32_t deviceId)
     : mCameraId(cameraId),
       mVirtualCameraClientCallback(configuration.virtualCameraCallback),
       mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
@@ -582,11 +582,11 @@
 }
 
 binder_status_t VirtualCameraDevice::dump(int fd, const char**, uint32_t) {
-  ALOGD("Dumping virtual camera %d", mCameraId);
+  ALOGD("Dumping virtual camera %s", mCameraId.c_str());
   const char* indent = "  ";
   const char* doubleIndent = "    ";
-  dprintf(fd, "%svirtual_camera %d belongs to virtual device %d\n", indent,
-          mCameraId,
+  dprintf(fd, "%svirtual_camera %s belongs to virtual device %d\n", indent,
+          mCameraId.c_str(),
           getDeviceId(mCameraCharacteristics)
               .value_or(VirtualCameraService::kDefaultDeviceId));
   dprintf(fd, "%sSupportedStreamConfiguration:\n", indent);
@@ -597,7 +597,7 @@
 }
 
 std::string VirtualCameraDevice::getCameraName() const {
-  return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
+  return std::string(kDevicePathPrefix) + mCameraId;
 }
 
 const std::vector<SupportedStreamConfiguration>&
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.h b/services/camera/virtualcamera/VirtualCameraDevice.h
index 296383f..a33d4cf 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.h
+++ b/services/camera/virtualcamera/VirtualCameraDevice.h
@@ -37,7 +37,7 @@
     : public ::aidl::android::hardware::camera::device::BnCameraDevice {
  public:
   explicit VirtualCameraDevice(
-      uint32_t cameraId,
+      const std::string& cameraId,
       const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
           configuration,
       int32_t deviceId);
@@ -92,10 +92,12 @@
   binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
   // Returns unique virtual camera name in form
-  // "device@{major}.{minor}/virtual/{numerical_id}"
+  // "device@{major}.{minor}/virtual/{camera_id}"
   std::string getCameraName() const;
 
-  uint32_t getCameraId() const { return mCameraId; }
+  const std::string& getCameraId() const {
+    return mCameraId;
+  }
 
   const std::vector<
       aidl::android::companion::virtualcamera::SupportedStreamConfiguration>&
@@ -141,7 +143,7 @@
  private:
   std::shared_ptr<VirtualCameraDevice> sharedFromThis();
 
-  const uint32_t mCameraId;
+  const std::string mCameraId;
   const std::shared_ptr<
       ::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
       mVirtualCameraClientCallback;
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.cc b/services/camera/virtualcamera/VirtualCameraProvider.cc
index 67eaec0..b2c10f6 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.cc
+++ b/services/camera/virtualcamera/VirtualCameraProvider.cc
@@ -150,11 +150,10 @@
 }
 
 std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::createCamera(
-    const VirtualCameraConfiguration& configuration, const int cameraId,
-    const int32_t deviceId) {
-  if (cameraId < 0) {
-    ALOGE("%s: Cannot create camera with negative id. cameraId: %d", __func__,
-          cameraId);
+    const VirtualCameraConfiguration& configuration,
+    const std::string& cameraId, const int32_t deviceId) {
+  if (cameraId.empty()) {
+    ALOGE("%s: Cannot create camera with empty cameraId", __func__);
     return nullptr;
   }
 
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.h b/services/camera/virtualcamera/VirtualCameraProvider.h
index c536547..606b44c 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.h
+++ b/services/camera/virtualcamera/VirtualCameraProvider.h
@@ -77,7 +77,7 @@
   std::shared_ptr<VirtualCameraDevice> createCamera(
       const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
           configuration,
-      int cameraId, int32_t deviceId);
+      const std::string& cameraId, int32_t deviceId);
 
   std::shared_ptr<VirtualCameraDevice> getCamera(const std::string& name);
 
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 9a5bd1e..cd17517 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -24,6 +24,7 @@
 #include <memory>
 #include <mutex>
 #include <thread>
+#include <utility>
 #include <vector>
 
 #include "Exif.h"
@@ -78,6 +79,15 @@
 
 namespace {
 
+// helper type for the visitor
+template <class... Ts>
+struct overloaded : Ts... {
+  using Ts::operator()...;
+};
+// explicit deduction guide (not needed as of C++20)
+template <class... Ts>
+overloaded(Ts...) -> overloaded<Ts...>;
+
 using namespace std::chrono_literals;
 
 static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
@@ -89,6 +99,8 @@
 
 static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024;  // 32 KiB
 
+static constexpr UpdateTextureTask kUpdateTextureTask;
+
 CameraMetadata createCaptureResultMetadata(
     const std::chrono::nanoseconds timestamp,
     const RequestSettings& requestSettings,
@@ -287,6 +299,21 @@
       static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
 }
 
+class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
+ public:
+  FrameAvailableListenerProxy(std::function<void()> callback)
+      : mOnFrameAvailableCallback(callback) {
+  }
+
+  virtual void onFrameAvailable(const BufferItem&) override {
+    ALOGV("%s: onFrameAvailable", __func__);
+    mOnFrameAvailableCallback();
+  }
+
+ private:
+  std::function<void()> mOnFrameAvailableCallback;
+};
+
 }  // namespace
 
 CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -345,9 +372,25 @@
   return mRequestSettings;
 }
 
+void VirtualCameraRenderThread::requestTextureUpdate() {
+  std::lock_guard<std::mutex> lock(mLock);
+  // If queue is not empty, we don't need to set the mTextureUpdateRequested
+  // flag, since the texture will be updated during ProcessCaptureRequestTask
+  // processing anyway.
+  if (mQueue.empty()) {
+    mTextureUpdateRequested = true;
+    mCondVar.notify_one();
+  }
+}
+
 void VirtualCameraRenderThread::enqueueTask(
     std::unique_ptr<ProcessCaptureRequestTask> task) {
   std::lock_guard<std::mutex> lock(mLock);
+  // When enqueving process capture request task, clear the
+  // mTextureUpdateRequested flag. If this flag is set, the texture was not yet
+  // updated and it will be updated when processing ProcessCaptureRequestTask
+  // anyway.
+  mTextureUpdateRequested = false;
   mQueue.emplace_back(std::move(task));
   mCondVar.notify_one();
 }
@@ -377,8 +420,7 @@
   return mInputSurfaceFuture.get();
 }
 
-std::unique_ptr<ProcessCaptureRequestTask>
-VirtualCameraRenderThread::dequeueTask() {
+RenderThreadTask VirtualCameraRenderThread::dequeueTask() {
   std::unique_lock<std::mutex> lock(mLock);
   // Clang's thread safety analysis doesn't perform alias analysis,
   // so it doesn't support moveable std::unique_lock.
@@ -389,12 +431,20 @@
   ScopedLockAssertion lockAssertion(mLock);
 
   mCondVar.wait(lock, [this]() REQUIRES(mLock) {
-    return mPendingExit || !mQueue.empty();
+    return mPendingExit || mTextureUpdateRequested || !mQueue.empty();
   });
   if (mPendingExit) {
-    return nullptr;
+    // Render thread task with null task signals render thread to terminate.
+    return RenderThreadTask(nullptr);
   }
-  std::unique_ptr<ProcessCaptureRequestTask> task = std::move(mQueue.front());
+  if (mTextureUpdateRequested) {
+    // If mTextureUpdateRequested, it's guaranteed the queue is empty, return
+    // kUpdateTextureTask to signal we want render thread to update the texture
+    // (consume buffer from the queue).
+    mTextureUpdateRequested = false;
+    return RenderThreadTask(kUpdateTextureTask);
+  }
+  RenderThreadTask task(std::move(mQueue.front()));
   mQueue.pop_front();
   return task;
 }
@@ -409,11 +459,23 @@
       EglTextureProgram::TextureFormat::RGBA);
   mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
       mInputSurfaceSize.width, mInputSurfaceSize.height);
+  sp<FrameAvailableListenerProxy> frameAvailableListener =
+      sp<FrameAvailableListenerProxy>::make(
+          [this]() { requestTextureUpdate(); });
+  mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);
 
   mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
 
-  while (std::unique_ptr<ProcessCaptureRequestTask> task = dequeueTask()) {
-    processCaptureRequest(*task);
+  while (RenderThreadTask task = dequeueTask()) {
+    std::visit(
+        overloaded{[this](const std::unique_ptr<ProcessCaptureRequestTask>& t) {
+                     processTask(*t);
+                   },
+                   [this](const UpdateTextureTask&) {
+                     ALOGV("Idle update of the texture");
+                     mEglSurfaceTexture->updateTexture();
+                   }},
+        task);
   }
 
   // Destroy EGL utilities still on the render thread.
@@ -425,7 +487,7 @@
   ALOGV("Render thread exiting");
 }
 
-void VirtualCameraRenderThread::processCaptureRequest(
+void VirtualCameraRenderThread::processTask(
     const ProcessCaptureRequestTask& request) {
   std::chrono::nanoseconds timestamp =
       std::chrono::duration_cast<std::chrono::nanoseconds>(
@@ -688,7 +750,7 @@
     return status;
   }
 
-  PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
+  PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
                              fence);
   if (planesLock.getStatus() != OK) {
     return cameraStatus(Status::INTERNAL_ERROR);
@@ -771,8 +833,8 @@
 
   Rect viewportRect =
       viewport.value_or(Rect(framebuffer.getWidth(), framebuffer.getHeight()));
-  glViewport(viewportRect.leftTop().x, viewportRect.leftTop().y,
-             viewportRect.getWidth(), viewportRect.getHeight());
+  glViewport(viewportRect.left, viewportRect.top, viewportRect.getWidth(),
+             viewportRect.getHeight());
 
   sp<GraphicBuffer> textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
   if (textureBuffer == nullptr) {
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index b23c30c..5a5966b 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -23,6 +23,7 @@
 #include <future>
 #include <memory>
 #include <thread>
+#include <variant>
 #include <vector>
 
 #include "VirtualCameraDevice.h"
@@ -34,7 +35,6 @@
 #include "util/EglFramebuffer.h"
 #include "util/EglProgram.h"
 #include "util/EglSurfaceTexture.h"
-#include "util/MetadataUtil.h"
 #include "util/Util.h"
 
 namespace android {
@@ -94,6 +94,24 @@
   const RequestSettings mRequestSettings;
 };
 
+struct UpdateTextureTask {};
+
+struct RenderThreadTask
+    : public std::variant<std::unique_ptr<ProcessCaptureRequestTask>,
+                          UpdateTextureTask> {
+  // Allow implicit conversion to bool.
+  //
+  // Returns false, if the RenderThreadTask consist of null
+  // ProcessCaptureRequestTask, which signals that the thread should terminate.
+  operator bool() const {
+    const bool isExitSignal =
+        std::holds_alternative<std::unique_ptr<ProcessCaptureRequestTask>>(
+            *this) &&
+        std::get<std::unique_ptr<ProcessCaptureRequestTask>>(*this) == nullptr;
+    return !isExitSignal;
+  }
+};
+
 // Wraps dedicated rendering thread and rendering business with corresponding
 // input surface.
 class VirtualCameraRenderThread {
@@ -120,6 +138,12 @@
   // Stop rendering thread.
   void stop();
 
+  // Send request to render thread to update the texture.
+  // Currently queued buffers in the input surface will be consumed and the most
+  // recent buffer in the input surface will be attached to the texture), all
+  // other buffers will be returned to the buffer queue.
+  void requestTextureUpdate() EXCLUDES(mLock);
+
   // Equeue capture task for processing on render thread.
   void enqueueTask(std::unique_ptr<ProcessCaptureRequestTask> task)
       EXCLUDES(mLock);
@@ -131,13 +155,13 @@
   sp<Surface> getInputSurface();
 
  private:
-  std::unique_ptr<ProcessCaptureRequestTask> dequeueTask() EXCLUDES(mLock);
+  RenderThreadTask dequeueTask() EXCLUDES(mLock);
 
   // Rendering thread entry point.
   void threadLoop();
 
   // Process single capture request task (always called on render thread).
-  void processCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
+  void processTask(const ProcessCaptureRequestTask& captureRequestTask);
 
   // Flush single capture request task returning the error status immediately.
   void flushCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
@@ -192,6 +216,7 @@
   std::mutex mLock;
   std::deque<std::unique_ptr<ProcessCaptureRequestTask>> mQueue GUARDED_BY(mLock);
   std::condition_variable mCondVar;
+  volatile bool mTextureUpdateRequested GUARDED_BY(mLock);
   volatile bool mPendingExit GUARDED_BY(mLock);
 
   // Acquisition timestamp of last frame.
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 724ec62..7466089 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -57,12 +57,9 @@
 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 char kCameraIdPrefix[] = "v";
 constexpr int kVgaWidth = 640;
 constexpr int kVgaHeight = 480;
 constexpr int kMaxFps = 60;
@@ -79,6 +76,8 @@
        --camera_id=(ID) - override numerical ID for test camera instance
        --lens_facing=(front|back|external) - specifies lens facing for test camera instance
        --input_fps=(fps) - specify input fps for test camera, valid values are from 1 to 1000
+       --sensor_orientation=(0|90|180|270) - Clockwise angle through which the output image 
+           needs to be rotated to be upright on the device screen in its native orientation
  * disable_test_camera
 )";
 constexpr char kCreateVirtualDevicePermission[] =
@@ -90,6 +89,9 @@
     "GL_EXT_YUV_target",
 };
 
+// Numerical portion for id to assign to next created camera.
+static std::atomic_int sNextIdNumericalPortion{1000};
+
 ndk::ScopedAStatus validateConfiguration(
     const VirtualCameraConfiguration& configuration) {
   if (configuration.supportedStreamConfigs.empty()) {
@@ -192,7 +194,7 @@
   }
 
   return cmd;
-};
+}
 
 ndk::ScopedAStatus verifyRequiredEglExtensions() {
   EglDisplayContext context;
@@ -211,6 +213,11 @@
   return ndk::ScopedAStatus::ok();
 }
 
+std::string createCameraId(const int32_t deviceId) {
+  return kCameraIdPrefix + std::to_string(deviceId) + "_" +
+         std::to_string(sNextIdNumericalPortion++);
+}
+
 }  // namespace
 
 VirtualCameraService::VirtualCameraService(
@@ -224,13 +231,14 @@
     const ::ndk::SpAIBinder& token,
     const VirtualCameraConfiguration& configuration, const int32_t deviceId,
     bool* _aidl_return) {
-  return registerCamera(token, configuration, sNextId++, deviceId, _aidl_return);
+  return registerCamera(token, configuration, createCameraId(deviceId),
+                        deviceId, _aidl_return);
 }
 
 ndk::ScopedAStatus VirtualCameraService::registerCamera(
     const ::ndk::SpAIBinder& token,
-    const VirtualCameraConfiguration& configuration, const int cameraId,
-    const int32_t deviceId, bool* _aidl_return) {
+    const VirtualCameraConfiguration& configuration,
+    const std::string& cameraId, const int32_t deviceId, bool* _aidl_return) {
   if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
     ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
           getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -308,7 +316,7 @@
 }
 
 ndk::ScopedAStatus VirtualCameraService::getCameraId(
-    const ::ndk::SpAIBinder& token, int32_t* _aidl_return) {
+    const ::ndk::SpAIBinder& token, std::string* _aidl_return) {
   if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
     ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
           getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -400,13 +408,12 @@
     return STATUS_OK;
   }
 
-  std::optional<int> cameraId;
+  std::optional<std::string> cameraId;
   auto it = options.find("camera_id");
   if (it != options.end()) {
-    cameraId = parseInt(it->second);
+    cameraId = it->second;
     if (!cameraId.has_value()) {
-      dprintf(err, "Invalid camera_id: %s\n, must be number > 0",
-              it->second.c_str());
+      dprintf(err, "Invalid camera_id: %s", it->second.c_str());
       return STATUS_BAD_VALUE;
     }
   }
@@ -434,6 +441,31 @@
     }
   }
 
+  std::optional<SensorOrientation> sensorOrientation;
+  std::optional<int> sensorOrientationInt;
+  it = options.find("sensor_orientation");
+  if (it != options.end()) {
+    sensorOrientationInt = parseInt(it->second);
+    switch (sensorOrientationInt.value_or(0)) {
+      case 0:
+        sensorOrientation = SensorOrientation::ORIENTATION_0;
+        break;
+      case 90:
+        sensorOrientation = SensorOrientation::ORIENTATION_90;
+        break;
+      case 180:
+        sensorOrientation = SensorOrientation::ORIENTATION_180;
+        break;
+      case 270:
+        sensorOrientation = SensorOrientation::ORIENTATION_270;
+        break;
+      default:
+        dprintf(err, "Invalid sensor rotation: %s\n, must be 0, 90, 180 or 270.",
+                it->second.c_str());
+        return STATUS_BAD_VALUE;
+    }
+  }
+
   sp<BBinder> token = sp<BBinder>::make();
   mTestCameraToken.set(AIBinder_fromPlatformBinder(token));
 
@@ -444,10 +476,13 @@
                                                   Format::RGBA_8888,
                                                   .maxFps = kMaxFps});
   configuration.lensFacing = lensFacing.value_or(LensFacing::EXTERNAL);
+  configuration.sensorOrientation =
+      sensorOrientation.value_or(SensorOrientation::ORIENTATION_0);
   configuration.virtualCameraCallback =
       ndk::SharedRefBase::make<VirtualCameraTestInstance>(
           inputFps.value_or(kTestCameraDefaultInputFps));
-  registerCamera(mTestCameraToken, configuration, cameraId.value_or(sNextId++),
+  registerCamera(mTestCameraToken, configuration,
+                 cameraId.value_or(std::to_string(sNextIdNumericalPortion++)),
                  kDefaultDeviceId, &ret);
   if (ret) {
     dprintf(out, "Successfully registered test camera %s\n",
diff --git a/services/camera/virtualcamera/VirtualCameraService.h b/services/camera/virtualcamera/VirtualCameraService.h
index f04acb5..4ef01c7 100644
--- a/services/camera/virtualcamera/VirtualCameraService.h
+++ b/services/camera/virtualcamera/VirtualCameraService.h
@@ -50,15 +50,17 @@
       const ::ndk::SpAIBinder& token,
       const ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
           configuration,
-      int cameraId, int32_t deviceId, bool* _aidl_return) EXCLUDES(mLock);
+      const std::string& cameraId, int32_t deviceId, bool* _aidl_return)
+      EXCLUDES(mLock);
 
   // Unregisters camera corresponding to the binder token.
   ndk::ScopedAStatus unregisterCamera(const ::ndk::SpAIBinder& token) override
       EXCLUDES(mLock);
 
   // Returns the camera id corresponding to the binder token.
-  ndk::ScopedAStatus getCameraId(
-      const ::ndk::SpAIBinder& token, int32_t* _aidl_return) override EXCLUDES(mLock);
+  ndk::ScopedAStatus getCameraId(const ::ndk::SpAIBinder& token,
+                                 std::string* _aidl_return) override
+      EXCLUDES(mLock);
 
   // Returns VirtualCameraDevice corresponding to binder token or nullptr if
   // there's no camera asociated with the token.
@@ -101,9 +103,6 @@
 
   // 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/VirtualCameraSessionContext.cc b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
index 284ad05..aab2d0d 100644
--- a/services/camera/virtualcamera/VirtualCameraSessionContext.cc
+++ b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
@@ -129,7 +129,8 @@
           streamId);
     return std::optional<Stream>();
   }
-  return {it->second->getStreamConfig()};
+  VirtualCameraStream& stream = *it->second;
+  return {stream.getStreamConfig()};
 }
 
 std::shared_ptr<AHardwareBuffer> VirtualCameraSessionContext::fetchHardwareBuffer(
@@ -141,7 +142,8 @@
           streamId);
     return nullptr;
   }
-  return it->second->getHardwareBuffer(bufferId);
+  VirtualCameraStream& stream = *it->second;
+  return stream.getHardwareBuffer(bufferId);
 }
 
 std::shared_ptr<EglFrameBuffer>
@@ -154,7 +156,8 @@
           streamId);
     return nullptr;
   }
-  return it->second->getEglFrameBuffer(eglDisplay, bufferId);
+  VirtualCameraStream& stream = *it->second;
+  return stream.getEglFrameBuffer(eglDisplay, bufferId);
 }
 
 std::set<int> VirtualCameraSessionContext::getStreamIds() const {
diff --git a/services/camera/virtualcamera/VirtualCameraTestInstance.cc b/services/camera/virtualcamera/VirtualCameraTestInstance.cc
index 1eac4fe..ff4a2d8 100644
--- a/services/camera/virtualcamera/VirtualCameraTestInstance.cc
+++ b/services/camera/virtualcamera/VirtualCameraTestInstance.cc
@@ -125,10 +125,18 @@
   ALOGV("%s: streamId %d, %dx%d pixFmt=%s", __func__, streamId, width, height,
         toString(pixelFormat).c_str());
 
-  std::lock_guard<std::mutex> lock(mLock);
-  mRenderer = std::make_shared<TestPatternRenderer>(
+  auto renderer = std::make_shared<TestPatternRenderer>(
       nativeWindowFromSurface(surface), mFps);
-  mRenderer->start();
+
+  std::lock_guard<std::mutex> lock(mLock);
+  if (mInputRenderers.try_emplace(streamId, renderer).second) {
+    renderer->start();
+  } else {
+    ALOGE(
+        "%s: Input stream with id %d is already active, ignoring "
+        "onStreamConfigured call",
+        __func__, streamId);
+  }
 
   return ScopedAStatus::ok();
 }
@@ -141,10 +149,17 @@
 ScopedAStatus VirtualCameraTestInstance::onStreamClosed(const int32_t streamId) {
   ALOGV("%s: streamId %d", __func__, streamId);
 
-  std::lock_guard<std::mutex> lock(mLock);
-  if (mRenderer != nullptr) {
-    mRenderer->stop();
-    mRenderer.reset();
+  std::shared_ptr<TestPatternRenderer> renderer;
+  {
+    std::lock_guard<std::mutex> lock(mLock);
+    auto it = mInputRenderers.find(streamId);
+    if (it != mInputRenderers.end()) {
+      renderer = std::move(it->second);
+      mInputRenderers.erase(it);
+    }
+  }
+  if (renderer != nullptr) {
+    renderer->stop();
   }
   return ScopedAStatus::ok();
 }
diff --git a/services/camera/virtualcamera/VirtualCameraTestInstance.h b/services/camera/virtualcamera/VirtualCameraTestInstance.h
index 43e33d5..c130645 100644
--- a/services/camera/virtualcamera/VirtualCameraTestInstance.h
+++ b/services/camera/virtualcamera/VirtualCameraTestInstance.h
@@ -17,7 +17,7 @@
 #define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERATESTINSTANCE_H
 
 #include <atomic>
-#include <condition_variable>
+#include <map>
 #include <memory>
 #include <thread>
 
@@ -80,7 +80,10 @@
   const int mFps;
 
   std::mutex mLock;
-  std::shared_ptr<TestPatternRenderer> mRenderer GUARDED_BY(mLock);
+  // Map maintaining streamId -> TestPatternRenderer mapping for active
+  // input streams.
+  std::map<int, std::shared_ptr<TestPatternRenderer>> mInputRenderers
+      GUARDED_BY(mLock);
 };
 
 }  // namespace virtualcamera
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
index 1bd99be..2f1e2a9 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
@@ -41,5 +41,5 @@
      * Returns the camera id for a given binder token. Note that this id corresponds to the id of
      * the camera device in the camera framework.
      */
-    int getCameraId(in IBinder token);
+    @utf8InCpp String getCameraId(in IBinder token);
 }
diff --git a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
index 3fe7c11..32cd23f 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
@@ -54,11 +54,9 @@
 using metadata_stream_t =
     camera_metadata_enum_android_scaler_available_stream_configurations_t;
 
-constexpr int kCameraId = 42;
+constexpr char kCameraId[] = "42";
 constexpr int kQvgaWidth = 320;
 constexpr int kQvgaHeight = 240;
-constexpr int k360pWidth = 640;
-constexpr int k360pHeight = 360;
 constexpr int kVgaWidth = 640;
 constexpr int kVgaHeight = 480;
 constexpr int kHdWidth = 1280;
diff --git a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
index f1b2a92..d4bc6de 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
@@ -50,13 +50,12 @@
 using ::testing::Not;
 using ::testing::Return;
 
+constexpr char kCameraId[] = "42";
 constexpr int kVgaWidth = 640;
 constexpr int kVgaHeight = 480;
 constexpr int kMaxFps = 30;
-constexpr int kCameraId = 9999;
 constexpr int kDefaultDeviceId = 0;
-constexpr char kVirtualCameraNameRegex[] =
-    "device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
+constexpr char kVirtualCameraNameRegex[] = "device@[0-9]+\\.[0-9]+/virtual/.+";
 
 class MockCameraProviderCallback : public BnCameraProviderCallback {
  public:
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index 50977d8..719f64d 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -19,6 +19,7 @@
 #include <cstdio>
 #include <iterator>
 #include <memory>
+#include <optional>
 #include <regex>
 
 #include "VirtualCameraService.h"
@@ -191,6 +192,16 @@
     return getLensFacing(metadata);
   }
 
+  std::optional<int32_t> getCameraSensorOrienation(const std::string& id) {
+    std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->getCamera(id);
+    if (camera == nullptr) {
+      return std::nullopt;
+    }
+    CameraMetadata metadata;
+    camera->getCameraCharacteristics(&metadata);
+    return getSensorOrientation(metadata);
+  }
+
  protected:
   std::shared_ptr<VirtualCameraService> mCameraService;
   std::shared_ptr<VirtualCameraProvider> mCameraProvider;
@@ -390,7 +401,7 @@
 }
 
 TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) {
-  int32_t aidlRet;
+  std::string aidlRet;
   EXPECT_CALL(mMockPermissionsProxy,
               checkCallingPermission(kCreateVirtualDevicePermissions))
       .WillOnce(Return(false));
@@ -445,11 +456,13 @@
 }
 
 TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) {
-  EXPECT_THAT(execute_shell_command("enable_test_camera --camera_id=12345"),
-              Eq(NO_ERROR));
+  EXPECT_THAT(
+      execute_shell_command("enable_test_camera --camera_id=hello12345"),
+      Eq(NO_ERROR));
 
   std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
-  EXPECT_THAT(cameraIdsAfterEnable, ElementsAre("device@1.1/virtual/12345"));
+  EXPECT_THAT(cameraIdsAfterEnable,
+              ElementsAre("device@1.1/virtual/hello12345"));
 
   EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR));
 
@@ -458,9 +471,8 @@
 }
 
 TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidId) {
-  EXPECT_THAT(
-      execute_shell_command("enable_test_camera --camera_id=NotNumericalId"),
-      Eq(STATUS_BAD_VALUE));
+  EXPECT_THAT(execute_shell_command("enable_test_camera --camera_id="),
+              Eq(STATUS_BAD_VALUE));
 }
 
 TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithUnknownCommand) {
@@ -505,6 +517,24 @@
               Eq(STATUS_BAD_VALUE));
 }
 
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientation90) {
+  EXPECT_THAT(
+      execute_shell_command("enable_test_camera --sensor_orientation=90"),
+      Eq(NO_ERROR));
+
+  std::vector<std::string> cameraIds = getCameraIds();
+  ASSERT_THAT(cameraIds, SizeIs(1));
+  EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(90)));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientationNoArgs) {
+  EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR));
+
+  std::vector<std::string> cameraIds = getCameraIds();
+  ASSERT_THAT(cameraIds, SizeIs(1));
+  EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(0)));
+}
+
 }  // namespace
 }  // namespace virtualcamera
 }  // namespace companion
diff --git a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
index 93f90b4..a9eb413 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
@@ -37,6 +37,7 @@
 namespace virtualcamera {
 namespace {
 
+constexpr char kCameraId[] = "42";
 constexpr int kQvgaWidth = 320;
 constexpr int kQvgaHeight = 240;
 constexpr int kVgaWidth = 640;
@@ -46,7 +47,6 @@
 constexpr int kMaxFps = 30;
 constexpr int kStreamId = 0;
 constexpr int kSecondStreamId = 1;
-constexpr int kCameraId = 42;
 constexpr int kDefaultDeviceId = 0;
 
 using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 7de5020..c81d36d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -64,6 +64,11 @@
   return mGlConsumer->getCurrentBuffer();
 }
 
+void EglSurfaceTexture::setFrameAvailableListener(
+    const wp<ConsumerBase::FrameAvailableListener>& listener) {
+  mGlConsumer->setFrameAvailableListener(listener);
+}
+
 bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
   return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
                                     static_cast<nsecs_t>(timeout.count()));
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index b9c5126..ac3cf7d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -21,6 +21,7 @@
 #include <cstdint>
 
 #include "GLES/gl.h"
+#include "gui/ConsumerBase.h"
 #include "gui/Surface.h"
 #include "utils/RefBase.h"
 
@@ -58,6 +59,9 @@
   // Returns false on timeout, true if new frame was received before timeout.
   bool waitForNextFrame(std::chrono::nanoseconds timeout);
 
+  void setFrameAvailableListener(
+      const wp<ConsumerBase::FrameAvailableListener>& listener);
+
   // Update the texture with the most recent submitted buffer.
   // Most be called on thread with EGL context.
   //
diff --git a/services/camera/virtualcamera/util/MetadataUtil.cc b/services/camera/virtualcamera/util/MetadataUtil.cc
index 31a8776..4889830 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.cc
+++ b/services/camera/virtualcamera/util/MetadataUtil.cc
@@ -961,6 +961,20 @@
   return static_cast<int32_t>(entry.data.i32[0]);
 }
 
+std::optional<int32_t> getSensorOrientation(
+    const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+  auto metadata =
+      reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+  camera_metadata_ro_entry_t entry;
+  if (find_camera_metadata_ro_entry(metadata, ANDROID_SENSOR_ORIENTATION,
+                                    &entry) != OK) {
+    return std::nullopt;
+  }
+
+  return static_cast<int32_t>(entry.data.i32[0]);
+}
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.h b/services/camera/virtualcamera/util/MetadataUtil.h
index ca6f332..22d3657 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.h
+++ b/services/camera/virtualcamera/util/MetadataUtil.h
@@ -488,6 +488,11 @@
 std::optional<int32_t> getDeviceId(
     const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
 
+// Return the value of ANDROID_SENSOR_ORIENTATION or nullopt if the key is not
+// present (which is equivalent to a orientation of 0).
+std::optional<int32_t> getSensorOrientation(
+    const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
index c6793a9..c7b4297 100644
--- a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
@@ -17,6 +17,7 @@
  *****************************************************************************
  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
  */
+#include <binder/IPCThreadState.h>
 #include <fuzzer/FuzzedDataProvider.h>
 #include <media/MediaMetricsItem.h>
 #include <mediametricsservice/AudioTypes.h>
@@ -26,210 +27,158 @@
 #include <string.h>
 #include <utils/Log.h>
 #include <algorithm>
+#include <set>
 
 using namespace android;
+static constexpr size_t STATSD_LOG_LINES_MAX = 48;
+static unsigned long long kPackedCallingUid = (unsigned long long)AID_SYSTEM << 32;
+constexpr int8_t kMaxBytes = 100;
+constexpr int8_t kMinBytes = 0;
+constexpr size_t kMaxItemLength = 16;
 
 // low water mark
 constexpr size_t kLogItemsLowWater = 1;
 // high water mark
 constexpr size_t kLogItemsHighWater = 2;
-constexpr size_t kMaxItemLength = 16;
-constexpr size_t kMaxApis = 64;
+
+/*
+ * Concatenating strings to generate keys in such a way that the
+ * lambda function inside AudioAnalytics() added in the 'mAction' object is covered
+ */
+
+std::string keyMediaValues[] = {
+        "metrics.manager",
+        "mediadrm",
+        "audio.device.a2dp",
+        AMEDIAMETRICS_KEY_AUDIO_MIDI,
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*",
+        AMEDIAMETRICS_KEY_AUDIO_FLINGER,
+        AMEDIAMETRICS_KEY_AUDIO_POLICY,
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*",
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
+        "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent",
+};
+
+std::string keyMediaAction[] = {
+        "createAudioPatch",
+        "connected",
+        AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE,
+        AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP,
+};
 
 class MediaMetricsServiceFuzzer {
-   public:
-    void invokeStartsWith(const uint8_t *data, size_t size);
-    void invokeInstantiate(const uint8_t *data, size_t size);
-    void invokePackageInstallerCheck(const uint8_t *data, size_t size);
-    void invokeItemManipulation(const uint8_t *data, size_t size);
-    void invokeItemExpansion(const uint8_t *data, size_t size);
-    void invokeTimeMachineStorage(const uint8_t *data, size_t size);
-    void invokeTransactionLog(const uint8_t *data, size_t size);
-    void invokeAnalyticsAction(const uint8_t *data, size_t size);
-    void invokeAudioAnalytics(const uint8_t *data, size_t size);
-    void invokeTimedAction(const uint8_t *data, size_t size);
-    void process(const uint8_t *data, size_t size);
+  public:
+    MediaMetricsServiceFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+    void invokeStartsWith();
+    void invokeInstantiate();
+    void invokePackageInstallerCheck();
+    void invokeTimeMachineStorage();
+    void invokeTransactionLog();
+    void invokeAnalyticsAction();
+    void invokeAudioAnalytics();
+    void invokeTimedAction();
+    void setKeyValues(std::shared_ptr<mediametrics::Item>& item, std::string keyValue);
+    std::shared_ptr<mediametrics::Item> CreateItem();
+    sp<MediaMetricsService> mMediaMetricsService;
+    FuzzedDataProvider mFdp;
     std::atomic_int mValue = 0;
 };
 
-void MediaMetricsServiceFuzzer::invokeStartsWith(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-    while (fdp.remaining_bytes()) {
-        android::mediametrics::startsWith(fdp.ConsumeRandomLengthString(),
-                                          fdp.ConsumeRandomLengthString());
-    }
+void MediaMetricsServiceFuzzer::setKeyValues(std::shared_ptr<mediametrics::Item>& item,
+                                             std::string keyValue) {
+    auto invokeActionAPIs = mFdp.PickValueInArray<const std::function<void()>>({
+            [&]() { item->setInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
+            [&]() { item->addInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
+            [&]() { item->setInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
+            [&]() { item->addInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
+            [&]() { item->setDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
+            [&]() { item->addDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
+            [&]() { item->setTimestamp(mFdp.ConsumeIntegral<int64_t>()); },
+            [&]() {
+                std::string value = mFdp.ConsumeBool()
+                                            ? mFdp.ConsumeRandomLengthString(kMaxBytes)
+                                            : mFdp.PickValueInArray<std::string>(keyMediaAction);
+                item->setCString(keyValue.c_str(), value.c_str());
+            },
+            [&]() {
+                item->setRate(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>(),
+                              mFdp.ConsumeIntegral<int64_t>());
+            },
+            [&]() {
+                mediametrics::LogItem<1> itemTemp(mFdp.ConsumeRandomLengthString(kMaxBytes));
+                itemTemp.setPid(mFdp.ConsumeIntegral<int16_t>())
+                        .setUid(mFdp.ConsumeIntegral<int16_t>());
+
+                int32_t i = mFdp.ConsumeIntegral<int32_t>();
+                itemTemp.set(std::to_string(i).c_str(), (int32_t)i);
+                itemTemp.updateHeader();
+                (void)item->readFromByteString(itemTemp.getBuffer(), itemTemp.getLength());
+            },
+
+    });
+    invokeActionAPIs();
 }
 
-void MediaMetricsServiceFuzzer::invokeInstantiate(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-    sp mediaMetricsService = new MediaMetricsService();
-
-    while (fdp.remaining_bytes()) {
-        std::unique_ptr<mediametrics::Item> random_key(
-            mediametrics::Item::create(fdp.ConsumeRandomLengthString()));
-        mediaMetricsService->submit(random_key.get());
-        random_key->setInt32(fdp.ConsumeRandomLengthString().c_str(),
-                             fdp.ConsumeIntegral<int32_t>());
-        mediaMetricsService->submit(random_key.get());
-
-        std::unique_ptr<mediametrics::Item> audiotrack_key(
-            mediametrics::Item::create("audiotrack"));
-        mediaMetricsService->submit(audiotrack_key.get());
-        audiotrack_key->addInt32(fdp.ConsumeRandomLengthString().c_str(),
-                                 fdp.ConsumeIntegral<int32_t>());
-        mediaMetricsService->submit(audiotrack_key.get());
+std::shared_ptr<mediametrics::Item> MediaMetricsServiceFuzzer::CreateItem() {
+    std::string key;
+    if (mFdp.ConsumeBool()) {
+        key = mFdp.ConsumeRandomLengthString(kMaxItemLength);
+    } else {
+        key = mFdp.PickValueInArray<std::string>(keyMediaValues);
     }
-}
 
-void MediaMetricsServiceFuzzer::invokePackageInstallerCheck(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-    while (fdp.remaining_bytes()) {
-        MediaMetricsService::useUidForPackage(fdp.ConsumeRandomLengthString().c_str(),
-                                              fdp.ConsumeRandomLengthString().c_str());
-    }
-}
-
-void MediaMetricsServiceFuzzer::invokeItemManipulation(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
-    mediametrics::Item item(fdp.ConsumeRandomLengthString().c_str());
-    while (fdp.remaining_bytes()) {
-        const uint8_t action = fdp.ConsumeIntegralInRange<uint8_t>(0, 16);
-        const std::string key = fdp.ConsumeRandomLengthString();
-        if (fdp.remaining_bytes() < 1 || key.length() < 1) {
-            break;
+    std::shared_ptr<mediametrics::Item> item = std::make_shared<mediametrics::Item>(key.c_str());
+    size_t numKeys = mFdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes);
+    std::set<std::string> keySet;
+    for (size_t i = 0; i < numKeys; ++i) {
+        std::string keyValue;
+        if (mFdp.ConsumeBool()) {
+            keyValue = mFdp.ConsumeRandomLengthString(kMaxBytes);
+        } else {
+            keyValue = mFdp.PickValueInArray<std::string>(
+                    {AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_STATE, "logSessionIkeyd"});
         }
-        switch (action) {
-            case 0: {
-                item.setInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
-                break;
-            }
-            case 1: {
-                item.addInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
-                break;
-            }
-            case 2: {
-                int32_t i32 = 0;
-                item.getInt32(key.c_str(), &i32);
-                break;
-            }
-            case 3: {
-                item.setInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
-                break;
-            }
-            case 4: {
-                item.addInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
-                break;
-            }
-            case 5: {
-                int64_t i64 = 0;
-                item.getInt64(key.c_str(), &i64);
-                break;
-            }
-            case 6: {
-                item.setDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
-                break;
-            }
-            case 7: {
-                item.addDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
-                break;
-            }
-            case 8: {
-                double d = 0;
-                item.getDouble(key.c_str(), &d);
-                break;
-            }
-            case 9: {
-                item.setCString(key.c_str(), fdp.ConsumeRandomLengthString().c_str());
-                break;
-            }
-            case 10: {
-                char *s = nullptr;
-                item.getCString(key.c_str(), &s);
-                if (s) free(s);
-                break;
-            }
-            case 11: {
-                std::string s;
-                item.getString(key.c_str(), &s);
-                break;
-            }
-            case 12: {
-                item.setRate(key.c_str(), fdp.ConsumeIntegral<int64_t>(),
-                             fdp.ConsumeIntegral<int64_t>());
-                break;
-            }
-            case 13: {
-                int64_t b = 0, h = 0;
-                double d = 0;
-                item.getRate(key.c_str(), &b, &h, &d);
-                break;
-            }
-            case 14: {
-                (void)item.filter(key.c_str());
-                break;
-            }
-            case 15: {
-                const char *arr[1] = {""};
-                arr[0] = const_cast<char *>(key.c_str());
-                (void)item.filterNot(1, arr);
-                break;
-            }
-            case 16: {
-                (void)item.toString().c_str();
-                break;
-            }
+        if (keySet.find(keyValue) == keySet.end()) {
+            setKeyValues(item, keyValue);
+            keySet.insert(keyValue);
         }
     }
-
-    Parcel p;
-    mediametrics::Item item2;
-
-    (void)item.writeToParcel(&p);
-    p.setDataPosition(0);  // rewind for reading
-    (void)item2.readFromParcel(p);
-
-    char *byteData = nullptr;
-    size_t length = 0;
-    (void)item.writeToByteString(&byteData, &length);
-    (void)item2.readFromByteString(byteData, length);
-    if (byteData) {
-        free(byteData);
-    }
-
-    sp mediaMetricsService = new MediaMetricsService();
-    mediaMetricsService->submit(&item2);
+    return item;
 }
 
-void MediaMetricsServiceFuzzer::invokeItemExpansion(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
-    mediametrics::LogItem<1> item("FuzzItem");
-    item.setPid(fdp.ConsumeIntegral<int16_t>()).setUid(fdp.ConsumeIntegral<int16_t>());
-
-    while (fdp.remaining_bytes()) {
-        int32_t i = fdp.ConsumeIntegral<int32_t>();
-        item.set(std::to_string(i).c_str(), (int32_t)i);
-    }
-    item.updateHeader();
-
-    mediametrics::Item item2;
-    (void)item2.readFromByteString(item.getBuffer(), item.getLength());
-
-    sp mediaMetricsService = new MediaMetricsService();
-    mediaMetricsService->submit(&item2);
+void MediaMetricsServiceFuzzer::invokeStartsWith() {
+    android::mediametrics::startsWith(mFdp.ConsumeRandomLengthString(kMaxBytes),
+                                      mFdp.ConsumeRandomLengthString(kMaxBytes));
 }
 
-void MediaMetricsServiceFuzzer::invokeTimeMachineStorage(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeInstantiate() {
+    auto item = CreateItem();
+    mMediaMetricsService->submit(item.get());
+}
 
-    auto item = std::make_shared<mediametrics::Item>("FuzzKey");
-    int32_t i32 = fdp.ConsumeIntegral<int32_t>();
-    int64_t i64 = fdp.ConsumeIntegral<int64_t>();
-    double d = fdp.ConsumeFloatingPoint<double>();
-    std::string str = fdp.ConsumeRandomLengthString();
-    std::pair<int64_t, int64_t> pair(fdp.ConsumeIntegral<int64_t>(),
-                                     fdp.ConsumeIntegral<int64_t>());
+void MediaMetricsServiceFuzzer::invokePackageInstallerCheck() {
+    MediaMetricsService::useUidForPackage(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str(),
+                                          mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
+}
+
+void MediaMetricsServiceFuzzer::invokeTimeMachineStorage() {
+    auto item = CreateItem();
+    int32_t i32 = mFdp.ConsumeIntegral<int32_t>();
+    int64_t i64 = mFdp.ConsumeIntegral<int64_t>();
+    double d = mFdp.ConsumeFloatingPoint<double>();
+    std::string str = mFdp.ConsumeRandomLengthString(kMaxBytes);
+    std::pair<int64_t, int64_t> pair(mFdp.ConsumeIntegral<int64_t>(),
+                                     mFdp.ConsumeIntegral<int64_t>());
     (*item).set("i32", i32).set("i64", i64).set("double", d).set("string", str).set("rate", pair);
 
     android::mediametrics::TimeMachine timeMachine;
@@ -253,124 +202,89 @@
     timeMachine.get("Key.string", &str, -1);
 }
 
-void MediaMetricsServiceFuzzer::invokeTransactionLog(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
-    auto item = std::make_shared<mediametrics::Item>("Key1");
-    (*item)
-        .set("one", fdp.ConsumeIntegral<int32_t>())
-        .set("two", fdp.ConsumeIntegral<int32_t>())
-        .setTimestamp(fdp.ConsumeIntegral<int32_t>());
+void MediaMetricsServiceFuzzer::invokeTransactionLog() {
+    auto item = CreateItem();
 
     android::mediametrics::TransactionLog transactionLog(
         kLogItemsLowWater, kLogItemsHighWater);  // keep at most 2 items
     transactionLog.size();
 
     transactionLog.put(item);
-    transactionLog.size();
-
-    auto item2 = std::make_shared<mediametrics::Item>("Key2");
-    (*item2)
-        .set("three", fdp.ConsumeIntegral<int32_t>())
-        .set("[Key1]three", fdp.ConsumeIntegral<int32_t>())
-        .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-
-    transactionLog.put(item2);
-    transactionLog.size();
-
-    auto item3 = std::make_shared<mediametrics::Item>("Key3");
-    (*item3)
-        .set("six", fdp.ConsumeIntegral<int32_t>())
-        .set("[Key1]four", fdp.ConsumeIntegral<int32_t>())  // affects Key1
-        .set("[Key1]five", fdp.ConsumeIntegral<int32_t>())  // affects key1
-        .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-
-    transactionLog.put(item3);
-    transactionLog.size();
 }
 
-void MediaMetricsServiceFuzzer::invokeAnalyticsAction(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-
+void MediaMetricsServiceFuzzer::invokeAnalyticsAction() {
     mediametrics::AnalyticsActions analyticsActions;
     bool action = false;
 
-    while (fdp.remaining_bytes()) {
-        analyticsActions.addAction(
-            (fdp.ConsumeRandomLengthString() + std::string(".event")).c_str(),
-            fdp.ConsumeRandomLengthString(),
+    analyticsActions.addAction(
+            (mFdp.ConsumeRandomLengthString(kMaxBytes) + std::string(".event")).c_str(),
+            mFdp.ConsumeRandomLengthString(kMaxBytes),
             std::make_shared<mediametrics::AnalyticsActions::Function>(
-                [&](const std::shared_ptr<const android::mediametrics::Item> &) {
-                    action = true;
-                }));
-    }
+                    [&](const std::shared_ptr<const android::mediametrics::Item>&) {
+                        action = true;
+                    }));
 
-    FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size);
-    size_t apiCount = 0;
-    while (fdp2.remaining_bytes() && ++apiCount <= kMaxApis) {
-        // make a test item
-        auto item = std::make_shared<mediametrics::Item>(
-                fdp2.ConsumeRandomLengthString(kMaxItemLength).c_str());
-        (*item).set("event", fdp2.ConsumeRandomLengthString().c_str());
+    // make a test item
+    auto item = CreateItem();
+    (*item).set("event", mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
 
-        // get the actions and execute them
-        auto actions = analyticsActions.getActionsForItem(item);
-        for (const auto &action : actions) {
-            action->operator()(item);
+    // get the actions and execute them
+    auto actions = analyticsActions.getActionsForItem(item);
+    for (const auto& action : actions) {
+        action->operator()(item);
         }
-    }
 }
 
-void MediaMetricsServiceFuzzer::invokeAudioAnalytics(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeAudioAnalytics() {
+    int32_t maxLogLine = mFdp.ConsumeIntegralInRange<int32_t>(0, STATSD_LOG_LINES_MAX);
     std::shared_ptr<android::mediametrics::StatsdLog> statsdLog =
-            std::make_shared<android::mediametrics::StatsdLog>(10);
+            std::make_shared<android::mediametrics::StatsdLog>(maxLogLine);
     android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
 
-    while (fdp.remaining_bytes()) {
-        auto item = std::make_shared<mediametrics::Item>(fdp.ConsumeRandomLengthString().c_str());
-        int32_t transactionUid = fdp.ConsumeIntegral<int32_t>();  // arbitrary
-        (*item)
-            .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
-            .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
-            .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
-            .setUid(transactionUid)
-            .setTimestamp(fdp.ConsumeIntegral<int32_t>());
-        audioAnalytics.submit(item, fdp.ConsumeBool());
+    auto item = CreateItem();
+    Parcel parcel;
+    item->writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    if (mFdp.ConsumeBool()) {
+        item->readFromParcel(parcel);
     }
-
-    audioAnalytics.dump(1000);
+    audioAnalytics.submit(item, mFdp.ConsumeBool());
 }
 
-void MediaMetricsServiceFuzzer::invokeTimedAction(const uint8_t *data, size_t size) {
-    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+void MediaMetricsServiceFuzzer::invokeTimedAction() {
     android::mediametrics::TimedAction timedAction;
+    timedAction.postIn(std::chrono::seconds(mFdp.ConsumeIntegral<uint32_t>()),
+                       [this] { ++mValue; });
+    timedAction.size();
+}
 
-    while (fdp.remaining_bytes()) {
-        timedAction.postIn(std::chrono::seconds(fdp.ConsumeIntegral<int32_t>()),
-                           [this] { ++mValue; });
-        timedAction.size();
+void MediaMetricsServiceFuzzer::process() {
+    mMediaMetricsService = sp<MediaMetricsService>::make();
+
+    if (mFdp.ConsumeBool()) {
+        IPCThreadState::self()->restoreCallingIdentity(kPackedCallingUid);
+    } else {
+        IPCThreadState::self()->restoreCallingIdentity(mFdp.ConsumeIntegral<size_t>());
+    }
+    while (mFdp.remaining_bytes()) {
+        auto invokeAPIs = mFdp.PickValueInArray<const std::function<void()>>({
+                [&]() { invokeStartsWith(); },
+                [&]() { invokeInstantiate(); },
+                [&]() { invokePackageInstallerCheck(); },
+                [&]() { invokeTimeMachineStorage(); },
+                [&]() { invokeTransactionLog(); },
+                [&]() { invokeAudioAnalytics(); },
+                [&]() { invokeTimedAction(); },
+        });
+        invokeAPIs();
     }
 }
 
-void MediaMetricsServiceFuzzer::process(const uint8_t *data, size_t size) {
-    invokeStartsWith(data, size);
-    invokeInstantiate(data, size);
-    invokePackageInstallerCheck(data, size);
-    invokeItemManipulation(data, size);
-    invokeItemExpansion(data, size);
-    invokeTimeMachineStorage(data, size);
-    invokeTransactionLog(data, size);
-    invokeAnalyticsAction(data, size);
-    invokeAudioAnalytics(data, size);
-    invokeTimedAction(data, size);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     if (size < 1) {
         return 0;
     }
-    MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer;
-    mediaMetricsServiceFuzzer.process(data, size);
+    MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer(data, size);
+    mediaMetricsServiceFuzzer.process();
     return 0;
 }
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 4e46bbf..20a5ea8 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -398,6 +398,7 @@
 }
 
 // implement Runnable, periodically send timestamps to client and process commands from queue.
+// Enter standby mode if idle for a while.
 __attribute__((no_sanitize("integer")))
 void AAudioServiceStreamBase::run() {
     ALOGD("%s() %s entering >>>>>>>>>>>>>> COMMANDS", __func__, getTypeText());
@@ -406,6 +407,7 @@
     TimestampScheduler timestampScheduler;
     int64_t nextTimestampReportTime;
     int64_t nextDataReportTime;
+    // When to try to enter standby.
     int64_t standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
     // Balance the incStrong from when the thread was launched.
     holdStream->decStrong(nullptr);
@@ -417,28 +419,26 @@
     int32_t loopCount = 0;
     while (mThreadEnabled.load()) {
         loopCount++;
-        int64_t timeoutNanos = -1;
-        if (isDisconnected_l()) {
-            if (!isStandby_l()) {
-                // If the stream is disconnected but not in standby mode, wait until standby time.
+        int64_t timeoutNanos = -1; // wait forever
+        if (isDisconnected_l() || isIdle_l()) {
+            if (isStandbyImplemented() && !isStandby_l()) {
+                // If not in standby mode, wait until standby time.
                 timeoutNanos = standbyTime - AudioClock::getNanoseconds();
                 timeoutNanos = std::max<int64_t>(0, timeoutNanos);
-            } // else {
-                // If the stream is disconnected and in standby mode, keep `timeoutNanos` as
-                // -1 to wait forever until next command as the stream can only be closed.
-            // }
-        } else if (isRunning() || (isIdle_l() && !isStandby_l())) {
-            timeoutNanos = (isRunning() ? std::min(nextTimestampReportTime, nextDataReportTime)
-                                        : standbyTime) - AudioClock::getNanoseconds();
+            }
+            // Otherwise, keep `timeoutNanos` as -1 to wait forever until next command.
+        } else if (isRunning()) {
+            timeoutNanos = std::min(nextTimestampReportTime, nextDataReportTime)
+                    - AudioClock::getNanoseconds();
             timeoutNanos = std::max<int64_t>(0, timeoutNanos);
         }
-
         auto command = mCommandQueue.waitForCommand(timeoutNanos);
         if (!mThreadEnabled) {
             // Break the loop if the thread is disabled.
             break;
         }
 
+        // Is it time to send timestamps?
         if (isRunning() && !isDisconnected_l()) {
             auto currentTimestamp = AudioClock::getNanoseconds();
             if (currentTimestamp >= nextDataReportTime) {
@@ -454,19 +454,24 @@
                 nextTimestampReportTime = timestampScheduler.nextAbsoluteTime();
             }
         }
-        if ((isIdle_l() || isDisconnected_l()) && AudioClock::getNanoseconds() >= standbyTime) {
+
+        // Is it time to enter standby?
+        if ((isIdle_l() || isDisconnected_l())
+                && isStandbyImplemented()
+                && !isStandby_l()
+                && (AudioClock::getNanoseconds() >= standbyTime)) {
+            ALOGD("%s() call standby_l(), %d loops", __func__, loopCount);
             aaudio_result_t result = standby_l();
             if (result != AAUDIO_OK) {
-                // If standby failed because of the function is not implemented, there is no
-                // need to retry. Otherwise, retry standby later.
-                ALOGW("Failed to enter standby, error=%d", result);
-                standbyTime = result == AAUDIO_ERROR_UNIMPLEMENTED
-                        ? std::numeric_limits<int64_t>::max()
-                        : AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
+                ALOGW("Failed to enter standby, error = %d", result);
+                // Try again later.
+                standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
             }
         }
 
         if (command != nullptr) {
+            ALOGD("%s() got COMMAND opcode %d after %d loops",
+                    __func__, command->operationCode, loopCount);
             std::scoped_lock<std::mutex> _commandLock(command->lock);
             switch (command->operationCode) {
                 case START:
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 8057f87..20737bc 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -316,9 +316,14 @@
         mDisconnected = flag;
     }
 
+    // If you implemented this method then please also override isStandbyImplemented().
     virtual aaudio_result_t standby_l() REQUIRES(mLock) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
+    virtual bool isStandbyImplemented() {
+        return false;
+    }
+
     class ExitStandbyParam : public AAudioCommandParam {
     public:
         explicit ExitStandbyParam(AudioEndpointParcelable* parcelable)
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index f4ce83d..f20ea10 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -73,6 +73,9 @@
     aaudio_result_t stop_l() REQUIRES(mLock) override;
 
     aaudio_result_t standby_l() REQUIRES(mLock) override;
+    bool isStandbyImplemented() override {
+        return true;
+    }
 
     aaudio_result_t exitStandby_l(AudioEndpointParcelable* parcelable) REQUIRES(mLock) override;