SF: Clean up API for refresh rate selection

Define types for each step: ScoredRefreshRate, RefreshRateRanking,
RankedRefreshRates, DisplayModeChoice, and DisplayModeRequest. The
last will replace DisplayDevice::ActiveModeInfo in a follow-up CL.

Add Scheduler::mLeaderDisplayId (always the primary display for now)
and provisionally use its DisplayModeChoice until Scheduler::Policy
is tracked per display.

Rewrite multi-display tests, which relied on each DisplayMode having
the same PhysicalDisplayId, and did not actually verify mode/display
association (`expectedDisplays` was unused). Test RefreshRateRanking
ordering by descending score.

Bug: 241285191
Test: libsurfaceflinger_unittest
Change-Id: I1d24d6a1fa9285aa7fc4bf2dd6654fa660d27b08
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 7219584..99f81aa 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -23,6 +23,7 @@
 #include <utility>
 #include <variant>
 
+#include <ftl/concat.h>
 #include <gui/DisplayEventReceiver.h>
 
 #include <scheduler/Fps.h>
@@ -46,15 +47,6 @@
     return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs));
 }
 
-struct RefreshRateRanking {
-    DisplayModePtr displayModePtr;
-    float score = 0.0f;
-
-    bool operator==(const RefreshRateRanking& ranking) const {
-        return displayModePtr == ranking.displayModePtr && score == ranking.score;
-    }
-};
-
 using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
 
 /**
@@ -208,12 +200,46 @@
             return touch == other.touch && idle == other.idle &&
                     powerOnImminent == other.powerOnImminent;
         }
+
+        auto toString() const {
+            return ftl::Concat("{touch=", touch, ", idle=", idle,
+                               ", powerOnImminent=", powerOnImminent, '}');
+        }
     };
 
-    // Returns the list in the descending order of refresh rates desired
-    // based on their overall score, and the GlobalSignals that were considered.
-    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRates(
-            const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock);
+    struct ScoredRefreshRate {
+        DisplayModePtr modePtr;
+        float score = 0.0f;
+
+        bool operator==(const ScoredRefreshRate& other) const {
+            return modePtr == other.modePtr && score == other.score;
+        }
+
+        static bool scoresEqual(float lhs, float rhs) {
+            constexpr float kEpsilon = 0.0001f;
+            return std::abs(lhs - rhs) <= kEpsilon;
+        }
+
+        struct DescendingScore {
+            bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const {
+                return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score);
+            }
+        };
+    };
+
+    using RefreshRateRanking = std::vector<ScoredRefreshRate>;
+
+    struct RankedRefreshRates {
+        RefreshRateRanking ranking; // Ordered by descending score.
+        GlobalSignals consideredSignals;
+
+        bool operator==(const RankedRefreshRates& other) const {
+            return ranking == other.ranking && consideredSignals == other.consideredSignals;
+        }
+    };
+
+    RankedRefreshRates getRankedRefreshRates(const std::vector<LayerRequirement>&,
+                                             GlobalSignals) const EXCLUDES(mLock);
 
     FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
         std::lock_guard lock(mLock);
@@ -354,8 +380,8 @@
     // See mActiveModeIt for thread safety.
     DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock);
 
-    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked(
-            const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock);
+    RankedRefreshRates getRankedRefreshRatesLocked(const std::vector<LayerRequirement>&,
+                                                   GlobalSignals) const REQUIRES(mLock);
 
     // Returns number of display frames and remainder when dividing the layer refresh period by
     // display refresh period.
@@ -373,11 +399,10 @@
 
     enum class RefreshRateOrder { Ascending, Descending };
 
-    // Returns the rankings in RefreshRateOrder. May change at runtime.
     // Only uses the primary range, not the app request range.
-    std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked(
-            std::optional<int> anchorGroupOpt, RefreshRateOrder,
-            std::optional<DisplayModeId> preferredDisplayModeOpt) const REQUIRES(mLock);
+    RefreshRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt, RefreshRateOrder,
+                                        std::optional<DisplayModeId> preferredDisplayModeOpt =
+                                                std::nullopt) const REQUIRES(mLock);
 
     const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
     bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
@@ -436,7 +461,7 @@
 
     struct GetRankedRefreshRatesCache {
         std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
-        std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result;
+        RankedRefreshRates result;
     };
     mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock);