SF: Skip choosing mode for powered-off followers

While the inactive display of a foldable is powered off, the Scheduler's
chosen mode for it is ignored by shouldApplyRefreshRateSelectorPolicy in
SF::requestDisplayModes, as it will be applied when the display becomes
active.

As an optimization, skip RefreshRateSelector::getRankedFrameRates for
follower displays, since SF::requestDisplayModes throws the result away.

This also restricts the mode of powered-off external displays to only be
set in response to DM policy changes, e.g. 60+60 constraint. Previously,
the Scheduler could initiate a mode request with an unconstrained policy
before powering on the display, which HWC would apply after powering on.

Flag: NONE (blocks P1 bug fix, and risk is limited to multi-display)
Bug: 329111930
Bug: 318534874
Test: SchedulerTest.chooseDisplayModesMultipleDisplays
Change-Id: I4dd954bf9a943f181bd64950ff9edee863f53e99
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 005ec05..30bd735 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -1152,8 +1152,10 @@
         return pacesetterFps;
     }();
 
+    // Choose a mode for powered-on follower displays.
     for (const auto& [id, display] : mDisplays) {
         if (id == *mPacesetterDisplayId) continue;
+        if (display.powerMode != hal::PowerMode::ON) continue;
 
         auto rankedFrameRates =
                 display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals,
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 7479a4f..4fb0690 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -350,6 +350,9 @@
                                 std::make_shared<RefreshRateSelector>(kDisplay2Modes,
                                                                       kDisplay2Mode60->getId()));
 
+    mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON);
+    mScheduler->setDisplayPowerMode(kDisplayId2, hal::PowerMode::ON);
+
     using DisplayModeChoice = TestableScheduler::DisplayModeChoice;
     TestableScheduler::DisplayModeChoiceMap expectedChoices;
 
@@ -412,6 +415,7 @@
                 ->registerDisplay(kDisplayId3,
                                   std::make_shared<RefreshRateSelector>(kDisplay3Modes,
                                                                         kDisplay3Mode60->getId()));
+        mScheduler->setDisplayPowerMode(kDisplayId3, hal::PowerMode::ON);
 
         const GlobalSignals globalSignals = {.touch = true};
         mScheduler->replaceTouchTimer(10);
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 1e02c67..198a5de 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -111,6 +111,11 @@
         Scheduler::unregisterDisplay(displayId);
     }
 
+    void setDisplayPowerMode(PhysicalDisplayId displayId, hal::PowerMode powerMode) {
+        ftl::FakeGuard guard(kMainThreadContext);
+        Scheduler::setDisplayPowerMode(displayId, powerMode);
+    }
+
     std::optional<PhysicalDisplayId> pacesetterDisplayId() const NO_THREAD_SAFETY_ANALYSIS {
         return mPacesetterDisplayId;
     }