SF: Generalize frame rate override to any frame rate

Add support to be able to override the frame rate of an app to
any frame rate, as long as it is a divisor of the display refresh rate.

Test: SF unit tests
Bug: 241460058
Bug: 241447632
Change-Id: Ibf8fa600127d3d5672a4c2a58d0a93b190854cc1
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index f22f9e7..c913891 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -30,6 +30,7 @@
 #include <ftl/enum.h>
 #include <ftl/fake_guard.h>
 #include <ftl/match.h>
+#include <ftl/unit.h>
 #include <utils/Trace.h>
 
 #include "../SurfaceFlingerProperties.h"
@@ -105,7 +106,7 @@
     return sortedModes;
 }
 
-bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& sortedModes) {
+bool shouldEnableFrameRateOverride(const std::vector<DisplayModeIterator>& sortedModes) {
     for (const auto it1 : sortedModes) {
         const auto& mode1 = it1->second;
         for (const auto it2 : sortedModes) {
@@ -264,7 +265,7 @@
 
     if (layer.vote == LayerVoteType::ExplicitExact) {
         const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate);
-        if (mSupportsFrameRateOverrideByContent) {
+        if (supportsFrameRateOverrideByContent()) {
             // Since we support frame rate override, allow refresh rates which are
             // multiples of the layer's request, as those apps would be throttled
             // down to run at the desired refresh rate.
@@ -579,7 +580,7 @@
     // 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 bool touchBoostForExplicitExact = [&] {
-        if (mSupportsFrameRateOverrideByContent) {
+        if (supportsFrameRateOverrideByContent()) {
             // Enable touch boost if there are other layers besides exact
             return explicitExact + noVoteLayers != layers.size();
         } else {
@@ -648,23 +649,43 @@
                                                 GlobalSignals globalSignals) const
         -> UidToFrameRateOverride {
     ATRACE_CALL();
-
     ALOGV("%s: %zu layers", __func__, layers.size());
 
     std::lock_guard lock(mLock);
 
-    std::vector<RefreshRateScore> scores;
-    scores.reserve(mDisplayModes.size());
-
-    for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) {
-        scores.emplace_back(RefreshRateScore{it, 0.0f});
+    // Prepare a set of supported display refresh rates for easy lookup
+    constexpr size_t kStaticCapacity = 8;
+    ftl::SmallMap<Fps, ftl::Unit, kStaticCapacity, FpsApproxEqual> supportedDisplayRefreshRates;
+    if (mConfig.enableFrameRateOverride ==
+        Config::FrameRateOverride::EnabledForNativeRefreshRates) {
+        for (const auto& [_, modePtr] : mDisplayModes) {
+            supportedDisplayRefreshRates.try_emplace(modePtr->getFps(), ftl::unit);
+        }
     }
 
-    std::sort(scores.begin(), scores.end(), [](const auto& lhs, const auto& rhs) {
-        const auto& mode1 = lhs.modeIt->second;
-        const auto& mode2 = rhs.modeIt->second;
-        return isStrictlyLess(mode1->getFps(), mode2->getFps());
-    });
+    const auto* policyPtr = getCurrentPolicyLocked();
+    // We don't want to run lower than 30fps
+    const Fps minFrameRate = std::max(policyPtr->appRequestRanges.render.min, 30_Hz, isApproxLess);
+
+    using fps_approx_ops::operator/;
+    const unsigned numMultiples = displayRefreshRate / minFrameRate;
+
+    std::vector<std::pair<Fps, float>> scoredFrameRates;
+    scoredFrameRates.reserve(numMultiples);
+
+    for (unsigned n = numMultiples; n > 0; n--) {
+        const Fps divisor = displayRefreshRate / n;
+        if (mConfig.enableFrameRateOverride ==
+                    Config::FrameRateOverride::EnabledForNativeRefreshRates &&
+            !supportedDisplayRefreshRates.contains(divisor)) {
+            continue;
+        }
+
+        if (policyPtr->appRequestRanges.render.includes(divisor)) {
+            ALOGV("%s: adding %s as a potential frame rate", __func__, to_string(divisor).c_str());
+            scoredFrameRates.emplace_back(divisor, 0);
+        }
+    }
 
     const auto layersByUid = groupLayersByUid(layers);
     UidToFrameRateOverride frameRateOverrides;
@@ -680,7 +701,7 @@
             continue;
         }
 
-        for (auto& [_, score, _1] : scores) {
+        for (auto& [_, score] : scoredFrameRates) {
             score = 0;
         }
 
@@ -692,36 +713,33 @@
             LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
                                 layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
                                 layer->vote != LayerVoteType::ExplicitExact);
-            for (auto& [modeIt, score, _] : scores) {
+            for (auto& [fps, score] : scoredFrameRates) {
                 constexpr bool isSeamlessSwitch = true;
-                const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(),
-                                                                  isSeamlessSwitch);
+                const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch);
                 score += layer->weight * layerScore;
             }
         }
 
-        // We just care about the refresh rates which are a divisor of the
-        // display refresh rate
-        const auto it = std::remove_if(scores.begin(), scores.end(), [&](RefreshRateScore score) {
-            const auto& [id, mode] = *score.modeIt;
-            return getFrameRateDivisor(displayRefreshRate, mode->getFps()) == 0;
-        });
-        scores.erase(it, scores.end());
-
         // If we never scored any layers, we don't have a preferred frame rate
-        if (std::all_of(scores.begin(), scores.end(),
-                        [](RefreshRateScore score) { return score.overallScore == 0; })) {
+        if (std::all_of(scoredFrameRates.begin(), scoredFrameRates.end(),
+                        [](const auto& scoredFrameRate) {
+                            const auto [_, score] = scoredFrameRate;
+                            return score == 0;
+                        })) {
             continue;
         }
 
         // Now that we scored all the refresh rates we need to pick the lowest refresh rate
         // that got the highest score.
-        const DisplayModePtr& bestRefreshRate =
-                std::min_element(scores.begin(), scores.end(),
-                                 RefreshRateScoreComparator{.refreshRateOrder =
-                                                                    RefreshRateOrder::Ascending})
-                        ->modeIt->second;
-        frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
+        const auto [overrideFps, _] =
+                *std::max_element(scoredFrameRates.begin(), scoredFrameRates.end(),
+                                  [](const auto& lhsPair, const auto& rhsPair) {
+                                      const float lhs = lhsPair.second;
+                                      const float rhs = rhsPair.second;
+                                      return lhs < rhs && !ScoredRefreshRate::scoresEqual(lhs, rhs);
+                                  });
+        ALOGV("%s: overriding to %s for uid=%d", __func__, to_string(overrideFps).c_str(), uid);
+        frameRateOverrides.emplace(uid, overrideFps);
     }
 
     return frameRateOverrides;
@@ -894,8 +912,17 @@
     mDisplayManagerPolicy = {};
     mDisplayManagerPolicy.defaultMode = activeModeId;
 
-    mSupportsFrameRateOverrideByContent =
-            mConfig.enableFrameRateOverride && canModesSupportFrameRateOverride(sortedModes);
+    mFrameRateOverrideConfig = [&] {
+        switch (mConfig.enableFrameRateOverride) {
+            case Config::FrameRateOverride::Disabled:
+            case Config::FrameRateOverride::Enabled:
+                return mConfig.enableFrameRateOverride;
+            case Config::FrameRateOverride::EnabledForNativeRefreshRates:
+                return shouldEnableFrameRateOverride(sortedModes)
+                        ? Config::FrameRateOverride::EnabledForNativeRefreshRates
+                        : Config::FrameRateOverride::Disabled;
+        }
+    }();
 
     constructAvailableRefreshRates();
 }
@@ -1128,7 +1155,7 @@
         dumper.dump("overridePolicy"sv, currentPolicy.toString());
     }
 
-    dumper.dump("supportsFrameRateOverrideByContent"sv, mSupportsFrameRateOverrideByContent);
+    dumper.dump("frameRateOverrideConfig"sv, *ftl::enum_name(mFrameRateOverrideConfig));
 
     std::string idleTimer;
     if (mIdleTimer) {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 887d815..abbd304 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -251,7 +251,20 @@
 
     // Configuration flags.
     struct Config {
-        bool enableFrameRateOverride = false;
+        enum class FrameRateOverride {
+            // Do not override the frame rate for an app
+            Disabled,
+
+            // Override the frame rate for an app to a value which is also
+            // a display refresh rate
+            EnabledForNativeRefreshRates,
+
+            // Override the frame rate for an app to any value
+            Enabled,
+
+            ftl_last = Enabled
+        };
+        FrameRateOverride enableFrameRateOverride = FrameRateOverride::Disabled;
 
         // Specifies the upper refresh rate threshold (inclusive) for layer vote types of multiple
         // or heuristic, such that refresh rates higher than this value will not be voted for. 0 if
@@ -266,11 +279,12 @@
         std::optional<KernelIdleTimerController> kernelIdleTimerController;
     };
 
-    RefreshRateSelector(DisplayModes, DisplayModeId activeModeId,
-                        Config config = {.enableFrameRateOverride = false,
-                                         .frameRateMultipleThreshold = 0,
-                                         .idleTimerTimeout = 0ms,
-                                         .kernelIdleTimerController = {}});
+    RefreshRateSelector(
+            DisplayModes, DisplayModeId activeModeId,
+            Config config = {.enableFrameRateOverride = Config::FrameRateOverride::Disabled,
+                             .frameRateMultipleThreshold = 0,
+                             .idleTimerTimeout = 0ms,
+                             .kernelIdleTimerController = {}});
 
     RefreshRateSelector(const RefreshRateSelector&) = delete;
     RefreshRateSelector& operator=(const RefreshRateSelector&) = delete;
@@ -293,7 +307,9 @@
     // refresh rates.
     KernelIdleTimerAction getIdleTimerAction() const;
 
-    bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; }
+    bool supportsFrameRateOverrideByContent() const {
+        return mFrameRateOverrideConfig != Config::FrameRateOverride::Disabled;
+    }
 
     // Return the display refresh rate divisor to match the layer
     // frame rate, or 0 if the display refresh rate is not a multiple of the
@@ -446,7 +462,7 @@
     const std::vector<Fps> mKnownFrameRates;
 
     const Config mConfig;
-    bool mSupportsFrameRateOverrideByContent;
+    Config::FrameRateOverride mFrameRateOverrideConfig;
 
     struct GetRankedRefreshRatesCache {
         std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
index d89f685..31b1d69 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
@@ -144,8 +144,16 @@
     return !(lhs == rhs);
 }
 
+inline unsigned operator/(Fps lhs, Fps rhs) {
+    return static_cast<unsigned>(std::ceil(lhs.getValue() / rhs.getValue()));
+}
+
 } // namespace fps_approx_ops
 
+constexpr Fps operator/(Fps fps, unsigned divisor) {
+    return Fps::fromPeriodNsecs(fps.getPeriodNsecs() * static_cast<nsecs_t>(divisor));
+}
+
 inline bool FpsRange::includes(Fps fps) const {
     using fps_approx_ops::operator<=;
     return min <= fps && fps <= max;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2ca39d0..ee22ecc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2777,8 +2777,21 @@
         const auto [kernelIdleTimerController, idleTimerTimeoutMs] =
                 getKernelIdleTimerProperties(compositionDisplay->getId());
 
+        const auto enableFrameRateOverride = [&] {
+            using Config = scheduler::RefreshRateSelector::Config;
+            if (!sysprop::enable_frame_rate_override(false)) {
+                return Config::FrameRateOverride::Disabled;
+            }
+
+            if (sysprop::frame_rate_override_for_native_rates(true)) {
+                return Config::FrameRateOverride::EnabledForNativeRefreshRates;
+            }
+
+            return Config::FrameRateOverride::Enabled;
+        }();
+
         scheduler::RefreshRateSelector::Config config =
-                {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
+                {.enableFrameRateOverride = enableFrameRateOverride,
                  .frameRateMultipleThreshold =
                          base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0),
                  .idleTimerTimeout = idleTimerTimeoutMs,
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 20fa091..c8c71df 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -367,6 +367,10 @@
     return SurfaceFlingerProperties::enable_frame_rate_override().value_or(defaultValue);
 }
 
+bool frame_rate_override_for_native_rates(bool defaultValue) {
+    return SurfaceFlingerProperties::frame_rate_override_for_native_rates().value_or(defaultValue);
+}
+
 bool enable_layer_caching(bool defaultValue) {
     return SurfaceFlingerProperties::enable_layer_caching().value_or(defaultValue);
 }
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 080feee..5e316cf 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -96,6 +96,8 @@
 
 bool enable_frame_rate_override(bool defaultValue);
 
+bool frame_rate_override_for_native_rates(bool defaultValue);
+
 bool enable_layer_caching(bool defaultValue);
 
 bool enable_sdr_dimming(bool defaultValue);
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index bcbe21a..28da81f 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -445,6 +445,18 @@
     prop_name: "ro.surface_flinger.enable_frame_rate_override"
 }
 
+# Limits the frame rate override feature (enable_frame_rate_override) to override the refresh rate
+# to native display refresh rates only. Before introducing this flag, native display refresh rates
+# was the default behvaiour. With this flag we can control which behaviour we want explicitly.
+# This flag is intoruduced as a fail-safe machanism and planned to be defaulted to false.
+prop {
+    api_name: "frame_rate_override_for_native_rates"
+    type: Boolean
+    scope: Public
+    access: Readonly
+    prop_name: "ro.surface_flinger.frame_rate_override_for_native_rates"
+}
+
 # Enables Layer Caching
 prop {
     api_name: "enable_layer_caching"
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 348a462..0dfb80e 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -61,6 +61,10 @@
     prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
   }
   prop {
+    api_name: "frame_rate_override_for_native_rates"
+    prop_name: "ro.surface_flinger.frame_rate_override_for_native_rates"
+  }
+  prop {
     api_name: "has_HDR_display"
     prop_name: "ro.surface_flinger.has_HDR_display"
   }
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 9689ddb..cedb7eb 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -37,6 +37,7 @@
 
 namespace hal = android::hardware::graphics::composer::hal;
 
+using Config = RefreshRateSelector::Config;
 using LayerRequirement = RefreshRateSelector::LayerRequirement;
 using LayerVoteType = RefreshRateSelector::LayerVoteType;
 using SetPolicyResult = RefreshRateSelector::SetPolicyResult;
@@ -2034,7 +2035,8 @@
 
 TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) {
     TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60,
-                                         {.enableFrameRateOverride = true});
+                                         {.enableFrameRateOverride =
+                                                  Config::FrameRateOverride::Enabled});
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
     auto& explicitExactLayer = layers[0];
