Lock display refresh rate when primary range is a single rate.

When DMS enforces a fixed refresh rate to hide user-visible flickering,
we must respect that refresh rate to avoid unnecessary switches during
scenarios such as idle and touch boost.

We must still respect app votes when they explicitly provide a frame
rate.

Bug: 156315203
Test: Exoplayer
Test: Modified version of SetFrameRateTest to simulate 60hz video
Test: libsurfaceflinger_unittest
Change-Id: I5fe974ddaff30e2f02e381cb63e0a6418834fdb5
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 4a4f9c8..e181c12 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -128,15 +128,24 @@
         }
     }
 
+    const bool hasExplicitVoteLayers =
+            explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0;
+
     // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
     // selected a refresh rate to see if we should apply touch boost.
-    if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
+    if (touchActive && !hasExplicitVoteLayers) {
         ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
         if (touchConsidered) *touchConsidered = true;
         return getMaxRefreshRateByPolicyLocked();
     }
 
-    if (!touchActive && idle) {
+    // If the primary range consists of a single refresh rate then we can only
+    // move out the of range if layers explicitly request a different refresh
+    // rate.
+    const Policy* policy = getCurrentPolicyLocked();
+    const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
+
+    if (!touchActive && idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
         return getMinRefreshRateByPolicyLocked();
     }
 
@@ -150,8 +159,6 @@
         return getMinRefreshRateByPolicyLocked();
     }
 
-    const Policy* policy = getCurrentPolicyLocked();
-
     // Find the best refresh rate based on score
     std::vector<std::pair<const RefreshRate*, float>> scores;
     scores.reserve(mAppRequestRefreshRates.size());
@@ -171,7 +178,8 @@
         for (auto i = 0u; i < scores.size(); i++) {
             bool inPrimaryRange =
                     scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
-            if (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault &&
+            if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
+                layer.vote != LayerVoteType::ExplicitDefault &&
                 layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
                 // Only layers with explicit frame rate settings are allowed to score refresh rates
                 // outside the primary range.
@@ -263,11 +271,23 @@
             ? getBestRefreshRate(scores.rbegin(), scores.rend())
             : getBestRefreshRate(scores.begin(), scores.end());
 
+    if (primaryRangeIsSingleRate) {
+        // If we never scored any layers, then choose the rate from the primary
+        // range instead of picking a random score from the app range.
+        if (std::all_of(scores.begin(), scores.end(),
+                        [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
+            return getMaxRefreshRateByPolicyLocked();
+        } else {
+            return *bestRefreshRate;
+        }
+    }
+
     // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
     // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
     // vote we should not change it if we get a touch event. Only apply touch boost if it will
     // actually increase the refresh rate over the normal selection.
     const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
+
     if (touchActive && explicitDefaultVoteLayers == 0 &&
         bestRefreshRate->fps < touchRefreshRate.fps) {
         if (touchConsidered) *touchConsidered = true;
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 692f71f..c919e93 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1205,6 +1205,121 @@
     }
 }
 
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    bool touchConsidered = false;
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true, /*idle*/ false,
+                                                     &touchConsidered));
+    EXPECT_EQ(false, touchConsidered);
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitDefault";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true, /*idle*/ false,
+                                                     &touchConsidered));
+    EXPECT_EQ(false, touchConsidered);
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+              0);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    bool touchConsidered = false;
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.desiredRefreshRate = 90.0f;
+    lr.name = "90Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ true,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 90.0f;
+    lr.name = "90Hz ExplicitDefault";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ true,
+                                                     &touchConsidered));
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitLayers) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    bool touchConsidered = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate({}, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+    EXPECT_EQ(false, touchConsidered);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitDefault";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::Heuristic;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::Max;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::Min;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Min";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+}
+
 TEST_F(RefreshRateConfigsTest, groupSwitching) {
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
@@ -1234,7 +1349,7 @@
 
 TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
     auto refreshRateConfigs =
-            std::make_unique<RefreshRateConfigs>(m60_90Device,
+            std::make_unique<RefreshRateConfigs>(m30_60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
     auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
@@ -1253,7 +1368,7 @@
     };
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+                      {HWC_CONFIG_ID_60, {30.f, 60.f}, {30.f, 90.f}}),
               0);
     bool touchConsidered;
     EXPECT_EQ(HWC_CONFIG_ID_60,
@@ -1262,7 +1377,7 @@
                                            &touchConsidered)
                       .getConfigId());
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90.f));
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
     EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));