NoPreference frame rate category is no-op

Change NoPreference frame rate category to behave like a no-op.
When all layers are NoPreference votes, the current frame rate should be
used, instead of choosing Min.
This also allows idle timer to trigger.

Bug: 328084518
Test: atest libsurfaceflinger_unittest
Test: Manual sysui jank suit
Change-Id: Ibe25ab8427367c5b86a1eaf0ed43434b6d270691
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index ad59f1a..56c29e2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -506,6 +506,8 @@
     }
 
     int noVoteLayers = 0;
+    // Layers that prefer the same mode ("no-op").
+    int noPreferenceLayers = 0;
     int minVoteLayers = 0;
     int maxVoteLayers = 0;
     int explicitDefaultVoteLayers = 0;
@@ -549,10 +551,7 @@
                     explicitCategoryVoteLayers++;
                 }
                 if (layer.frameRateCategory == FrameRateCategory::NoPreference) {
-                    // Count this layer for Min vote as well. The explicit vote avoids
-                    // touch boost and idle for choosing a category, while Min vote is for correct
-                    // behavior when all layers are Min or no vote.
-                    minVoteLayers++;
+                    noPreferenceLayers++;
                 }
                 break;
             case LayerVoteType::Heuristic:
@@ -612,6 +611,16 @@
         return {ranking, kNoSignals};
     }
 
+    // If all layers are category NoPreference, use the current config.
+    if (noPreferenceLayers + noVoteLayers == layers.size()) {
+        ALOGV("All layers NoPreference");
+        const auto ascendingWithPreferred =
+                rankFrameRates(anchorGroup, RefreshRateOrder::Ascending, activeMode.getId());
+        ATRACE_FORMAT_INSTANT("%s (All layers NoPreference)",
+                              to_string(ascendingWithPreferred.front().frameRateMode.fps).c_str());
+        return {ascendingWithPreferred, kNoSignals};
+    }
+
     const bool smoothSwitchOnly = categorySmoothSwitchOnlyLayers > 0;
     const DisplayModeId activeModeId = activeMode.getId();
 
@@ -643,6 +652,7 @@
               ftl::enum_string(layer.frameRateCategory).c_str());
         if (layer.isNoVote() || layer.frameRateCategory == FrameRateCategory::NoPreference ||
             layer.vote == LayerVoteType::Min) {
+            ALOGV("%s scoring skipped due to vote", formatLayerInfo(layer, layer.weight).c_str());
             continue;
         }
 
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index fe0e3d1..a155f5d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -295,6 +295,12 @@
                     << "Did not get expected frame rate for frameRate="
                     << to_string(testCase.desiredFrameRate)
                     << " category=" << ftl::enum_string(testCase.frameRateCategory);
+            EXPECT_EQ(testCase.expectedModeId,
+                      selector.getBestFrameRateMode(layers).modePtr->getId())
+                    << "Did not get expected DisplayModeId for modeId="
+                    << ftl::to_underlying(testCase.expectedModeId)
+                    << " frameRate=" << to_string(testCase.desiredFrameRate)
+                    << " category=" << ftl::enum_string(testCase.frameRateCategory);
         }
     }
 };
@@ -1534,7 +1540,7 @@
             {0_Hz, FrameRateCategory::High, 90_Hz},
             {0_Hz, FrameRateCategory::Normal, 60_Hz},
             {0_Hz, FrameRateCategory::Low, 30_Hz},
-            {0_Hz, FrameRateCategory::NoPreference, 30_Hz},
+            {0_Hz, FrameRateCategory::NoPreference, 60_Hz},
 
             // Cases that have both desired frame rate and frame rate category requirements.
             {24_Hz, FrameRateCategory::High, 120_Hz},
@@ -1591,6 +1597,7 @@
 
         // Expected result
         Fps expectedFrameRate = 0_Hz;
