Merge "AAudio: Improve buffer size calculations" into main
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index 5b10794..ee1a2c8 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -21,14 +21,16 @@
     name: "com.android.media.audioserver-aconfig-cc",
     aconfig_declarations: "com.android.media.audioserver-aconfig",
     defaults: ["audio-aconfig-cc-defaults"],
-
-    // TODO(b/308061678) remove vndk dependency
     double_loadable: true,
+    host_supported: true,
     product_available: true,
     vendor_available: true,
     apex_available: [
         "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
     ],
+    min_sdk_version: "29",
 }
 
 cc_aconfig_library {
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
index 6e05abc..ae0457f 100644
--- a/media/libaudiofoundation/AudioPort.cpp
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -57,14 +57,21 @@
 
 void AudioPort::importAudioPort(const audio_port_v7 &port) {
     for (size_t i = 0; i < port.num_audio_profiles; ++i) {
+        if (port.audio_profiles[i].format == AUDIO_FORMAT_DEFAULT) {
+            // The dynamic format from AudioPort should not be AUDIO_FORMAT_DEFAULT.
+            continue;
+        }
         sp<AudioProfile> profile = new AudioProfile(port.audio_profiles[i].format,
                 ChannelMaskSet(port.audio_profiles[i].channel_masks,
                         port.audio_profiles[i].channel_masks +
-                        port.audio_profiles->num_channel_masks),
+                        port.audio_profiles[i].num_channel_masks),
                 SampleRateSet(port.audio_profiles[i].sample_rates,
                         port.audio_profiles[i].sample_rates +
                         port.audio_profiles[i].num_sample_rates),
                 port.audio_profiles[i].encapsulation_type);
+        profile->setDynamicFormat(true);
+        profile->setDynamicChannels(true);
+        profile->setDynamicRate(true);
         if (!mProfiles.contains(profile)) {
             addAudioProfile(profile);
         }
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
index ff0c32b..49e6827 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
@@ -51,6 +51,7 @@
 status_t AidlConversionSpatializer::getParameter(EffectParamWriter& param) {
     DefaultExtension defaultExt;
     // read parameters into DefaultExtension vector<uint8_t>
+    defaultExt.bytes.resize(param.getParameterSize());
     if (OK != param.readFromParameter(defaultExt.bytes.data(), param.getParameterSize())) {
         ALOGE("%s invalid param %s", __func__, param.toString().c_str());
         param.setStatus(BAD_VALUE);
diff --git a/media/libstagefright/VideoRenderQualityTracker.cpp b/media/libstagefright/VideoRenderQualityTracker.cpp
index 90d5405..aca20a4 100644
--- a/media/libstagefright/VideoRenderQualityTracker.cpp
+++ b/media/libstagefright/VideoRenderQualityTracker.cpp
@@ -28,6 +28,7 @@
 #include <cmath>
 #include <stdio.h>
 #include <sys/time.h>
+#include <sys/wait.h>
 
 #include <android-base/macros.h>
 #include <android-base/parsebool.h>
@@ -801,19 +802,28 @@
 void VideoRenderQualityTracker::triggerTrace() {
     // Trigger perfetto to stop always-on-tracing (AOT) to collect trace into a file for video
     // freeze event, the collected trace categories are configured by AOT.
-    const char* args[] = {"/system/bin/trigger_perfetto", "com.android.codec-video-freeze", NULL};
+    static const char* args[] = {"/system/bin/trigger_perfetto",
+                                 "com.android.codec-video-freeze", NULL};
+
     pid_t pid = fork();
     if (pid < 0) {
         ALOGI("Failed to fork for triggering trace");
-        return;
-    }
-    if (pid == 0) {
-        // child process.
+    } else if (pid == 0) {
+        // Child process.
+        ALOGI("Trigger trace %s", args[1]);
         execvp(args[0], const_cast<char**>(args));
         ALOGW("Failed to trigger trace %s", args[1]);
         _exit(1);
+    } else {
+        // Parent process.
+        int status;
+        // Wait for the child process (pid) gets terminated, and allow the system to release
+        // the resource associated with the child. Or the child process will remain in a
+        // zombie state and get killed by llkd to cause foreground app crash.
+        if (waitpid(pid, &status, 0) < 0) {
+            ALOGW("Failed to waitpid for triggering trace");
+        }
     }
-    ALOGI("Triggered trace %s", args[1]);
 }
 
 } // namespace android
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index c82a303..959f43e 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -102,6 +102,21 @@
 
 namespace android {
 
+static bool isValidOmxParamSize(const void *params, OMX_U32 size) {
+    // expect the vector to contain at least the size and version, two OMX_U32 entries.
+    if (size < 2 * sizeof(OMX_U32)) {
+        return false;
+    }
+
+    // expect the vector to be as large as the declared size
+    OMX_U32 *buf = (OMX_U32 *)params;
+    OMX_U32 declaredSize = *(OMX_U32*)buf;
+    if (declaredSize > size) {
+        return false;
+    }
+    return true;
+}
+
 struct BufferMeta {
     explicit BufferMeta(
             const sp<IMemory> &mem, const sp<IHidlMemory> &hidlMemory,
@@ -688,6 +703,18 @@
 
 status_t OMXNodeInstance::getParameter(
         OMX_INDEXTYPE index, void *params, size_t size) {
+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
+    if (extIndex == OMX_IndexParamConsumerUsageBits) {
+        // expect the size to be 4 bytes for OMX_IndexParamConsumerUsageBits
+        if (size != sizeof(OMX_U32)) {
+            return BAD_VALUE;
+        }
+    } else {
+        if (!isValidOmxParamSize(params, size)) {
+            return BAD_VALUE;
+        }
+    }
+
     Mutex::Autolock autoLock(mLock);
     if (mHandle == NULL) {
         return DEAD_OBJECT;
@@ -699,7 +726,6 @@
     }
 
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
-    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     // some errors are expected for getParameter
     if (err != OMX_ErrorNoMore) {
         CLOG_IF_ERROR(getParameter, err, "%s(%#x)", asString(extIndex), index);
@@ -710,6 +736,10 @@
 
 status_t OMXNodeInstance::setParameter(
         OMX_INDEXTYPE index, const void *params, size_t size) {
+    if (!isValidOmxParamSize(params, size)) {
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
     if (mHandle == NULL) {
         return DEAD_OBJECT;
@@ -736,6 +766,9 @@
 
 status_t OMXNodeInstance::getConfig(
         OMX_INDEXTYPE index, void *params, size_t size) {
+    if (!isValidOmxParamSize(params, size)) {
+        return BAD_VALUE;
+    }
     Mutex::Autolock autoLock(mLock);
     if (mHandle == NULL) {
         return DEAD_OBJECT;
@@ -759,6 +792,10 @@
 
 status_t OMXNodeInstance::setConfig(
         OMX_INDEXTYPE index, const void *params, size_t size) {
+    if (!isValidOmxParamSize(params, size)) {
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
     if (mHandle == NULL) {
         return DEAD_OBJECT;
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index e853da9..4183023 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -616,6 +616,10 @@
                 DescribeHDR10PlusInfoParams* outParams =
                         (DescribeHDR10PlusInfoParams *)params;
 
+                if (!isValidOMXParam(outParams)) {
+                    return OMX_ErrorBadParameter;
+                }
+
                 outParams->nParamSizeUsed = info->size();
 
                 // If the buffer provided by the client does not have enough
@@ -694,6 +698,10 @@
             const DescribeHDR10PlusInfoParams* inParams =
                     (DescribeHDR10PlusInfoParams *)params;
 
+            if (!isValidOMXParam(inParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
             if (*frameConfig) {
                 // This is a request to append to the current frame config set.
                 // For now, we only support kDescribeHdr10PlusInfoIndex, which
diff --git a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
index 3b70636..78140dd 100644
--- a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
+++ b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
@@ -298,7 +298,7 @@
     Configuration::GetServerConfigurableFlagFn getServerConfigurableFlagFn{
         [](const std::string &, const std::string &flag, const std::string &) -> std::string {
             if (flag == "render_metrics_enabled") {
-                return "false";
+                return "true";
             } else if (flag == "render_metrics_are_skipped_frames_dropped") {
                 return "false";
             } else if (flag == "render_metrics_max_expected_content_frame_duration_us") {
@@ -349,7 +349,7 @@
     // default - if we are accidentally configuring to the default then we're not necessarily
     // testing the parsing.
     Configuration d;
-    EXPECT_EQ(c.enabled, false);
+    EXPECT_EQ(c.enabled, true);
     EXPECT_NE(c.enabled, d.enabled);
     EXPECT_EQ(c.areSkippedFramesDropped, false);
     EXPECT_NE(c.areSkippedFramesDropped, d.areSkippedFramesDropped);
@@ -407,6 +407,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, countsReleasedFrames) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c);
     h.drop(10);
     h.render({16.66, 16.66, 16.66});
@@ -418,6 +419,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, countsSkippedFrames) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c);
     h.drop(10); // dropped frames are not counted
     h.skip(10); // frames skipped before rendering a frame are not counted
@@ -432,6 +434,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSkippedFramesAreDropped_countsDroppedFrames) {
     Configuration c;
+    c.enabled = true;
     c.areSkippedFramesDropped = true;
     Helper h(16.66, c);
     h.skip(10); // skipped frames at the beginning of playback are not counted
@@ -448,6 +451,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenNotSkippedFramesAreDropped_countsDroppedFrames) {
     Configuration c;
+    c.enabled = true;
     c.areSkippedFramesDropped = false;
     Helper h(16.66, c);
     h.skip(10); // skipped frames at the beginning of playback are not counted
@@ -464,6 +468,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, countsRenderedFrames) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c);
     h.drop(10); // dropped frames are not counted
     h.render({16.66, 16.66, 16.66});
@@ -475,6 +480,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, detectsFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -484,6 +490,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, handlesSeeking) {
     Configuration c;
+    c.enabled = true;
     c.maxExpectedContentFrameDurationUs = 30;
     VideoRenderQualityTracker v(c);
     v.onFrameReleased(0, 0);
@@ -522,6 +529,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, withSkipping_handlesSeeking) {
     Configuration c;
+    c.enabled = true;
     c.maxExpectedContentFrameDurationUs = 30;
     VideoRenderQualityTracker v(c);
     v.onFrameReleased(0, 0);
@@ -558,6 +566,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenLowTolerance_doesntDetectFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 0;
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -567,6 +576,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenFrameRateDestabilizes_detectsFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -577,6 +587,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, detects32Pulldown) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(41.66, c);
     h.render({49.9, 33.2, 50.0, 33.4, 50.1, 33.2});
@@ -586,6 +597,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBad32Pulldown_doesntDetect32Pulldown) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(41.66, c);
     h.render({50.0, 33.33, 33.33, 50.00, 33.33, 50.00});
@@ -595,6 +607,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenFrameRateChanges_detectsMostRecentFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -608,6 +621,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenFrameRateIsUnstable_doesntDetectFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.66, 30.0, 16.66, 30.0, 16.66});
@@ -617,6 +631,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeRate) {
     Configuration c;
+    c.enabled = true;
     Helper h(20, c);
     h.render(3);
     EXPECT_EQ(h.getMetrics().freezeRate, 0);
@@ -629,6 +644,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeDurationHistogram) {
     Configuration c;
+    c.enabled = true;
     // +17 because freeze durations include the render time of the previous frame
     c.freezeDurationMsHistogramBuckets = {2 * 17 + 17, 3 * 17 + 17, 6 * 17 + 17};
     Helper h(17, c);
@@ -662,6 +678,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeDistanceHistogram) {
     Configuration c;
+    c.enabled = true;
     c.freezeDistanceMsHistogramBuckets = {1 * 17, 5 * 17, 6 * 17};
     Helper h(17, c);
     h.render(1);
@@ -693,6 +710,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when60hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c); // ~24Hz
     h.render({16.66, 16.66, 16.66, 16.66, 16.66, 16.66, 16.66});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -701,6 +719,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSmallVariance60hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c); // ~24Hz
     h.render({14, 18, 14, 18, 14, 18, 14, 18});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -709,6 +728,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBadSmallVariance60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c); // ~24Hz
     h.render({14, 18, 14, /* no 18 between 14s */ 14, 18, 14, 18});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 1);
@@ -716,6 +736,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when30Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({33.33, 33.33, 33.33, 33.33, 33.33, 33.33});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -724,6 +745,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSmallVariance30Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({29.0, 35.0, 29.0, 35.0, 29.0, 35.0});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -732,6 +754,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBadSmallVariance30Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({29.0, 35.0, 29.0, /* no 35 between 29s */ 29.0, 35.0, 29.0, 35.0});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 1);
@@ -739,6 +762,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBad30HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({33.33, 33.33, 50.0, /* frame stayed 1 vsync too long */ 16.66, 33.33, 33.33});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 2); // note: 2 counts of judder
@@ -746,6 +770,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when24HzTo60Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(41.66, c);
     h.render({50.0, 33.33, 50.0, 33.33, 50.0, 33.33});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -754,6 +779,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when25HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(40, c);
     h.render({33.33, 33.33, 50.0});
     h.render({33.33, 33.33, 50.0});
@@ -766,6 +792,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when50HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(20, c);
     h.render({16.66, 16.66, 16.66, 33.33});
     h.render({16.66, 16.66, 16.66, 33.33});
@@ -778,6 +805,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when30HzTo50Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({40.0, 40.0, 40.0, 60.0});
     h.render({40.0, 40.0, 40.0, 60.0});
@@ -789,6 +817,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSmallVariancePulldown24HzTo60Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(41.66, c);
     h.render({52.0, 31.33, 52.0, 31.33, 52.0, 31.33});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 0);
@@ -796,6 +825,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBad24HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(41.66, c);
     h.render({50.0, 33.33, 50.0, 33.33, /* no 50 between 33s */ 33.33, 50.0, 33.33});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 1);
@@ -803,6 +833,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesJudderScoreHistogram) {
     Configuration c;
+    c.enabled = true;
     c.judderErrorToleranceUs = 2000;
     c.judderScoreHistogramBuckets = {1, 5, 8};
     Helper h(16, c);
@@ -817,6 +848,7 @@
 TEST_F(VideoRenderQualityTrackerTest, ranksJudderScoresInOrder) {
     // Each rendering is ranked from best to worst from a user experience
     Configuration c;
+    c.enabled = true;
     c.judderErrorToleranceUs = 2000;
     c.judderScoreHistogramBuckets = {0, 1000};
     int64_t previousScore = 0;
@@ -896,6 +928,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeEvents) {
     Configuration c;
+    c.enabled = true;
     c.freezeEventMax = 5;
     c.freezeEventDetailsMax = 4;
     c.freezeEventDistanceToleranceMs = 1000;
@@ -988,6 +1021,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesJudderEvents) {
     Configuration c;
+    c.enabled = true;
     c.judderEventMax = 4;
     c.judderEventDetailsMax = 3;
     c.judderEventDistanceToleranceMs = 100;
@@ -1038,6 +1072,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesOverallFreezeScore) {
     Configuration c;
+    c.enabled = true;
     // # drops * 20ms + 20ms because current frame is frozen + 1 for bucket threshold
     c.freezeDurationMsHistogramBuckets = {1 * 20 + 21, 5 * 20 + 21, 10 * 20 + 21};
     c.freezeDurationMsHistogramToScore = {10, 100, 1000};
@@ -1062,6 +1097,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesOverallJudderScore) {
     Configuration c;
+    c.enabled = true;
     c.judderScoreHistogramBuckets = {0, 6, 10};
     c.judderScoreHistogramToScore = {10, 100, 1000};
     Helper h(20, c);
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 9f26074..afd28e5 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -156,7 +156,6 @@
         "libaudiohal",
         "libaudioprocessing",
         "libaudioutils",
-        "libaudioutils_nonvndk",
         "libcutils",
         "libutils",
         "liblog",
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index df0b576..c4b41fd 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -85,6 +85,7 @@
 #include <utils/Trace.h>
 
 #include <fcntl.h>
+#include <future>
 #include <linux/futex.h>
 #include <math.h>
 #include <memory>
@@ -3899,15 +3900,25 @@
 {
     aflog::setThreadWriter(mNBLogWriter.get());
 
+    std::future<void> priorityBoostFuture; // joined on dtor; this is a one-shot boost.
     if (mType == SPATIALIZER) {
         const pid_t tid = getTid();
         if (tid == -1) {  // odd: we are here, we must be a running thread.
             ALOGW("%s: Cannot update Spatializer mixer thread priority, no tid", __func__);
         } else {
-            const int priorityBoost = requestSpatializerPriority(getpid(), tid);
-            if (priorityBoost > 0) {
-                stream()->setHalThreadPriority(priorityBoost);
-            }
+            // We launch the priority boost request in a separate thread because
+            // the SchedulingPolicyService may not be available during early
+            // boot time, with a wait causing boot delay.
+            // There is also a PrioConfigEvent that does this, but it will also
+            // block other config events.  This command should be able
+            // to run concurrent with other stream commands.
+            priorityBoostFuture = std::async(std::launch::async,
+                    [tid, output_sp = stream()]() {
+                const int priorityBoost = requestSpatializerPriority(getpid(), tid);
+                if (priorityBoost > 0) {
+                    output_sp->setHalThreadPriority(priorityBoost);
+                }
+            });
         }
     }
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 0dbb502..7752357 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1311,7 +1311,9 @@
             if (!playbackThread->isTrackActive(this)) {
                 reset();
                 mState = STOPPED;
-            } else if (!isFastTrack() && !isOffloaded() && !isDirect()) {
+            } else if (isPatchTrack() || (!isFastTrack() && !isOffloaded() && !isDirect())) {
+                // for a PatchTrack (whatever fast ot not), do not drain but move directly
+                // to STOPPED to avoid closing while active.
                 mState = STOPPED;
             } else {
                 // For fast tracks prepareTracks_l() will set state to STOPPING_2
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 937d755..3801470 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1490,13 +1490,14 @@
     return res;
 }
 
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupManualFlashStrengthControlTags() {
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupManualFlashStrengthControlTags(
+            CameraMetadata& ch) {
     status_t res = OK;
-    auto& c = mCameraCharacteristics;
-    auto flashSingleStrengthMaxLevelEntry = c.find(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL);
+    auto flashSingleStrengthMaxLevelEntry = ch.find(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL);
     if (flashSingleStrengthMaxLevelEntry.count == 0) {
         int32_t flashSingleStrengthMaxLevel = 1;
-        res = c.update(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+        res = ch.update(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
                 &flashSingleStrengthMaxLevel, 1);
         if (res != OK) {
             ALOGE("%s: Failed to update ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL: %s (%d)",
@@ -1504,10 +1505,11 @@
             return res;
         }
     }
-    auto flashSingleStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL);
+    auto flashSingleStrengthDefaultLevelEntry = ch.find(
+            ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL);
     if (flashSingleStrengthDefaultLevelEntry.count == 0) {
         int32_t flashSingleStrengthDefaultLevel = 1;
-        res = c.update(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+        res = ch.update(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
                 &flashSingleStrengthDefaultLevel, 1);
         if (res != OK) {
             ALOGE("%s: Failed to update ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL: %s (%d)",
@@ -1515,10 +1517,10 @@
             return res;
         }
     }
-    auto flashTorchStrengthMaxLevelEntry = c.find(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL);
+    auto flashTorchStrengthMaxLevelEntry = ch.find(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL);
     if (flashTorchStrengthMaxLevelEntry.count == 0) {
         int32_t flashTorchStrengthMaxLevel = 1;
-        res = c.update(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+        res = ch.update(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
                 &flashTorchStrengthMaxLevel, 1);
         if (res != OK) {
             ALOGE("%s: Failed to update ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL: %s (%d)",
@@ -1526,10 +1528,10 @@
             return res;
         }
     }
-    auto flashTorchStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL);
+    auto flashTorchStrengthDefaultLevelEntry = ch.find(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL);
     if (flashTorchStrengthDefaultLevelEntry.count == 0) {
         int32_t flashTorchStrengthDefaultLevel = 1;
-        res = c.update(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
+        res = ch.update(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
                 &flashTorchStrengthDefaultLevel, 1);
         if (res != OK) {
             ALOGE("%s: Failed to update ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL: %s (%d)",
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 37a9ccb..2a5e73b 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -683,7 +683,7 @@
             SystemCameraKind getSystemCameraKind();
             status_t fixupMonochromeTags();
             status_t fixupTorchStrengthTags();
-            status_t fixupManualFlashStrengthControlTags();
+            status_t fixupManualFlashStrengthControlTags(CameraMetadata& ch);
             status_t addDynamicDepthTags(bool maxResolution = false);
             status_t deriveHeicTags(bool maxResolution = false);
             status_t deriveJpegRTags(bool maxResolution = false);
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index f5279aa..9f28b5f 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -508,7 +508,7 @@
         return;
     }
     if (flags::camera_manual_flash_strength_control()) {
-        res = fixupManualFlashStrengthControlTags();
+        res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
         if (OK != res) {
             ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
                     __FUNCTION__, strerror(-res), res);
@@ -653,6 +653,15 @@
                 ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
                         __FUNCTION__, strerror(-res), res);
             }
+
+            if (flags::camera_manual_flash_strength_control()) {
+                res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
+                if (OK != res) {
+                    ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                            __FUNCTION__, strerror(-res), res);
+                    return;
+                }
+            }
         }
     }
 
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 4197358..e4bd503 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -616,7 +616,7 @@
         return;
     }
     if (flags::camera_manual_flash_strength_control()) {
-        res = fixupManualFlashStrengthControlTags();
+        res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
         if (OK != res) {
             ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
                     __FUNCTION__, strerror(-res), res);
@@ -772,6 +772,15 @@
                 ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
                         __FUNCTION__, strerror(-res), res);
             }
+
+            if (flags::camera_manual_flash_strength_control()) {
+                res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
+                if (OK != res) {
+                    ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                            __FUNCTION__, strerror(-res), res);
+                    return;
+                }
+            }
         }
     }
 }