@@ -2100,7 +2102,8 @@
 
 TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExactTouchBoost) {
     TestableRefreshRateSelector selector(kModes_60_120, kModeId60,
-                                         {.enableFrameRateOverride = true});
+                                         {.enableFrameRateOverride =
+                                                  Config::FrameRateOverride::Enabled});
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
     auto& explicitExactLayer = layers[0];
@@ -2125,7 +2128,8 @@
 
 TEST_F(RefreshRateSelectorTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
     TestableRefreshRateSelector selector(kModes_24_25_30_50_60_Frac, kModeId60,
-                                         {.enableFrameRateOverride = true});
+                                         {.enableFrameRateOverride =
+                                                  Config::FrameRateOverride::Enabled});
 
     std::vector<LayerRequirement> layers = {{.weight = 0.5f}, {.weight = 0.5f}};
     auto& explicitDefaultLayer = layers[0];
@@ -2319,7 +2323,7 @@
 
 TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_60on120) {
     RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
-                                 {.enableFrameRateOverride = true});
+                                 {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     layers[0].name = "Test layer";
@@ -2357,7 +2361,7 @@
 
 TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_twoUids) {
     RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
-                                 {.enableFrameRateOverride = true});
+                                 {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
 
     std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f},
                                             {.ownerUid = 5678, .weight = 1.f}};
