Merge "SF: Remove BufferStateLayer class"
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 00886f0..3cb052c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -48,24 +48,6 @@
     } fixedRateBelowThresholdLayersScore;
 };
 
-template <typename Iterator>
-const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) {
-    const auto it =
-            std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) {
-                const auto& [modeIt, overallScore, _] = current;
-
-                std::string name = to_string(modeIt->second->getFps());
-                ALOGV("%s scores %.2f", name.c_str(), overallScore);
-
-                ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));
-
-                constexpr float kEpsilon = 0.0001f;
-                return overallScore > max.overallScore * (1 + kEpsilon);
-            });
-
-    return it->modeIt->second;
-}
-
 constexpr RefreshRateConfigs::GlobalSignals kNoSignals;
 
 std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
@@ -137,6 +119,34 @@
 
 } // namespace
 
+struct RefreshRateConfigs::RefreshRateScoreComparator {
+    bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const {
+        const auto& [modeIt, overallScore, _] = lhs;
+
+        std::string name = to_string(modeIt->second->getFps());
+        ALOGV("%s sorting scores %.2f", name.c_str(), overallScore);
+
+        ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));
+
+        constexpr float kEpsilon = 0.0001f;
+        if (std::abs(overallScore - rhs.overallScore) > kEpsilon) {
+            return overallScore > rhs.overallScore;
+        }
+
+        // If overallScore tie we will pick the higher refresh rate if
+        // high refresh rate is the priority else the lower refresh rate.
+        if (refreshRateOrder == RefreshRateOrder::Descending) {
+            using fps_approx_ops::operator>;
+            return modeIt->second->getFps() > rhs.modeIt->second->getFps();
+        } else {
+            using fps_approx_ops::operator<;
+            return modeIt->second->getFps() < rhs.modeIt->second->getFps();
+        }
+    }
+
+    const RefreshRateOrder refreshRateOrder;
+};
+
 std::string RefreshRateConfigs::Policy::toString() const {
     return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
                               ", primaryRange=%s, appRequestRange=%s}",
@@ -218,6 +228,13 @@
     return 0;
 }
 
+float RefreshRateConfigs::calculateRefreshRateScoreForFps(Fps refreshRate) const {
+    const float ratio =
+            refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue();
+    // Use ratio^2 to get a lower score the more we get further from peak
+    return ratio * ratio;
+}
+
 float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
                                                     bool isSeamlessSwitch) const {
     // Slightly prefer seamless switches.
@@ -226,10 +243,7 @@
 
     // If the layer wants Max, give higher score to the higher refresh rate
     if (layer.vote == LayerVoteType::Max) {
-        const auto& maxRefreshRate = mAppRequestRefreshRates.back()->second;
-        const auto ratio = refreshRate.getValue() / maxRefreshRate->getFps().getValue();
-        // use ratio^2 to get a lower score the more we get further from peak
-        return ratio * ratio;
+        return calculateRefreshRateScoreForFps(refreshRate);
     }
 
     if (layer.vote == LayerVoteType::ExplicitExact) {
@@ -258,24 +272,24 @@
             kNonExactMatchingPenalty;
 }
 
-auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
-                                            GlobalSignals signals) const
-        -> std::pair<DisplayModePtr, GlobalSignals> {
+auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers,
+                                               GlobalSignals signals) const
+        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
     std::lock_guard lock(mLock);
 
-    if (mGetBestRefreshRateCache &&
-        mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) {
-        return mGetBestRefreshRateCache->result;
+    if (mGetRankedRefreshRatesCache &&
+        mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) {
+        return mGetRankedRefreshRatesCache->result;
     }
 
-    const auto result = getBestRefreshRateLocked(layers, signals);
-    mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result};
+    const auto result = getRankedRefreshRatesLocked(layers, signals);
+    mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result};
     return result;
 }
 
-auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
-                                                  GlobalSignals signals) const
-        -> std::pair<DisplayModePtr, GlobalSignals> {
+auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers,
+                                                     GlobalSignals signals) const
+        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
     using namespace fps_approx_ops;
     ATRACE_CALL();
     ALOGV("%s: %zu layers", __func__, layers.size());
@@ -285,8 +299,8 @@
     // Keep the display at max refresh rate for the duration of powering on the display.
     if (signals.powerOnImminent) {
         ALOGV("Power On Imminent");
-        const auto& max = getMaxRefreshRateByPolicyLocked(activeMode.getGroup());
-        return {max, GlobalSignals{.powerOnImminent = true}};
+        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending),
+                GlobalSignals{.powerOnImminent = true}};
     }
 
     int noVoteLayers = 0;