+        DisplayModeId expectedModeId = kModeId90;
     };
 
     testFrameRateCategoryWithMultipleLayers(
@@ -1605,7 +1612,7 @@
 
     testFrameRateCategoryWithMultipleLayers(
             std::initializer_list<Case>{
-                    {0_Hz, FrameRateCategory::Normal, 60_Hz},
+                    {0_Hz, FrameRateCategory::Normal, 60_Hz, kModeId60},
                     {0_Hz, FrameRateCategory::High, 90_Hz},
                     {0_Hz, FrameRateCategory::NoPreference, 90_Hz},
             },
@@ -1614,18 +1621,18 @@
     testFrameRateCategoryWithMultipleLayers(
             std::initializer_list<Case>{
                     {30_Hz, FrameRateCategory::High, 90_Hz},
-                    {24_Hz, FrameRateCategory::High, 120_Hz},
-                    {12_Hz, FrameRateCategory::Normal, 120_Hz},
-                    {30_Hz, FrameRateCategory::NoPreference, 120_Hz},
+                    {24_Hz, FrameRateCategory::High, 120_Hz, kModeId120},
+                    {12_Hz, FrameRateCategory::Normal, 120_Hz, kModeId120},
+                    {30_Hz, FrameRateCategory::NoPreference, 120_Hz, kModeId120},
 
             },
             selector);
 
     testFrameRateCategoryWithMultipleLayers(
             std::initializer_list<Case>{
-                    {24_Hz, FrameRateCategory::Default, 120_Hz},
-                    {30_Hz, FrameRateCategory::Default, 120_Hz},
-                    {120_Hz, FrameRateCategory::Default, 120_Hz},
+                    {24_Hz, FrameRateCategory::Default, 120_Hz, kModeId120},
+                    {30_Hz, FrameRateCategory::Default, 120_Hz, kModeId120},
+                    {120_Hz, FrameRateCategory::Default, 120_Hz, kModeId120},
             },
             selector);
 }
@@ -1640,6 +1647,7 @@
 
         // Expected result
         Fps expectedFrameRate = 0_Hz;
+        DisplayModeId expectedModeId = kModeId120;
     };
 
     testFrameRateCategoryWithMultipleLayers(std::initializer_list<
@@ -1970,6 +1978,122 @@
 }
 
 TEST_P(RefreshRateSelectorTest,
+       getBestFrameRateMode_withFrameRateCategory_idleTimer_60_120_nonVrr) {
+    SET_FLAG_FOR_TEST(flags::vrr_config, false);
+    using KernelIdleTimerAction = RefreshRateSelector::KernelIdleTimerAction;
+    struct LayerArg {
+        // Params
+        FrameRateCategory frameRateCategory = FrameRateCategory::Default;
+        LayerVoteType voteType = LayerVoteType::ExplicitDefault;
+
+        // Expected result
+        Fps expectedFrameRate = 0_Hz;
+        DisplayModeId expectedModeId = kModeId60;
+    };
+
+    const auto runTest = [&](const TestableRefreshRateSelector& selector,
+                             const std::initializer_list<LayerArg>& layerArgs,
+                             const RefreshRateSelector::GlobalSignals& signals) {
+        std::vector<LayerRequirement> layers;
+        for (auto testCase : layerArgs) {
+            ALOGI("**** %s: Testing frameRateCategory=%s", __func__,
+                  ftl::enum_string(testCase.frameRateCategory).c_str());
+
+            if (testCase.frameRateCategory != FrameRateCategory::Default) {
+                std::stringstream ss;
+                ss << "ExplicitCategory (" << ftl::enum_string(testCase.frameRateCategory) << ")";
+                LayerRequirement layer = {.name = ss.str(),
+                                          .vote = LayerVoteType::ExplicitCategory,
+                                          .frameRateCategory = testCase.frameRateCategory,
+                                          .weight = 1.f};
+                layers.push_back(layer);
+            }
+
+            if (testCase.voteType != LayerVoteType::ExplicitDefault) {
+                std::stringstream ss;
+                ss << ftl::enum_string(testCase.voteType);
+                LayerRequirement layer = {.name = ss.str(),
+                                          .vote = testCase.voteType,
+                                          .weight = 1.f};
+                layers.push_back(layer);
+            }
+
+            EXPECT_EQ(testCase.expectedFrameRate,
+                      selector.getBestFrameRateMode(layers, signals).modePtr->getPeakFps())
+                    << "Did not get expected frame rate for"
+                    << " category=" << ftl::enum_string(testCase.frameRateCategory);
+            EXPECT_EQ(testCase.expectedModeId,
+                      selector.getBestFrameRateMode(layers, signals).modePtr->getId())
+                    << "Did not get expected DisplayModeId for modeId="
+                    << ftl::to_underlying(testCase.expectedModeId)
+                    << " category=" << ftl::enum_string(testCase.frameRateCategory);
+        }
+    };
+
+    {
+        // IdleTimer not configured
+        auto selector = createSelector(makeModes(kMode60, kMode120), kModeId120);
+        ASSERT_EQ(0ms, selector.getIdleTimerTimeout());
+
+        runTest(selector,
+                std::initializer_list<LayerArg>{
+                        // Rate does not change due to NoPreference.
+                        {.frameRateCategory = FrameRateCategory::NoPreference,
+                         .expectedFrameRate = 120_Hz,
+                         .expectedModeId = kModeId120},
+                        {.voteType = LayerVoteType::NoVote,
+                         .expectedFrameRate = 120_Hz,
+                         .expectedModeId = kModeId120},
+                        {.frameRateCategory = FrameRateCategory::NoPreference,
+                         .expectedFrameRate = 120_Hz,
+                         .expectedModeId = kModeId120},
+                },
+                {.idle = false});
+    }
+
+    // IdleTimer configured
+    constexpr std::chrono::milliseconds kIdleTimerTimeoutMs = 10ms;
+    auto selector = createSelector(makeModes(kMode60, kMode120), kModeId120,
+                                   Config{
+                                           .idleTimerTimeout = kIdleTimerTimeoutMs,
+                                   });
+    ASSERT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction());
+    ASSERT_EQ(kIdleTimerTimeoutMs, selector.getIdleTimerTimeout());
+    runTest(selector,
+            std::initializer_list<LayerArg>{
+                    // Rate won't change immediately and will stay 120 due to NoPreference, as
+                    // idle timer did not timeout yet.
+                    {.frameRateCategory = FrameRateCategory::NoPreference,
+                     .expectedFrameRate = 120_Hz,
+                     .expectedModeId = kModeId120},
+                    {.voteType = LayerVoteType::NoVote,
+                     .expectedFrameRate = 120_Hz,
+                     .expectedModeId = kModeId120},
+                    {.frameRateCategory = FrameRateCategory::NoPreference,
+                     .expectedFrameRate = 120_Hz,
+                     .expectedModeId = kModeId120},
+            },
+            {.idle = false});
+
+    // Idle timer is triggered using GlobalSignals.
+    ASSERT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction());
+    ASSERT_EQ(kIdleTimerTimeoutMs, selector.getIdleTimerTimeout());
+    runTest(selector,
+            std::initializer_list<LayerArg>{
+                    {.frameRateCategory = FrameRateCategory::NoPreference,
+                     .expectedFrameRate = 60_Hz,
+                     .expectedModeId = kModeId60},
+                    {.voteType = LayerVoteType::NoVote,
+                     .expectedFrameRate = 60_Hz,
+                     .expectedModeId = kModeId60},
+                    {.frameRateCategory = FrameRateCategory::NoPreference,
+                     .expectedFrameRate = 60_Hz,
+                     .expectedModeId = kModeId60},
+            },
+            {.idle = true});
+}
+
+TEST_P(RefreshRateSelectorTest,
        getBestFrameRateMode_withFrameRateCategory_smoothSwitchOnly_60_120_nonVrr) {
     if (GetParam() != Config::FrameRateOverride::Enabled) {
         return;
@@ -1992,8 +2116,7 @@
     const std::initializer_list<Case> testCases = {
             // These layers may switch modes because smoothSwitchOnly=false.
             {FrameRateCategory::Default, false, 120_Hz, kModeId120},
-            // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate.
-            {FrameRateCategory::NoPreference, false, 60_Hz, kModeId60},
+            {FrameRateCategory::NoPreference, false, 120_Hz, kModeId120},
             {FrameRateCategory::Low, false, 30_Hz, kModeId60},
             {FrameRateCategory::Normal, false, 60_Hz, kModeId60},
             {FrameRateCategory::High, false, 120_Hz, kModeId120},