@@ -2390,7 +2394,7 @@
 
 TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_touch) {
     RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
-                                 {.enableFrameRateOverride = true});
+                                 {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
 
     std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f}};
     layers[0].name = "Test layer";
@@ -2428,5 +2432,139 @@
     EXPECT_TRUE(frameRateOverrides.empty());
 }
 
+TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_DivisorIsNotDisplayRefreshRate_Enabled) {
+    RefreshRateSelector selector(kModes_60_120, kModeId120,
+                                 {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
+
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+    layers[0].name = "Test layer";
+    layers[0].ownerUid = 1234;
+    layers[0].desiredRefreshRate = 30_Hz;
+    layers[0].vote = LayerVoteType::ExplicitDefault;
+
+    auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_EQ(1u, frameRateOverrides.size());
+    ASSERT_EQ(1u, frameRateOverrides.count(1234));
+    EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+
+    layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_EQ(1u, frameRateOverrides.size());
+    ASSERT_EQ(1u, frameRateOverrides.count(1234));
+    EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+
+    layers[0].vote = LayerVoteType::NoVote;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+
+    layers[0].vote = LayerVoteType::Min;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+
+    layers[0].vote = LayerVoteType::Max;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+
+    layers[0].vote = LayerVoteType::Heuristic;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+}
+
+TEST_F(RefreshRateSelectorTest,
+       getFrameRateOverrides_DivisorIsNotDisplayRefreshRate_EnabledForNativeRefreshRates) {
+    RefreshRateSelector selector(kModes_60_120, kModeId120,
+                                 {.enableFrameRateOverride =
+                                          Config::FrameRateOverride::EnabledForNativeRefreshRates});
+
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+    layers[0].name = "Test layer";
+    layers[0].ownerUid = 1234;
+    layers[0].desiredRefreshRate = 30_Hz;
+    layers[0].vote = LayerVoteType::ExplicitDefault;
+
+    auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_EQ(1u, frameRateOverrides.size());
+    ASSERT_EQ(1u, frameRateOverrides.count(1234));
+    EXPECT_EQ(60_Hz, frameRateOverrides.at(1234));
+
+    layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_EQ(1u, frameRateOverrides.size());
+    ASSERT_EQ(1u, frameRateOverrides.count(1234));
+    EXPECT_EQ(60_Hz, frameRateOverrides.at(1234));
+
+    layers[0].vote = LayerVoteType::NoVote;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+
+    layers[0].vote = LayerVoteType::Min;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+
+    layers[0].vote = LayerVoteType::Max;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+
+    layers[0].vote = LayerVoteType::Heuristic;
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_TRUE(frameRateOverrides.empty());
+}
+
+TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_InPolicy) {
+    TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
+                                         {.enableFrameRateOverride =
+                                                  Config::FrameRateOverride::Enabled});
+
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+    {
+        const FpsRange physical = {120_Hz, 120_Hz};
+        const FpsRange render = {60_Hz, 90_Hz};
+        EXPECT_EQ(SetPolicyResult::Changed,
+                  selector.setDisplayManagerPolicy(
+                          {kModeId120, {physical, render}, {physical, render}}));
+    }
+
+    layers[0].name = "30Hz";
+    layers[0].ownerUid = 1234;
+    layers[0].desiredRefreshRate = 30_Hz;
+    layers[0].vote = LayerVoteType::ExplicitDefault;
+
+    auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_EQ(1u, frameRateOverrides.size());
+    EXPECT_EQ(1u, frameRateOverrides.count(1234));
+    EXPECT_EQ(60_Hz, frameRateOverrides.at(1234));
+
+    {
+        const FpsRange physical = {120_Hz, 120_Hz};
+        const FpsRange render = {30_Hz, 90_Hz};
+        EXPECT_EQ(SetPolicyResult::Changed,
+                  selector.setDisplayManagerPolicy(
+                          {kModeId120, {physical, render}, {physical, render}}));
+    }
+
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_EQ(1u, frameRateOverrides.size());
+    EXPECT_EQ(1u, frameRateOverrides.count(1234));
+    EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+
+    {
+        const FpsRange physical = {120_Hz, 120_Hz};
+        const FpsRange render = {30_Hz, 30_Hz};
+        EXPECT_EQ(SetPolicyResult::Changed,
+                  selector.setDisplayManagerPolicy(
+                          {kModeId120, {physical, render}, {physical, render}}));
+    }
+
+    layers[0].name = "60Hz";
+    layers[0].ownerUid = 1234;
+    layers[0].desiredRefreshRate = 60_Hz;
+    layers[0].vote = LayerVoteType::ExplicitDefault;
+
+    frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+    EXPECT_EQ(1u, frameRateOverrides.size());
+    EXPECT_EQ(1u, frameRateOverrides.count(1234));
+    EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+}
+
 } // namespace
 } // namespace android::scheduler