@@ -295,7 +309,6 @@
     int explicitDefaultVoteLayers = 0;
     int explicitExactOrMultipleVoteLayers = 0;
     int explicitExact = 0;
-    float maxExplicitWeight = 0;
     int seamedFocusedLayers = 0;
 
     for (const auto& layer : layers) {
@@ -311,15 +324,12 @@
                 break;
             case LayerVoteType::ExplicitDefault:
                 explicitDefaultVoteLayers++;
-                maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
                 break;
             case LayerVoteType::ExplicitExactOrMultiple:
                 explicitExactOrMultipleVoteLayers++;
-                maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
                 break;
             case LayerVoteType::ExplicitExact:
                 explicitExact++;
-                maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
                 break;
             case LayerVoteType::Heuristic:
                 break;
@@ -348,9 +358,9 @@
     // 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 (signals.touch && !hasExplicitVoteLayers) {
-        const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
-        ALOGV("TouchBoost - choose %s", to_string(max->getFps()).c_str());
-        return {max, GlobalSignals{.touch = true}};
+        ALOGV("Touch Boost");
+        return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
+                GlobalSignals{.touch = true}};
     }
 
     // If the primary range consists of a single refresh rate then we can only
@@ -360,22 +370,22 @@
             isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);
 
     if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
-        const DisplayModePtr& min = getMinRefreshRateByPolicyLocked();
-        ALOGV("Idle - choose %s", to_string(min->getFps()).c_str());
-        return {min, GlobalSignals{.idle = true}};
+        ALOGV("Idle");
+        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending),
+                GlobalSignals{.idle = true}};
     }
 
     if (layers.empty() || noVoteLayers == layers.size()) {
-        const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
-        ALOGV("no layers with votes - choose %s", to_string(max->getFps()).c_str());
-        return {max, kNoSignals};
+        ALOGV("No layers with votes");
+        return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
+                kNoSignals};
     }
 
     // Only if all layers want Min we should return Min
     if (noVoteLayers + minVoteLayers == layers.size()) {
-        const DisplayModePtr& min = getMinRefreshRateByPolicyLocked();
-        ALOGV("all layers Min - choose %s", to_string(min->getFps()).c_str());
-        return {min, kNoSignals};
+        ALOGV("All layers Min");
+        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending),
+                kNoSignals};
     }
 
     // Find the best refresh rate based on score
@@ -522,22 +532,29 @@
     }
 
     // Now that we scored all the refresh rates we need to pick the one that got the highest
-    // overallScore. In case of a tie we will pick the higher refresh rate if any of the layers
-    // wanted Max, or the lower otherwise.
-    const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0
-            ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend())
-            : getMaxScoreRefreshRate(scores.begin(), scores.end());
+    // overallScore. Sort the scores based on their overallScore in descending order of priority.
+    const RefreshRateOrder refreshRateOrder =
+            maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending;
+    std::sort(scores.begin(), scores.end(),
+              RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder});
+    std::vector<RefreshRateRanking> rankedRefreshRates;
+    rankedRefreshRates.reserve(scores.size());
+
+    std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates),
+                   [](const RefreshRateScore& score) {
+                       return RefreshRateRanking{score.modeIt->second, score.overallScore};
+                   });
 
     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(),
                         [](RefreshRateScore score) { return score.overallScore == 0; })) {
-            const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
-            ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str());
-            return {max, kNoSignals};
+            ALOGV("Layers not scored");
+            return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
+                    kNoSignals};
         } else {
-            return {bestRefreshRate, kNoSignals};
+            return {rankedRefreshRates, kNoSignals};
         }
     }
 
@@ -545,8 +562,6 @@
     // 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 DisplayModePtr& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
-
     const bool touchBoostForExplicitExact = [&] {
         if (mSupportsFrameRateOverrideByContent) {
             // Enable touch boost if there are other layers besides exact
@@ -557,15 +572,18 @@
         }
     }();
 
+    const auto& touchRefreshRates =
+            getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending);
     using fps_approx_ops::operator<;
 
     if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
-        bestRefreshRate->getFps() < touchRefreshRate->getFps()) {
-        ALOGV("TouchBoost - choose %s", to_string(touchRefreshRate->getFps()).c_str());
-        return {touchRefreshRate, GlobalSignals{.touch = true}};
+        scores.front().modeIt->second->getFps() <
+                touchRefreshRates.front().displayModePtr->getFps()) {
+        ALOGV("Touch Boost");
+        return {touchRefreshRates, GlobalSignals{.touch = true}};
     }
 
-    return {bestRefreshRate, kNoSignals};
+    return {rankedRefreshRates, kNoSignals};
 }
 
 std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
@@ -670,11 +688,13 @@
             continue;
         }
 
-        // Now that we scored all the refresh rates we need to pick the one that got the highest
-        // score.
+        // Now that we scored all the refresh rates we need to pick the lowest refresh rate
+        // that got the highest score.
         const DisplayModePtr& bestRefreshRate =
-                getMaxScoreRefreshRate(scores.begin(), scores.end());
-
+                std::min_element(scores.begin(), scores.end(),
+                                 RefreshRateScoreComparator{.refreshRateOrder =
+                                                                    RefreshRateOrder::Ascending})
+                        ->modeIt->second;
         frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
     }
 
@@ -715,16 +735,6 @@
     return mPrimaryRefreshRates.front()->second;
 }
 
-DisplayModePtr RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
-    std::lock_guard lock(mLock);
-    return getMaxRefreshRateByPolicyLocked();
-}
-
-const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
-    const int anchorGroup = getActiveModeItLocked()->second->getGroup();
-    return getMaxRefreshRateByPolicyLocked(anchorGroup);
-}
-
 const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
     for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) {
         const auto& mode = (*it)->second;
@@ -733,14 +743,41 @@
         }
     }
 
-    const auto& activeMode = *getActiveModeItLocked()->second;
-    ALOGE("Can't find max refresh rate by policy with the same mode group as the current mode %s",
-          to_string(activeMode).c_str());
+    ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup);
 
     // Default to the highest refresh rate.
     return mPrimaryRefreshRates.back()->second;
 }
 
+std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked(
+        std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const {
+    std::vector<RefreshRateRanking> rankings;
+    const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) {
+        const auto& mode = it->second;
+        const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending);
+        const float score = calculateRefreshRateScoreForFps(mode->getFps());
+        if (!anchorGroupOpt || mode->getGroup() == anchorGroupOpt) {
+            rankings.push_back(RefreshRateRanking{mode, inverseScore ? 1.0f / score : score});
+        }
+    };
+
+    if (refreshRateOrder == RefreshRateOrder::Ascending) {
+        std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking);
+    } else {
+        std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking);
+    }
+
+    if (!rankings.empty() || !anchorGroupOpt) {
+        return rankings;
+    }
+
+    ALOGW("Can't find %s refresh rate by policy with the same mode group"
+          " as the mode group %d",
+          refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value());
+
+    return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder);
+}
+
 DisplayModePtr RefreshRateConfigs::getActiveModePtr() const {
     std::lock_guard lock(mLock);
     return getActiveModeItLocked()->second;
@@ -760,9 +797,9 @@
 void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) {
     std::lock_guard lock(mLock);
 
-    // Invalidate the cached invocation to getBestRefreshRate. This forces
-    // the refresh rate to be recomputed on the next call to getBestRefreshRate.
-    mGetBestRefreshRateCache.reset();
+    // Invalidate the cached invocation to getRankedRefreshRates. This forces
+    // the refresh rate to be recomputed on the next call to getRankedRefreshRates.
+    mGetRankedRefreshRatesCache.reset();
 
     mActiveModeIt = mDisplayModes.find(modeId);
     LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
@@ -797,9 +834,9 @@
 void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) {
     std::lock_guard lock(mLock);
 
-    // Invalidate the cached invocation to getBestRefreshRate. This forces
-    // the refresh rate to be recomputed on the next call to getBestRefreshRate.
-    mGetBestRefreshRateCache.reset();
+    // Invalidate the cached invocation to getRankedRefreshRates. This forces
+    // the refresh rate to be recomputed on the next call to getRankedRefreshRates.
+    mGetRankedRefreshRatesCache.reset();
 
     mDisplayModes = std::move(modes);
     mActiveModeIt = mDisplayModes.find(activeModeId);
@@ -843,7 +880,7 @@
         ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
         return BAD_VALUE;
     }
-    mGetBestRefreshRateCache.reset();
+    mGetRankedRefreshRatesCache.reset();
     Policy previousPolicy = *getCurrentPolicyLocked();
     mDisplayManagerPolicy = policy;
     if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -858,7 +895,7 @@
     if (policy && !isPolicyValidLocked(*policy)) {
         return BAD_VALUE;
     }
-    mGetBestRefreshRateCache.reset();
+    mGetRankedRefreshRatesCache.reset();
     Policy previousPolicy = *getCurrentPolicyLocked();
     mOverridePolicy = policy;
     if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -958,7 +995,8 @@
         return KernelIdleTimerAction::TurnOff;
     }
 
-    const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked();
+    const DisplayModePtr& maxByPolicy =
+            getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup());
     if (minByPolicy == maxByPolicy) {
         // Turn on the timer when the min of the primary range is below the device min.
         if (const Policy* currentPolicy = getCurrentPolicyLocked();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 19bcb94..0642fcb 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -44,6 +44,15 @@
     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;
 
 /**
@@ -195,9 +204,9 @@
         }
     };
 
-    // Returns the refresh rate that best fits the given layers, and whether the refresh rate was
-    // chosen based on touch boost and/or idle timer.
-    std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRate(
+    // 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);
 
     FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
@@ -208,10 +217,6 @@
     std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId,
                                             bool timerExpired) const EXCLUDES(mLock);
 
-    // Returns the highest refresh rate according to the current policy. May change at runtime. Only
-    // uses the primary range, not the app request range.
-    DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
-
     void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext);
 
     // See mActiveModeIt for thread safety.
@@ -343,7 +348,7 @@
     // See mActiveModeIt for thread safety.
     DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock);
 
-    std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked(
+    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked(
             const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock);
 
     // Returns number of display frames and remainder when dividing the layer refresh period by
@@ -356,12 +361,23 @@
 
     // Returns the highest refresh rate according to the current policy. May change at runtime. Only
     // uses the primary range, not the app request range.
-    const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
     const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock);
 
+    struct RefreshRateScoreComparator;
+
+    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) const
+            REQUIRES(mLock);
+
     const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
     bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
 
+    // Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1.
+    float calculateRefreshRateScoreForFps(Fps refreshRate) const REQUIRES(mLock);
     // calculates a score for a layer. Used to determine the display refresh rate
     // and the frame rate override for certains applications.
     float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate,
@@ -410,11 +426,11 @@
     const Config mConfig;
     bool mSupportsFrameRateOverrideByContent;
 
-    struct GetBestRefreshRateCache {
+    struct GetRankedRefreshRatesCache {
         std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
-        std::pair<DisplayModePtr, GlobalSignals> result;
+        std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result;
     };
-    mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock);
+    mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock);
 
     // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed.
     std::mutex mIdleTimerCallbacksMutex;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index ff6b461..6d68bac 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -674,7 +674,9 @@
         if (currentState == newState) return {};
         currentState = std::forward<T>(newState);
 
-        std::tie(newMode, consideredSignals) = chooseDisplayMode();
+        const auto [rankings, signals] = getRankedDisplayModes();
+        newMode = rankings.front().displayModePtr;
+        consideredSignals = signals;
         frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
 
         if (mPolicy.mode == newMode) {
@@ -699,7 +701,8 @@
     return consideredSignals;
 }
 
-auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
+auto Scheduler::getRankedDisplayModes()
+        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
     ATRACE_CALL();
 
     const auto configs = holdRefreshRateConfigs();
@@ -712,14 +715,14 @@
                                 .idle = mPolicy.idleTimer == TimerState::Expired,
                                 .powerOnImminent = powerOnImminent};
 
-    return configs->getBestRefreshRate(mPolicy.contentRequirements, signals);
+    return configs->getRankedRefreshRates(mPolicy.contentRequirements, signals);
 }
 
 DisplayModePtr Scheduler::getPreferredDisplayMode() {
     std::lock_guard<std::mutex> lock(mPolicyLock);
     // Make sure the stored mode is up to date.
     if (mPolicy.mode) {
-        mPolicy.mode = chooseDisplayMode().first;
+        mPolicy.mode = getRankedDisplayModes().first.front().displayModePtr;
     }
     return mPolicy.mode;
 }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 1df60a5..f567205 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -269,8 +269,10 @@
     template <typename S, typename T>
     GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock);
 
-    // Returns the display mode that fulfills the policy, and the signals that were considered.
-    std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock);
+    // Returns the list of display modes in descending order of their priority that fulfills the
+    // policy, and the signals that were considered.
+    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedDisplayModes()
+            REQUIRES(mPolicyLock);
 
     bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a7a08bf..bcd2b43 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -813,16 +813,37 @@
         enableHalVirtualDisplays(true);
     }
 
-    // Process any initial hotplug and resulting display changes.
+    // Process hotplug for displays connected at boot.
     LOG_ALWAYS_FATAL_IF(!configureLocked(),
                         "Initial display configuration failed: HWC did not hotplug");
-    processDisplayChangesLocked();
 
-    const auto display = getDefaultDisplayDeviceLocked();
+    // Commit primary display.
+    sp<const DisplayDevice> display;
+    if (const auto indexOpt = mCurrentState.getDisplayIndex(getPrimaryDisplayIdLocked())) {
+        const auto& displays = mCurrentState.displays;
+
+        const auto& token = displays.keyAt(*indexOpt);
+        const auto& state = displays.valueAt(*indexOpt);
+
+        processDisplayAdded(token, state);
+        mDrawingState.displays.add(token, state);
+
+        display = getDefaultDisplayDeviceLocked();
+    }
+
     LOG_ALWAYS_FATAL_IF(!display, "Failed to configure the primary display");
     LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getPhysicalId()),
                         "Primary display is disconnected");
 
+    // TODO(b/241285876): The Scheduler needlessly depends on creating the CompositionEngine part of
+    // the DisplayDevice, hence the above commit of the primary display. Remove that special case by
+    // initializing the Scheduler after configureLocked, once decoupled from DisplayDevice.
+    initScheduler(display);
+    dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
+
+    // Commit secondary display(s).
+    processDisplayChangesLocked();
+
     // initialize our drawing state
     mDrawingState = mCurrentState;
 
@@ -2952,10 +2973,13 @@
     LOG_FATAL_IF(!displaySurface);
     auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), state,
                                                  displaySurface, producer);
-    if (display->isPrimary()) {
-        initScheduler(display);
-    }
-    if (!state.isVirtual()) {
+
+    if (mScheduler && !display->isVirtual()) {
+        // Display modes are reloaded on hotplug reconnect.
+        if (display->isPrimary()) {
+            mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
+        }
+
         dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
     }
 
@@ -3367,15 +3391,9 @@
     mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
 }
 
-void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {
-    if (mScheduler) {
-        // If the scheduler is already initialized, this means that we received
-        // a hotplug(connected) on the primary display. In that case we should
-        // update the scheduler with the most recent display information.
-        ALOGW("Scheduler already initialized, updating instead");
-        mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
-        return;
-    }
+void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
+    LOG_ALWAYS_FATAL_IF(mScheduler);
+
     const auto currRefreshRate = display->getActiveMode()->getFps();
     mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
                                                                       hal::PowerMode::OFF);
@@ -7076,7 +7094,7 @@
     mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime());
 }
 
-void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) {
+void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<const DisplayDevice>& activeDisplay) {
     mScheduler->onActiveDisplayAreaChanged(activeDisplay->getWidth() * activeDisplay->getHeight());
     getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize());
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0daf71d..1f8874d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -373,7 +373,20 @@
 
         const LayerVector::StateSet stateSet = LayerVector::StateSet::Invalid;
         LayerVector layersSortedByZ;
-        DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
+
+        // TODO(b/241285876): Replace deprecated DefaultKeyedVector with ftl::SmallMap.
+        DefaultKeyedVector<wp<IBinder>, DisplayDeviceState> displays;
+
+        std::optional<size_t> getDisplayIndex(PhysicalDisplayId displayId) const {
+            for (size_t i = 0; i < displays.size(); i++) {
+                const auto& state = displays.valueAt(i);
+                if (state.physical && state.physical->id == displayId) {
+                    return i;
+                }
+            }
+
+            return {};
+        }
 
         bool colorMatrixChanged = true;
         mat4 colorMatrix;
@@ -694,7 +707,7 @@
     void commitInputWindowCommands() REQUIRES(mStateLock);
     void updateCursorAsync();
 
-    void initScheduler(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
+    void initScheduler(const sp<const DisplayDevice>&) REQUIRES(mStateLock);
     void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock);
     void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
 
@@ -1026,7 +1039,7 @@
     void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay)
             REQUIRES(mStateLock, kMainThreadContext);
 
-    void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay);
+    void onActiveDisplaySizeChanged(const sp<const DisplayDevice>&);
 
     /*
      * Debugging & dumpsys
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index cb940b3..66bac44 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -350,7 +350,7 @@
     const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
     std::vector<LayerRequirement> layers = {{.weight = mFdp.ConsumeFloatingPoint<float>()}};
 
-    refreshRateConfigs.getBestRefreshRate(layers, globalSignals);
+    refreshRateConfigs.getRankedRefreshRates(layers, globalSignals);
 
     layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength);
     layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 5d9b2a8..a706c4b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -41,6 +41,7 @@
 
 struct TestableRefreshRateConfigs : RefreshRateConfigs {
     using RefreshRateConfigs::RefreshRateConfigs;
+    using RefreshRateConfigs::RefreshRateOrder;
 
     void setActiveModeId(DisplayModeId modeId) {
         ftl::FakeGuard guard(kMainThreadContext);
@@ -67,19 +68,30 @@
         return getMinRefreshRateByPolicyLocked();
     }
 
+    DisplayModePtr getMaxRefreshRateByPolicy() const {
+        std::lock_guard lock(mLock);
+        return getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup());
+    }
+
+    std::vector<RefreshRateRanking> getRefreshRatesByPolicy(
+            std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const {
+        std::lock_guard lock(mLock);
+        return RefreshRateConfigs::getRefreshRatesByPolicyLocked(anchorGroupOpt, refreshRateOrder);
+    }
+
     const std::vector<Fps>& knownFrameRates() const { return mKnownFrameRates; }
 
-    using RefreshRateConfigs::GetBestRefreshRateCache;
-    auto& mutableGetBestRefreshRateCache() { return mGetBestRefreshRateCache; }
+    using RefreshRateConfigs::GetRankedRefreshRatesCache;
+    auto& mutableGetRankedRefreshRatesCache() { return mGetRankedRefreshRatesCache; }
 
-    auto getBestRefreshRateAndSignals(const std::vector<LayerRequirement>& layers,
-                                      GlobalSignals signals) const {
-        return RefreshRateConfigs::getBestRefreshRate(layers, signals);
+    auto getRankedRefreshRatesAndSignals(const std::vector<LayerRequirement>& layers,
+                                         GlobalSignals signals) const {
+        return RefreshRateConfigs::getRankedRefreshRates(layers, signals);
     }
 
     DisplayModePtr getBestRefreshRate(const std::vector<LayerRequirement>& layers = {},
                                       GlobalSignals signals = {}) const {
-        return getBestRefreshRateAndSignals(layers, signals).first;
+        return getRankedRefreshRatesAndSignals(layers, signals).first.front().displayModePtr;
     }
 };
 
@@ -977,16 +989,116 @@
     EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
 }
 
+TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicy) {
+    // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+    // different group.
+    TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60);
+    const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90},
+                                                                   RefreshRateRanking{kMode60},
+                                                                   RefreshRateRanking{kMode30}};
+
+    const std::vector<RefreshRateRanking>& refreshRates =
+            configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(),
+                                            TestableRefreshRateConfigs::RefreshRateOrder::
+                                                    Descending);
+
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicy) {
+    // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+    // different group.
+    TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60);
+    const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30},
+                                                                   RefreshRateRanking{kMode60},
+                                                                   RefreshRateRanking{kMode90}};
+
+    const std::vector<RefreshRateRanking>& refreshRates =
+            configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(),
+                                            TestableRefreshRateConfigs::RefreshRateOrder::
+                                                    Ascending);
+
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicyOutsideTheGroup) {
+    // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+    // different group.
+    TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72);
+    const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30},
+                                                                   RefreshRateRanking{kMode60},
+                                                                   RefreshRateRanking{kMode90}};
+
+    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+
+    const std::vector<RefreshRateRanking>& refreshRates =
+            configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
+                                            TestableRefreshRateConfigs::RefreshRateOrder::
+                                                    Ascending);
+
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicyOutsideTheGroup) {
+    // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+    // different group.
+    TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72);
+    const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90},
+                                                                   RefreshRateRanking{kMode60},
+                                                                   RefreshRateRanking{kMode30}};
+
+    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+
+    const std::vector<RefreshRateRanking>& refreshRates =
+            configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
+                                            TestableRefreshRateConfigs::RefreshRateOrder::
+                                                    Descending);
+
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
+}
+
 TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) {
     RefreshRateConfigs configs(kModes_60_90, kModeId60);
+    std::vector<RefreshRateRanking> expectedRefreshRates = {RefreshRateRanking{kMode90},
+                                                            RefreshRateRanking{kMode60}};
 
-    auto [refreshRate, signals] = configs.getBestRefreshRate({}, {});
+    auto [refreshRates, signals] = configs.getRankedRefreshRates({}, {});
     EXPECT_FALSE(signals.powerOnImminent);
-    EXPECT_EQ(kMode90, refreshRate);
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
 
-    std::tie(refreshRate, signals) = configs.getBestRefreshRate({}, {.powerOnImminent = true});
+    std::tie(refreshRates, signals) = configs.getRankedRefreshRates({}, {.powerOnImminent = true});
     EXPECT_TRUE(signals.powerOnImminent);
-    EXPECT_EQ(kMode90, refreshRate);
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr1 = layers[0];
@@ -994,22 +1106,35 @@
     lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
 
-    std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = false});
-    EXPECT_FALSE(signals.powerOnImminent);
-    EXPECT_EQ(kMode60, refreshRate);
-
-    std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = true});
+    std::tie(refreshRates, signals) =
+            configs.getRankedRefreshRates(layers, {.powerOnImminent = true});
     EXPECT_TRUE(signals.powerOnImminent);
-    EXPECT_EQ(kMode90, refreshRate);
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
+
+    expectedRefreshRates = {RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90}};
+    std::tie(refreshRates, signals) =
+            configs.getRankedRefreshRates(layers, {.powerOnImminent = false});
+    EXPECT_FALSE(signals.powerOnImminent);
+    ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+    for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+        EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+                << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+    }
 }
 
 TEST_F(RefreshRateConfigsTest, touchConsidered) {
     RefreshRateConfigs configs(kModes_60_90, kModeId60);
 
-    auto [_, signals] = configs.getBestRefreshRate({}, {});
+    auto [_, signals] = configs.getRankedRefreshRates({}, {});
     EXPECT_FALSE(signals.touch);
 
-    std::tie(std::ignore, signals) = configs.getBestRefreshRate({}, {.touch = true});
+    std::tie(std::ignore, signals) = configs.getRankedRefreshRates({}, {.touch = true});
     EXPECT_TRUE(signals.touch);
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
@@ -1022,16 +1147,16 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+    std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
     EXPECT_TRUE(signals.touch);
 
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.desiredRefreshRate = 60_Hz;
-    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr1.name = "60Hz ExplicitDefault";
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+    std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
     EXPECT_FALSE(signals.touch);
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -1040,16 +1165,16 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+    std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
     EXPECT_TRUE(signals.touch);
 
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.desiredRefreshRate = 60_Hz;
-    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr1.name = "60Hz ExplicitDefault";
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+    std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
     EXPECT_FALSE(signals.touch);
 }
 
@@ -1187,9 +1312,10 @@
     lr.name = "60Hz ExplicitDefault";
     lr.focused = true;
 
-    const auto [mode, signals] = configs.getBestRefreshRate(layers, {.touch = true, .idle = true});
+    const auto [mode, signals] =
+            configs.getRankedRefreshRates(layers, {.touch = true, .idle = true});
 
-    EXPECT_EQ(mode, kMode60);
+    EXPECT_EQ(mode.begin()->displayModePtr, kMode60);
     EXPECT_FALSE(signals.touch);
 }
 
@@ -1209,14 +1335,147 @@
     EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.idle = true}));
 }
 
+TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) {
+    TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60);
+
+    std::vector<LayerRequirement> layers = {{.weight = 1.f},
+                                            {.weight = 1.f},
+                                            {.weight = 1.f},
+                                            {.weight = 1.f},
+                                            {.weight = 1.f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+    auto& lr3 = layers[2];
+    auto& lr4 = layers[3];
+    auto& lr5 = layers[4];
+
+    lr1.desiredRefreshRate = 90_Hz;
+    lr1.name = "90Hz";
+    lr1.focused = true;
+
+    lr2.desiredRefreshRate = 60_Hz;
+    lr2.name = "60Hz";
+    lr2.focused = true;
+
+    lr3.desiredRefreshRate = 72_Hz;
+    lr3.name = "72Hz";
+    lr3.focused = true;
+
+    lr4.desiredRefreshRate = 120_Hz;
+    lr4.name = "120Hz";
+    lr4.focused = true;
+
+    lr5.desiredRefreshRate = 30_Hz;
+    lr5.name = "30Hz";
+    lr5.focused = true;
+
+    std::vector<RefreshRateRanking> expectedRankings = {
+            RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72},
+            RefreshRateRanking{kMode60},  RefreshRateRanking{kMode30},
+    };
+
+    std::vector<RefreshRateRanking> actualOrder =
+            configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+    ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+    for (size_t i = 0; i < expectedRankings.size(); ++i) {
+        EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+                << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+    }
+
+    lr1.vote = LayerVoteType::Max;
+    lr1.name = "Max";
+
+    lr2.desiredRefreshRate = 60_Hz;
+    lr2.name = "60Hz";
+
+    lr3.desiredRefreshRate = 72_Hz;
+    lr3.name = "72Hz";
+
+    lr4.desiredRefreshRate = 90_Hz;
+    lr4.name = "90Hz";
+
+    lr5.desiredRefreshRate = 120_Hz;
+    lr5.name = "120Hz";
+
+    expectedRankings = {
+            RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72},
+            RefreshRateRanking{kMode60},  RefreshRateRanking{kMode30},
+    };
+
+    actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+
+    ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+    for (size_t i = 0; i < expectedRankings.size(); ++i) {
+        EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+                << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+    }
+
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.desiredRefreshRate = 30_Hz;
+    lr1.name = "30Hz";
+
+    lr2.desiredRefreshRate = 120_Hz;
+    lr2.name = "120Hz";
+
+    lr3.desiredRefreshRate = 60_Hz;
+    lr3.name = "60Hz";
+
+    lr5.desiredRefreshRate = 72_Hz;
+    lr5.name = "72Hz";
+
+    expectedRankings = {
+            RefreshRateRanking{kMode30},  RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90},
+            RefreshRateRanking{kMode120}, RefreshRateRanking{kMode72},
+    };
+
+    actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+    ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+    for (size_t i = 0; i < expectedRankings.size(); ++i) {
+        EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+                << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+    }
+
+    lr1.desiredRefreshRate = 120_Hz;
+    lr1.name = "120Hz";
+    lr1.weight = 0.0f;
+
+    lr2.desiredRefreshRate = 60_Hz;
+    lr2.name = "60Hz";
+    lr2.vote = LayerVoteType::NoVote;
+
+    lr3.name = "60Hz-2";
+    lr3.vote = LayerVoteType::Heuristic;
+
+    lr4.vote = LayerVoteType::ExplicitExact;
+
+    lr5.desiredRefreshRate = 120_Hz;
+    lr5.name = "120Hz-2";
+
+    expectedRankings = {
+            RefreshRateRanking{kMode90}, RefreshRateRanking{kMode60}, RefreshRateRanking{kMode120},
+            RefreshRateRanking{kMode72}, RefreshRateRanking{kMode30},
+    };
+
+    actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+    ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+    for (size_t i = 0; i < expectedRankings.size(); ++i) {
+        EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+                << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+                << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+    }
+}
+
 TEST_F(RefreshRateConfigsTest,
        getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) {
     TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
 
     EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
 
-    const auto [mode, signals] = configs.getBestRefreshRateAndSignals({}, {});
-    EXPECT_EQ(mode, kMode90);
+    const auto [mode, signals] = configs.getRankedRefreshRatesAndSignals({}, {});
+    EXPECT_EQ(mode.front().displayModePtr, kMode90);
     EXPECT_FALSE(signals.touch);
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1593,11 +1852,12 @@
         layers[0].desiredRefreshRate = 90_Hz;
 
         const auto [refreshRate, signals] =
-                configs.getBestRefreshRateAndSignals(layers, {.touch = touchActive, .idle = true});
+                configs.getRankedRefreshRatesAndSignals(layers,
+                                                        {.touch = touchActive, .idle = true});
 
         // Refresh rate will be chosen by either touch state or idle state.
         EXPECT_EQ(!touchActive, signals.idle);
-        return refreshRate->getId();
+        return refreshRate.front().displayModePtr->getId();
     };
 
     EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
@@ -1756,24 +2016,26 @@
     using GlobalSignals = RefreshRateConfigs::GlobalSignals;
     const auto args = std::make_pair(std::vector<LayerRequirement>{},
                                      GlobalSignals{.touch = true, .idle = true});
-    const auto result = std::make_pair(kMode90, GlobalSignals{.touch = true});
 
-    configs.mutableGetBestRefreshRateCache() = {args, result};
+    const auto result = std::make_pair(std::vector<RefreshRateRanking>{RefreshRateRanking{kMode90}},
+                                       GlobalSignals{.touch = true});
 
-    EXPECT_EQ(result, configs.getBestRefreshRateAndSignals(args.first, args.second));
+    configs.mutableGetRankedRefreshRatesCache() = {args, result};
+
+    EXPECT_EQ(result, configs.getRankedRefreshRatesAndSignals(args.first, args.second));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) {
     TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60);
 
-    EXPECT_FALSE(configs.mutableGetBestRefreshRateCache());
+    EXPECT_FALSE(configs.mutableGetRankedRefreshRatesCache());
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
     RefreshRateConfigs::GlobalSignals globalSignals{.touch = true, .idle = true};
 
-    const auto result = configs.getBestRefreshRateAndSignals(layers, globalSignals);
+    const auto result = configs.getRankedRefreshRatesAndSignals(layers, globalSignals);
 
-    const auto& cache = configs.mutableGetBestRefreshRateCache();
+    const auto& cache = configs.mutableGetRankedRefreshRatesCache();
     ASSERT_TRUE(cache);
 
     EXPECT_EQ(cache->arguments, std::make_pair(layers, globalSignals));